diff options
Diffstat (limited to 'drivers/gpu/drm')
73 files changed, 5269 insertions, 2317 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 39a6bc69d22..c20fcdc6549 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -261,31 +261,6 @@ void *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type)  EXPORT_SYMBOL(drm_mode_object_find);  /** - * drm_crtc_from_fb - find the CRTC structure associated with an fb - * @dev: DRM device - * @fb: framebuffer in question - * - * LOCKING: - * Caller must hold mode_config lock. - * - * Find CRTC in the mode_config structure that matches @fb. - * - * RETURNS: - * Pointer to the CRTC or NULL if it wasn't found. - */ -struct drm_crtc *drm_crtc_from_fb(struct drm_device *dev, -				  struct drm_framebuffer *fb) -{ -	struct drm_crtc *crtc; - -	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { -		if (crtc->fb == fb) -			return crtc; -	} -	return NULL; -} - -/**   * drm_framebuffer_init - initialize a framebuffer   * @dev: DRM device   * @@ -331,11 +306,20 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb)  {  	struct drm_device *dev = fb->dev;  	struct drm_crtc *crtc; +	struct drm_mode_set set; +	int ret;  	/* remove from any CRTC */  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { -		if (crtc->fb == fb) -			crtc->fb = NULL; +		if (crtc->fb == fb) { +			/* should turn off the crtc */ +			memset(&set, 0, sizeof(struct drm_mode_set)); +			set.crtc = crtc; +			set.fb = NULL; +			ret = crtc->funcs->set_config(&set); +			if (ret) +				DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); +		}  	}  	drm_mode_object_put(dev, &fb->base); @@ -1502,7 +1486,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,  		goto out;  	} -	if (crtc_req->count_connectors > 0 && !mode && !fb) { +	if (crtc_req->count_connectors > 0 && (!mode || !fb)) {  		DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n",  			  crtc_req->count_connectors);  		ret = -EINVAL; @@ -1553,7 +1537,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,  	set.mode = mode;  	set.connectors = connector_set;  	set.num_connectors = crtc_req->count_connectors; -	set.fb =fb; +	set.fb = fb;  	ret = crtc->funcs->set_config(&set);  out: diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 9cd84513258..a06c5f52c28 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -708,8 +708,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)  	struct drm_encoder **save_encoders, *new_encoder;  	struct drm_framebuffer *old_fb = NULL;  	bool save_enabled; -	bool mode_changed = false; -	bool fb_changed = false; +	bool mode_changed = false; /* if true do a full mode set */ +	bool fb_changed = false; /* if true and !mode_changed just do a flip */  	struct drm_connector *connector;  	int count = 0, ro, fail = 0;  	struct drm_crtc_helper_funcs *crtc_funcs; @@ -761,6 +761,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)  		if (set->crtc->fb == NULL) {  			DRM_DEBUG_KMS("crtc has no fb, full mode set\n");  			mode_changed = true; +		} else if (set->fb == NULL) { +			mode_changed = true;  		} else if ((set->fb->bits_per_pixel !=  			 set->crtc->fb->bits_per_pixel) ||  			 set->fb->depth != set->crtc->fb->depth) diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 2960b6d7345..9903f270e44 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -101,6 +101,10 @@ int drm_debugfs_create_files(struct drm_info_list *files, int count,  			continue;  		tmp = kmalloc(sizeof(struct drm_info_node), GFP_KERNEL); +		if (tmp == NULL) { +			ret = -1; +			goto fail; +		}  		ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO,  					  root, tmp, &drm_debugfs_fops);  		if (!ent) { diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index bbcb2e22675..a1cab5de2f4 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -547,12 +547,41 @@ static int add_detailed_info(struct drm_connector *connector,  		struct detailed_non_pixel *data = &timing->data.other_data;  		struct drm_display_mode *newmode; -		/* EDID up to and including 1.2 may put monitor info here */ -		if (edid->version == 1 && edid->revision < 3) -			continue; +		/* X server check is version 1.1 or higher */ +		if (edid->version == 1 && edid->revision >= 1 && +		    !timing->pixel_clock) { +			/* Other timing or info */ +			switch (data->type) { +			case EDID_DETAIL_MONITOR_SERIAL: +				break; +			case EDID_DETAIL_MONITOR_STRING: +				break; +			case EDID_DETAIL_MONITOR_RANGE: +				/* Get monitor range data */ +				break; +			case EDID_DETAIL_MONITOR_NAME: +				break; +			case EDID_DETAIL_MONITOR_CPDATA: +				break; +			case EDID_DETAIL_STD_MODES: +				/* Five modes per detailed section */ +				for (j = 0; j < 5; i++) { +					struct std_timing *std; +					struct drm_display_mode *newmode; -		/* Detailed mode timing */ -		if (timing->pixel_clock) { +					std = &data->data.timings[j]; +					newmode = drm_mode_std(dev, std, +							       timing_level); +					if (newmode) { +						drm_mode_probed_add(connector, newmode); +						modes++; +					} +				} +				break; +			default: +				break; +			} +		} else {  			newmode = drm_mode_detailed(dev, edid, timing, quirks);  			if (!newmode)  				continue; @@ -563,39 +592,6 @@ static int add_detailed_info(struct drm_connector *connector,  			drm_mode_probed_add(connector, newmode);  			modes++; -			continue; -		} - -		/* Other timing or info */ -		switch (data->type) { -		case EDID_DETAIL_MONITOR_SERIAL: -			break; -		case EDID_DETAIL_MONITOR_STRING: -			break; -		case EDID_DETAIL_MONITOR_RANGE: -			/* Get monitor range data */ -			break; -		case EDID_DETAIL_MONITOR_NAME: -			break; -		case EDID_DETAIL_MONITOR_CPDATA: -			break; -		case EDID_DETAIL_STD_MODES: -			/* Five modes per detailed section */ -			for (j = 0; j < 5; i++) { -				struct std_timing *std; -				struct drm_display_mode *newmode; - -				std = &data->data.timings[j]; -				newmode = drm_mode_std(dev, std, -							timing_level); -				if (newmode) { -					drm_mode_probed_add(connector, newmode); -					modes++; -				} -			} -			break; -		default: -			break;  		}  	} diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 8104ecaea26..ffe8f4394d5 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -134,26 +134,29 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size)  	BUG_ON((size & (PAGE_SIZE - 1)) != 0);  	obj = kzalloc(sizeof(*obj), GFP_KERNEL); +	if (!obj) +		goto free;  	obj->dev = dev;  	obj->filp = shmem_file_setup("drm mm object", size, VM_NORESERVE); -	if (IS_ERR(obj->filp)) { -		kfree(obj); -		return NULL; -	} +	if (IS_ERR(obj->filp)) +		goto free;  	kref_init(&obj->refcount);  	kref_init(&obj->handlecount);  	obj->size = size;  	if (dev->driver->gem_init_object != NULL &&  	    dev->driver->gem_init_object(obj) != 0) { -		fput(obj->filp); -		kfree(obj); -		return NULL; +		goto fput;  	}  	atomic_inc(&dev->object_count);  	atomic_add(obj->size, &dev->object_memory);  	return obj; +fput: +	fput(obj->filp); +free: +	kfree(obj); +	return NULL;  }  EXPORT_SYMBOL(drm_gem_object_alloc); diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index b4a3dbcebe9..f85aaf21e78 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -566,7 +566,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data,  	ret = drm_vblank_get(dev, crtc);  	if (ret) { -		DRM_ERROR("failed to acquire vblank counter, %d\n", ret); +		DRM_DEBUG("failed to acquire vblank counter, %d\n", ret);  		return ret;  	}  	seq = drm_vblank_count(dev, crtc); diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 9e54925a760..ab6e70eadc5 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -980,6 +980,8 @@ void drm_mode_connector_list_update(struct drm_connector *connector)  				found_it = 1;  				/* if equal delete the probed mode */  				mode->status = pmode->status; +				/* Merge type bits together */ +				mode->type |= pmode->type;  				list_del(&pmode->head);  				drm_mode_destroy(connector->dev, pmode);  				break; diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 155a5bbce68..55bb8a82d61 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -489,7 +489,7 @@ int drm_put_minor(struct drm_minor **minor_p)   */  void drm_put_dev(struct drm_device *dev)  { -	struct drm_driver *driver = dev->driver; +	struct drm_driver *driver;  	struct drm_map_list *r_list, *list_temp;  	DRM_DEBUG("\n"); @@ -498,6 +498,7 @@ void drm_put_dev(struct drm_device *dev)  		DRM_ERROR("cleanup called no dev\n");  		return;  	} +	driver = dev->driver;  	drm_vblank_cleanup(dev); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 14625e146f1..544d889b9b1 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1181,6 +1181,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)  	if (ret)  		goto out_iomapfree; +	dev_priv->wq = create_workqueue("i915"); +	if (dev_priv->wq == NULL) { +		DRM_ERROR("Failed to create our workqueue.\n"); +		ret = -ENOMEM; +		goto out_iomapfree; +	} +  	/* enable GEM by default */  	dev_priv->has_gem = 1; @@ -1206,7 +1213,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)  	if (!I915_NEED_GFX_HWS(dev)) {  		ret = i915_init_phys_hws(dev);  		if (ret != 0) -			goto out_iomapfree; +			goto out_workqueue_free;  	}  	i915_get_mem_freq(dev); @@ -1240,7 +1247,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)  		ret = i915_load_modeset_init(dev, prealloc_size, agp_size);  		if (ret < 0) {  			DRM_ERROR("failed to init modeset\n"); -			goto out_rmmap; +			goto out_workqueue_free;  		}  	} @@ -1251,6 +1258,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)  	return 0; +out_workqueue_free: +	destroy_workqueue(dev_priv->wq);  out_iomapfree:  	io_mapping_free(dev_priv->mm.gtt_mapping);  out_rmmap: @@ -1264,6 +1273,8 @@ int i915_driver_unload(struct drm_device *dev)  {  	struct drm_i915_private *dev_priv = dev->dev_private; +	destroy_workqueue(dev_priv->wq); +  	io_mapping_free(dev_priv->mm.gtt_mapping);  	if (dev_priv->mm.gtt_mtrr >= 0) {  		mtrr_del(dev_priv->mm.gtt_mtrr, dev->agp->base, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d0875287588..7537f57d8a8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -219,6 +219,7 @@ typedef struct drm_i915_private {  	unsigned int lvds_vbt:1;  	unsigned int int_crt_support:1;  	unsigned int lvds_use_ssc:1; +	unsigned int edp_support:1;  	int lvds_ssc_freq;  	struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */ @@ -229,6 +230,8 @@ typedef struct drm_i915_private {  	spinlock_t error_lock;  	struct drm_i915_error_state *first_error; +	struct work_struct error_work; +	struct workqueue_struct *wq;  	/* Register state */  	u8 saveLBB; @@ -888,6 +891,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);  						      IS_I915GM(dev)))  #define SUPPORTS_INTEGRATED_HDMI(dev)	(IS_G4X(dev) || IS_IGDNG(dev))  #define SUPPORTS_INTEGRATED_DP(dev)	(IS_G4X(dev) || IS_IGDNG(dev)) +#define SUPPORTS_EDP(dev)		(IS_IGDNG_M(dev))  #define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev))  /* dsparb controlled by hw only */  #define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IGDNG(dev)) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 5bf420378b6..140bee142fc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1570,7 +1570,7 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,  	}  	if (was_empty && !dev_priv->mm.suspended) -		schedule_delayed_work(&dev_priv->mm.retire_work, HZ); +		queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);  	return seqno;  } @@ -1719,7 +1719,7 @@ i915_gem_retire_work_handler(struct work_struct *work)  	i915_gem_retire_requests(dev);  	if (!dev_priv->mm.suspended &&  	    !list_empty(&dev_priv->mm.request_list)) -		schedule_delayed_work(&dev_priv->mm.retire_work, HZ); +		queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);  	mutex_unlock(&dev->struct_mutex);  } diff --git a/drivers/gpu/drm/i915/i915_gem_debugfs.c b/drivers/gpu/drm/i915/i915_gem_debugfs.c index 9a44bfcb813..cb3b97405fb 100644 --- a/drivers/gpu/drm/i915/i915_gem_debugfs.c +++ b/drivers/gpu/drm/i915/i915_gem_debugfs.c @@ -343,6 +343,8 @@ static int i915_error_state(struct seq_file *m, void *unused)  	error = dev_priv->first_error; +	seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec, +		   error->time.tv_usec);  	seq_printf(m, "EIR: 0x%08x\n", error->eir);  	seq_printf(m, "  PGTBL_ER: 0x%08x\n", error->pgtbl_er);  	seq_printf(m, "  INSTPM: 0x%08x\n", error->instpm); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 7ba23a69a0c..7ebc84c2881 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -190,7 +190,7 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)  	low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;  	if (!i915_pipe_enabled(dev, pipe)) { -		DRM_ERROR("trying to get vblank count for disabled pipe %d\n", pipe); +		DRM_DEBUG("trying to get vblank count for disabled pipe %d\n", pipe);  		return 0;  	} @@ -219,7 +219,7 @@ u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)  	int reg = pipe ? PIPEB_FRMCOUNT_GM45 : PIPEA_FRMCOUNT_GM45;  	if (!i915_pipe_enabled(dev, pipe)) { -		DRM_ERROR("trying to get vblank count for disabled pipe %d\n", pipe); +		DRM_DEBUG("trying to get vblank count for disabled pipe %d\n", pipe);  		return 0;  	} @@ -290,6 +290,35 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev)  	return ret;  } +/** + * i915_error_work_func - do process context error handling work + * @work: work struct + * + * Fire an error uevent so userspace can see that a hang or error + * was detected. + */ +static void i915_error_work_func(struct work_struct *work) +{ +	drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, +						    error_work); +	struct drm_device *dev = dev_priv->dev; +	char *event_string = "ERROR=1"; +	char *envp[] = { event_string, NULL }; + +	DRM_DEBUG("generating error event\n"); + +	kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp); +} + +/** + * i915_capture_error_state - capture an error record for later analysis + * @dev: drm device + * + * Should be called when an error is detected (either a hang or an error + * interrupt) to capture error state from the time of the error.  Fills + * out a structure which becomes available in debugfs for user level tools + * to pick up. + */  static void i915_capture_error_state(struct drm_device *dev)  {  	struct drm_i915_private *dev_priv = dev->dev_private; @@ -325,12 +354,137 @@ static void i915_capture_error_state(struct drm_device *dev)  		error->acthd = I915_READ(ACTHD_I965);  	} +	do_gettimeofday(&error->time); +  	dev_priv->first_error = error;  out:  	spin_unlock_irqrestore(&dev_priv->error_lock, flags);  } +/** + * i915_handle_error - handle an error interrupt + * @dev: drm device + * + * Do some basic checking of regsiter state at error interrupt time and + * dump it to the syslog.  Also call i915_capture_error_state() to make + * sure we get a record and make it available in debugfs.  Fire a uevent + * so userspace knows something bad happened (should trigger collection + * of a ring dump etc.). + */ +static void i915_handle_error(struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	u32 eir = I915_READ(EIR); +	u32 pipea_stats = I915_READ(PIPEASTAT); +	u32 pipeb_stats = I915_READ(PIPEBSTAT); + +	i915_capture_error_state(dev); + +	printk(KERN_ERR "render error detected, EIR: 0x%08x\n", +	       eir); + +	if (IS_G4X(dev)) { +		if (eir & (GM45_ERROR_MEM_PRIV | GM45_ERROR_CP_PRIV)) { +			u32 ipeir = I915_READ(IPEIR_I965); + +			printk(KERN_ERR "  IPEIR: 0x%08x\n", +			       I915_READ(IPEIR_I965)); +			printk(KERN_ERR "  IPEHR: 0x%08x\n", +			       I915_READ(IPEHR_I965)); +			printk(KERN_ERR "  INSTDONE: 0x%08x\n", +			       I915_READ(INSTDONE_I965)); +			printk(KERN_ERR "  INSTPS: 0x%08x\n", +			       I915_READ(INSTPS)); +			printk(KERN_ERR "  INSTDONE1: 0x%08x\n", +			       I915_READ(INSTDONE1)); +			printk(KERN_ERR "  ACTHD: 0x%08x\n", +			       I915_READ(ACTHD_I965)); +			I915_WRITE(IPEIR_I965, ipeir); +			(void)I915_READ(IPEIR_I965); +		} +		if (eir & GM45_ERROR_PAGE_TABLE) { +			u32 pgtbl_err = I915_READ(PGTBL_ER); +			printk(KERN_ERR "page table error\n"); +			printk(KERN_ERR "  PGTBL_ER: 0x%08x\n", +			       pgtbl_err); +			I915_WRITE(PGTBL_ER, pgtbl_err); +			(void)I915_READ(PGTBL_ER); +		} +	} + +	if (IS_I9XX(dev)) { +		if (eir & I915_ERROR_PAGE_TABLE) { +			u32 pgtbl_err = I915_READ(PGTBL_ER); +			printk(KERN_ERR "page table error\n"); +			printk(KERN_ERR "  PGTBL_ER: 0x%08x\n", +			       pgtbl_err); +			I915_WRITE(PGTBL_ER, pgtbl_err); +			(void)I915_READ(PGTBL_ER); +		} +	} + +	if (eir & I915_ERROR_MEMORY_REFRESH) { +		printk(KERN_ERR "memory refresh error\n"); +		printk(KERN_ERR "PIPEASTAT: 0x%08x\n", +		       pipea_stats); +		printk(KERN_ERR "PIPEBSTAT: 0x%08x\n", +		       pipeb_stats); +		/* pipestat has already been acked */ +	} +	if (eir & I915_ERROR_INSTRUCTION) { +		printk(KERN_ERR "instruction error\n"); +		printk(KERN_ERR "  INSTPM: 0x%08x\n", +		       I915_READ(INSTPM)); +		if (!IS_I965G(dev)) { +			u32 ipeir = I915_READ(IPEIR); + +			printk(KERN_ERR "  IPEIR: 0x%08x\n", +			       I915_READ(IPEIR)); +			printk(KERN_ERR "  IPEHR: 0x%08x\n", +			       I915_READ(IPEHR)); +			printk(KERN_ERR "  INSTDONE: 0x%08x\n", +			       I915_READ(INSTDONE)); +			printk(KERN_ERR "  ACTHD: 0x%08x\n", +			       I915_READ(ACTHD)); +			I915_WRITE(IPEIR, ipeir); +			(void)I915_READ(IPEIR); +		} else { +			u32 ipeir = I915_READ(IPEIR_I965); + +			printk(KERN_ERR "  IPEIR: 0x%08x\n", +			       I915_READ(IPEIR_I965)); +			printk(KERN_ERR "  IPEHR: 0x%08x\n", +			       I915_READ(IPEHR_I965)); +			printk(KERN_ERR "  INSTDONE: 0x%08x\n", +			       I915_READ(INSTDONE_I965)); +			printk(KERN_ERR "  INSTPS: 0x%08x\n", +			       I915_READ(INSTPS)); +			printk(KERN_ERR "  INSTDONE1: 0x%08x\n", +			       I915_READ(INSTDONE1)); +			printk(KERN_ERR "  ACTHD: 0x%08x\n", +			       I915_READ(ACTHD_I965)); +			I915_WRITE(IPEIR_I965, ipeir); +			(void)I915_READ(IPEIR_I965); +		} +	} + +	I915_WRITE(EIR, eir); +	(void)I915_READ(EIR); +	eir = I915_READ(EIR); +	if (eir) { +		/* +		 * some errors might have become stuck, +		 * mask them. +		 */ +		DRM_ERROR("EIR stuck: 0x%08x, masking\n", eir); +		I915_WRITE(EMR, I915_READ(EMR) | eir); +		I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); +	} + +	queue_work(dev_priv->wq, &dev_priv->error_work); +} +  irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)  {  	struct drm_device *dev = (struct drm_device *) arg; @@ -372,6 +526,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)  		pipea_stats = I915_READ(PIPEASTAT);  		pipeb_stats = I915_READ(PIPEBSTAT); +		if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) +			i915_handle_error(dev); +  		/*  		 * Clear the PIPE(A|B)STAT regs before the IIR  		 */ @@ -403,86 +560,13 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)  			DRM_DEBUG("hotplug event received, stat 0x%08x\n",  				  hotplug_status);  			if (hotplug_status & dev_priv->hotplug_supported_mask) -				schedule_work(&dev_priv->hotplug_work); +				queue_work(dev_priv->wq, +					   &dev_priv->hotplug_work);  			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);  			I915_READ(PORT_HOTPLUG_STAT);  		} -		if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) { -			u32 eir = I915_READ(EIR); - -			i915_capture_error_state(dev); - -			printk(KERN_ERR "render error detected, EIR: 0x%08x\n", -			       eir); -			if (eir & I915_ERROR_PAGE_TABLE) { -				u32 pgtbl_err = I915_READ(PGTBL_ER); -				printk(KERN_ERR "page table error\n"); -				printk(KERN_ERR "  PGTBL_ER: 0x%08x\n", -				       pgtbl_err); -				I915_WRITE(PGTBL_ER, pgtbl_err); -				(void)I915_READ(PGTBL_ER); -			} -			if (eir & I915_ERROR_MEMORY_REFRESH) { -				printk(KERN_ERR "memory refresh error\n"); -				printk(KERN_ERR "PIPEASTAT: 0x%08x\n", -				       pipea_stats); -				printk(KERN_ERR "PIPEBSTAT: 0x%08x\n", -				       pipeb_stats); -				/* pipestat has already been acked */ -			} -			if (eir & I915_ERROR_INSTRUCTION) { -				printk(KERN_ERR "instruction error\n"); -				printk(KERN_ERR "  INSTPM: 0x%08x\n", -				       I915_READ(INSTPM)); -				if (!IS_I965G(dev)) { -					u32 ipeir = I915_READ(IPEIR); - -					printk(KERN_ERR "  IPEIR: 0x%08x\n", -					       I915_READ(IPEIR)); -					printk(KERN_ERR "  IPEHR: 0x%08x\n", -						   I915_READ(IPEHR)); -					printk(KERN_ERR "  INSTDONE: 0x%08x\n", -						   I915_READ(INSTDONE)); -					printk(KERN_ERR "  ACTHD: 0x%08x\n", -						   I915_READ(ACTHD)); -					I915_WRITE(IPEIR, ipeir); -					(void)I915_READ(IPEIR); -				} else { -					u32 ipeir = I915_READ(IPEIR_I965); - -					printk(KERN_ERR "  IPEIR: 0x%08x\n", -					       I915_READ(IPEIR_I965)); -					printk(KERN_ERR "  IPEHR: 0x%08x\n", -					       I915_READ(IPEHR_I965)); -					printk(KERN_ERR "  INSTDONE: 0x%08x\n", -					       I915_READ(INSTDONE_I965)); -					printk(KERN_ERR "  INSTPS: 0x%08x\n", -					       I915_READ(INSTPS)); -					printk(KERN_ERR "  INSTDONE1: 0x%08x\n", -					       I915_READ(INSTDONE1)); -					printk(KERN_ERR "  ACTHD: 0x%08x\n", -					       I915_READ(ACTHD_I965)); -					I915_WRITE(IPEIR_I965, ipeir); -					(void)I915_READ(IPEIR_I965); -				} -			} - -			I915_WRITE(EIR, eir); -			(void)I915_READ(EIR); -			eir = I915_READ(EIR); -			if (eir) { -				/* -				 * some errors might have become stuck, -				 * mask them. -				 */ -				DRM_ERROR("EIR stuck: 0x%08x, masking\n", eir); -				I915_WRITE(EMR, I915_READ(EMR) | eir); -				I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); -			} -		} -  		I915_WRITE(IIR, iir);  		new_iir = I915_READ(IIR); /* Flush posted writes */ @@ -830,6 +914,7 @@ void i915_driver_irq_preinstall(struct drm_device * dev)  	atomic_set(&dev_priv->irq_received, 0);  	INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); +	INIT_WORK(&dev_priv->error_work, i915_error_work_func);  	if (IS_IGDNG(dev)) {  		igdng_irq_preinstall(dev); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 6c085848409..2955083aa47 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1395,6 +1395,7 @@  #define TV_V_CHROMA_42		0x684a8  /* Display Port */ +#define DP_A				0x64000 /* eDP */  #define DP_B				0x64100  #define DP_C				0x64200  #define DP_D				0x64300 @@ -1437,13 +1438,22 @@  /* Mystic DPCD version 1.1 special mode */  #define   DP_ENHANCED_FRAMING		(1 << 18) +/* eDP */ +#define   DP_PLL_FREQ_270MHZ		(0 << 16) +#define   DP_PLL_FREQ_160MHZ		(1 << 16) +#define   DP_PLL_FREQ_MASK		(3 << 16) +  /** locked once port is enabled */  #define   DP_PORT_REVERSAL		(1 << 15) +/* eDP */ +#define   DP_PLL_ENABLE			(1 << 14) +  /** sends the clock on lane 15 of the PEG for debug */  #define   DP_CLOCK_OUTPUT_ENABLE	(1 << 13)  #define   DP_SCRAMBLING_DISABLE		(1 << 12) +#define   DP_SCRAMBLING_DISABLE_IGDNG	(1 << 7)  /** limit RGB values to avoid confusing TVs */  #define   DP_COLOR_RANGE_16_235		(1 << 8) @@ -1463,6 +1473,13 @@   * is 20 bytes in each direction, hence the 5 fixed   * data registers   */ +#define DPA_AUX_CH_CTL			0x64010 +#define DPA_AUX_CH_DATA1		0x64014 +#define DPA_AUX_CH_DATA2		0x64018 +#define DPA_AUX_CH_DATA3		0x6401c +#define DPA_AUX_CH_DATA4		0x64020 +#define DPA_AUX_CH_DATA5		0x64024 +  #define DPB_AUX_CH_CTL			0x64110  #define DPB_AUX_CH_DATA1		0x64114  #define DPB_AUX_CH_DATA2		0x64118 @@ -1618,7 +1635,7 @@  #define I830_FIFO_LINE_SIZE	32  #define I945_FIFO_SIZE		127 /* 945 & 965 */  #define I915_FIFO_SIZE		95 -#define I855GM_FIFO_SIZE	255 +#define I855GM_FIFO_SIZE	127 /* In cachelines */  #define I830_FIFO_SIZE		95  #define I915_MAX_WM		0x3f @@ -1848,6 +1865,8 @@  #define PFA_CTL_1               0x68080  #define PFB_CTL_1               0x68880  #define  PF_ENABLE              (1<<31) +#define PFA_WIN_SZ		0x68074 +#define PFB_WIN_SZ		0x68874  /* legacy palette */  #define LGC_PALETTE_A           0x4a000 @@ -2208,4 +2227,28 @@  #define PCH_PP_OFF_DELAYS	0xc720c  #define PCH_PP_DIVISOR		0xc7210 +#define PCH_DP_B		0xe4100 +#define PCH_DPB_AUX_CH_CTL	0xe4110 +#define PCH_DPB_AUX_CH_DATA1	0xe4114 +#define PCH_DPB_AUX_CH_DATA2	0xe4118 +#define PCH_DPB_AUX_CH_DATA3	0xe411c +#define PCH_DPB_AUX_CH_DATA4	0xe4120 +#define PCH_DPB_AUX_CH_DATA5	0xe4124 + +#define PCH_DP_C		0xe4200 +#define PCH_DPC_AUX_CH_CTL	0xe4210 +#define PCH_DPC_AUX_CH_DATA1	0xe4214 +#define PCH_DPC_AUX_CH_DATA2	0xe4218 +#define PCH_DPC_AUX_CH_DATA3	0xe421c +#define PCH_DPC_AUX_CH_DATA4	0xe4220 +#define PCH_DPC_AUX_CH_DATA5	0xe4224 + +#define PCH_DP_D		0xe4300 +#define PCH_DPD_AUX_CH_CTL	0xe4310 +#define PCH_DPD_AUX_CH_DATA1	0xe4314 +#define PCH_DPD_AUX_CH_DATA2	0xe4318 +#define PCH_DPD_AUX_CH_DATA3	0xe431c +#define PCH_DPD_AUX_CH_DATA4	0xe4320 +#define PCH_DPD_AUX_CH_DATA5	0xe4324 +  #endif /* _I915_REG_H_ */ diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 9e1d16e5c3e..1d04e1904ac 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -598,7 +598,7 @@ int i915_restore_state(struct drm_device *dev)  	for (i = 0; i < 16; i++) {  		I915_WRITE(SWF00 + (i << 2), dev_priv->saveSWF0[i]); -		I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]); +		I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i]);  	}  	for (i = 0; i < 3; i++)  		I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]); diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 7cc44719102..300aee3296c 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -97,14 +97,13 @@ static void  parse_lfp_panel_data(struct drm_i915_private *dev_priv,  			    struct bdb_header *bdb)  { -	struct drm_device *dev = dev_priv->dev;  	struct bdb_lvds_options *lvds_options;  	struct bdb_lvds_lfp_data *lvds_lfp_data;  	struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs;  	struct bdb_lvds_lfp_data_entry *entry;  	struct lvds_dvo_timing *dvo_timing;  	struct drm_display_mode *panel_fixed_mode; -	int lfp_data_size; +	int lfp_data_size, dvo_timing_offset;  	/* Defaults if we can't find VBT info */  	dev_priv->lvds_dither = 0; @@ -133,14 +132,16 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,  	entry = (struct bdb_lvds_lfp_data_entry *)  		((uint8_t *)lvds_lfp_data->data + (lfp_data_size *  						   lvds_options->panel_type)); +	dvo_timing_offset = lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset - +		lvds_lfp_data_ptrs->ptr[0].fp_timing_offset; -	/* On IGDNG mobile, LVDS data block removes panel fitting registers. -	   So dec 2 dword from dvo_timing offset */ -	if (IS_IGDNG(dev)) -		dvo_timing = (struct lvds_dvo_timing *) -					((u8 *)&entry->dvo_timing - 8); -	else -		dvo_timing = &entry->dvo_timing; +	/* +	 * the size of fp_timing varies on the different platform. +	 * So calculate the DVO timing relative offset in LVDS data +	 * entry to get the DVO timing entry +	 */ +	dvo_timing = (struct lvds_dvo_timing *) +			((unsigned char *)entry + dvo_timing_offset);  	panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); @@ -295,6 +296,25 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,  	}  	return;  } + +static void +parse_driver_features(struct drm_i915_private *dev_priv, +		       struct bdb_header *bdb) +{ +	struct drm_device *dev = dev_priv->dev; +	struct bdb_driver_features *driver; + +	/* set default for chips without eDP */ +	if (!SUPPORTS_EDP(dev)) { +		dev_priv->edp_support = 0; +		return; +	} + +	driver = find_section(bdb, BDB_DRIVER_FEATURES); +	if (driver && driver->lvds_config == BDB_DRIVER_FEATURE_EDP) +		dev_priv->edp_support = 1; +} +  /**   * intel_init_bios - initialize VBIOS settings & find VBT   * @dev: DRM device @@ -345,6 +365,8 @@ intel_init_bios(struct drm_device *dev)  	parse_lfp_panel_data(dev_priv, bdb);  	parse_sdvo_panel_data(dev_priv, bdb);  	parse_sdvo_device_mapping(dev_priv, bdb); +	parse_driver_features(dev_priv, bdb); +  	pci_unmap_rom(pdev, bios);  	return 0; diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index fe72e1c225d..0f8e5f69ac7 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -381,6 +381,51 @@ struct bdb_sdvo_lvds_options {  } __attribute__((packed)); +#define BDB_DRIVER_FEATURE_NO_LVDS		0 +#define BDB_DRIVER_FEATURE_INT_LVDS		1 +#define BDB_DRIVER_FEATURE_SDVO_LVDS		2 +#define BDB_DRIVER_FEATURE_EDP			3 + +struct bdb_driver_features { +	u8 boot_dev_algorithm:1; +	u8 block_display_switch:1; +	u8 allow_display_switch:1; +	u8 hotplug_dvo:1; +	u8 dual_view_zoom:1; +	u8 int15h_hook:1; +	u8 sprite_in_clone:1; +	u8 primary_lfp_id:1; + +	u16 boot_mode_x; +	u16 boot_mode_y; +	u8 boot_mode_bpp; +	u8 boot_mode_refresh; + +	u16 enable_lfp_primary:1; +	u16 selective_mode_pruning:1; +	u16 dual_frequency:1; +	u16 render_clock_freq:1; /* 0: high freq; 1: low freq */ +	u16 nt_clone_support:1; +	u16 power_scheme_ui:1; /* 0: CUI; 1: 3rd party */ +	u16 sprite_display_assign:1; /* 0: secondary; 1: primary */ +	u16 cui_aspect_scaling:1; +	u16 preserve_aspect_ratio:1; +	u16 sdvo_device_power_down:1; +	u16 crt_hotplug:1; +	u16 lvds_config:2; +	u16 tv_hotplug:1; +	u16 hdmi_config:2; + +	u8 static_display:1; +	u8 reserved2:7; +	u16 legacy_crt_max_x; +	u16 legacy_crt_max_y; +	u8 legacy_crt_max_refresh; + +	u8 hdmi_termination; +	u8 custom_vbt_version; +} __attribute__((packed)); +  bool intel_init_bios(struct drm_device *dev);  /* diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index d6a1a6e5539..4cf8e2e88a4 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -156,6 +156,9 @@ static bool intel_igdng_crt_detect_hotplug(struct drm_connector *connector)  	temp = adpa = I915_READ(PCH_ADPA); +	adpa &= ~ADPA_DAC_ENABLE; +	I915_WRITE(PCH_ADPA, adpa); +  	adpa &= ~ADPA_CRT_HOTPLUG_MASK;  	adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 | @@ -169,13 +172,14 @@ static bool intel_igdng_crt_detect_hotplug(struct drm_connector *connector)  	DRM_DEBUG("pch crt adpa 0x%x", adpa);  	I915_WRITE(PCH_ADPA, adpa); -	/* This might not be needed as not specified in spec...*/ -	udelay(1000); +	while ((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) != 0) +		;  	/* Check the status to see if both blue and green are on now */  	adpa = I915_READ(PCH_ADPA); -	if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) == -			ADPA_CRT_HOTPLUG_MONITOR_COLOR) +	adpa &= ADPA_CRT_HOTPLUG_MONITOR_MASK; +	if ((adpa == ADPA_CRT_HOTPLUG_MONITOR_COLOR) || +		(adpa == ADPA_CRT_HOTPLUG_MONITOR_MONO))  		ret = true;  	else  		ret = false; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 508838ee31e..d6fce213341 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -34,6 +34,8 @@  #include "drm_crtc_helper.h" +#define HAS_eDP (intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) +  bool intel_pipe_has_type (struct drm_crtc *crtc, int type);  static void intel_update_watermarks(struct drm_device *dev); @@ -88,7 +90,7 @@ struct intel_limit {  #define I8XX_P2_SLOW		      4  #define I8XX_P2_FAST		      2  #define I8XX_P2_LVDS_SLOW	      14 -#define I8XX_P2_LVDS_FAST	      14 /* No fast option */ +#define I8XX_P2_LVDS_FAST	      7  #define I8XX_P2_SLOW_LIMIT	 165000  #define I9XX_DOT_MIN		  20000 @@ -268,6 +270,9 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,  static bool  intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc,  		      int target, int refclk, intel_clock_t *best_clock); +static bool +intel_find_pll_igdng_dp(const intel_limit_t *, struct drm_crtc *crtc, +		      int target, int refclk, intel_clock_t *best_clock);  static const intel_limit_t intel_limits_i8xx_dvo = {          .dot = { .min = I8XX_DOT_MIN,		.max = I8XX_DOT_MAX }, @@ -598,6 +603,23 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type)      return false;  } +struct drm_connector * +intel_pipe_get_output (struct drm_crtc *crtc) +{ +    struct drm_device *dev = crtc->dev; +    struct drm_mode_config *mode_config = &dev->mode_config; +    struct drm_connector *l_entry, *ret = NULL; + +    list_for_each_entry(l_entry, &mode_config->connector_list, head) { +	    if (l_entry->encoder && +	        l_entry->encoder->crtc == crtc) { +		    ret = l_entry; +		    break; +	    } +    } +    return ret; +} +  #define INTELPllInvalid(s)   do { /* DRM_DEBUG(s); */ return false; } while (0)  /**   * Returns whether the given set of divisors are valid for a given refclk with @@ -645,7 +667,7 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,  	int err = target;  	if (IS_I9XX(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && -	    (I915_READ(LVDS) & LVDS_PORT_EN) != 0) { +	    (I915_READ(LVDS)) != 0) {  		/*  		 * For LVDS, if the panel is on, just rely on its current  		 * settings for dual-channel.  We haven't figured out how to @@ -752,6 +774,30 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,  }  static bool +intel_find_pll_igdng_dp(const intel_limit_t *limit, struct drm_crtc *crtc, +		      int target, int refclk, intel_clock_t *best_clock) +{ +	struct drm_device *dev = crtc->dev; +	intel_clock_t clock; +	if (target < 200000) { +		clock.n = 1; +		clock.p1 = 2; +		clock.p2 = 10; +		clock.m1 = 12; +		clock.m2 = 9; +	} else { +		clock.n = 2; +		clock.p1 = 1; +		clock.p2 = 10; +		clock.m1 = 14; +		clock.m2 = 8; +	} +	intel_clock(dev, refclk, &clock); +	memcpy(best_clock, &clock, sizeof(intel_clock_t)); +	return true; +} + +static bool  intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,  			int target, int refclk, intel_clock_t *best_clock)  { @@ -763,6 +809,14 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,  	int err_most = 47;  	found = false; +	/* eDP has only 2 clock choice, no n/m/p setting */ +	if (HAS_eDP) +		return true; + +	if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) +		return intel_find_pll_igdng_dp(limit, crtc, target, +					       refclk, best_clock); +  	if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {  		if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==  		    LVDS_CLKB_POWER_UP) @@ -998,6 +1052,90 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,  	return 0;  } +/* Disable the VGA plane that we never use */ +static void i915_disable_vga (struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	u8 sr1; +	u32 vga_reg; + +	if (IS_IGDNG(dev)) +		vga_reg = CPU_VGACNTRL; +	else +		vga_reg = VGACNTRL; + +	if (I915_READ(vga_reg) & VGA_DISP_DISABLE) +		return; + +	I915_WRITE8(VGA_SR_INDEX, 1); +	sr1 = I915_READ8(VGA_SR_DATA); +	I915_WRITE8(VGA_SR_DATA, sr1 | (1 << 5)); +	udelay(100); + +	I915_WRITE(vga_reg, VGA_DISP_DISABLE); +} + +static void igdng_disable_pll_edp (struct drm_crtc *crtc) +{ +	struct drm_device *dev = crtc->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	u32 dpa_ctl; + +	DRM_DEBUG("\n"); +	dpa_ctl = I915_READ(DP_A); +	dpa_ctl &= ~DP_PLL_ENABLE; +	I915_WRITE(DP_A, dpa_ctl); +} + +static void igdng_enable_pll_edp (struct drm_crtc *crtc) +{ +	struct drm_device *dev = crtc->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	u32 dpa_ctl; + +	dpa_ctl = I915_READ(DP_A); +	dpa_ctl |= DP_PLL_ENABLE; +	I915_WRITE(DP_A, dpa_ctl); +	udelay(200); +} + + +static void igdng_set_pll_edp (struct drm_crtc *crtc, int clock) +{ +	struct drm_device *dev = crtc->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	u32 dpa_ctl; + +	DRM_DEBUG("eDP PLL enable for clock %d\n", clock); +	dpa_ctl = I915_READ(DP_A); +	dpa_ctl &= ~DP_PLL_FREQ_MASK; + +	if (clock < 200000) { +		u32 temp; +		dpa_ctl |= DP_PLL_FREQ_160MHZ; +		/* workaround for 160Mhz: +		   1) program 0x4600c bits 15:0 = 0x8124 +		   2) program 0x46010 bit 0 = 1 +		   3) program 0x46034 bit 24 = 1 +		   4) program 0x64000 bit 14 = 1 +		   */ +		temp = I915_READ(0x4600c); +		temp &= 0xffff0000; +		I915_WRITE(0x4600c, temp | 0x8124); + +		temp = I915_READ(0x46010); +		I915_WRITE(0x46010, temp | 1); + +		temp = I915_READ(0x46034); +		I915_WRITE(0x46034, temp | (1 << 24)); +	} else { +		dpa_ctl |= DP_PLL_FREQ_270MHZ; +	} +	I915_WRITE(DP_A, dpa_ctl); + +	udelay(500); +} +  static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)  {  	struct drm_device *dev = crtc->dev; @@ -1015,6 +1153,7 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)  	int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;  	int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF;  	int pf_ctl_reg = (pipe == 0) ? PFA_CTL_1 : PFB_CTL_1; +	int pf_win_size = (pipe == 0) ? PFA_WIN_SZ : PFB_WIN_SZ;  	int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;  	int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;  	int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; @@ -1028,7 +1167,7 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)  	int trans_vblank_reg = (pipe == 0) ? TRANS_VBLANK_A : TRANS_VBLANK_B;  	int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B;  	u32 temp; -	int tries = 5, j; +	int tries = 5, j, n;  	/* XXX: When our outputs are all unaware of DPMS modes other than off  	 * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. @@ -1038,27 +1177,32 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)  	case DRM_MODE_DPMS_STANDBY:  	case DRM_MODE_DPMS_SUSPEND:  		DRM_DEBUG("crtc %d dpms on\n", pipe); -		/* enable PCH DPLL */ -		temp = I915_READ(pch_dpll_reg); -		if ((temp & DPLL_VCO_ENABLE) == 0) { -			I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE); -			I915_READ(pch_dpll_reg); -		} +		if (HAS_eDP) { +			/* enable eDP PLL */ +			igdng_enable_pll_edp(crtc); +		} else { +			/* enable PCH DPLL */ +			temp = I915_READ(pch_dpll_reg); +			if ((temp & DPLL_VCO_ENABLE) == 0) { +				I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE); +				I915_READ(pch_dpll_reg); +			} -		/* enable PCH FDI RX PLL, wait warmup plus DMI latency */ -		temp = I915_READ(fdi_rx_reg); -		I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE | -				FDI_SEL_PCDCLK | -				FDI_DP_PORT_WIDTH_X4); /* default 4 lanes */ -		I915_READ(fdi_rx_reg); -		udelay(200); +			/* enable PCH FDI RX PLL, wait warmup plus DMI latency */ +			temp = I915_READ(fdi_rx_reg); +			I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE | +					FDI_SEL_PCDCLK | +					FDI_DP_PORT_WIDTH_X4); /* default 4 lanes */ +			I915_READ(fdi_rx_reg); +			udelay(200); -		/* Enable CPU FDI TX PLL, always on for IGDNG */ -		temp = I915_READ(fdi_tx_reg); -		if ((temp & FDI_TX_PLL_ENABLE) == 0) { -			I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE); -			I915_READ(fdi_tx_reg); -			udelay(100); +			/* Enable CPU FDI TX PLL, always on for IGDNG */ +			temp = I915_READ(fdi_tx_reg); +			if ((temp & FDI_TX_PLL_ENABLE) == 0) { +				I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE); +				I915_READ(fdi_tx_reg); +				udelay(100); +			}  		}  		/* Enable CPU pipe */ @@ -1077,122 +1221,126 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)  			I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));  		} -		/* enable CPU FDI TX and PCH FDI RX */ -		temp = I915_READ(fdi_tx_reg); -		temp |= FDI_TX_ENABLE; -		temp |= FDI_DP_PORT_WIDTH_X4; /* default */ -		temp &= ~FDI_LINK_TRAIN_NONE; -		temp |= FDI_LINK_TRAIN_PATTERN_1; -		I915_WRITE(fdi_tx_reg, temp); -		I915_READ(fdi_tx_reg); +		if (!HAS_eDP) { +			/* enable CPU FDI TX and PCH FDI RX */ +			temp = I915_READ(fdi_tx_reg); +			temp |= FDI_TX_ENABLE; +			temp |= FDI_DP_PORT_WIDTH_X4; /* default */ +			temp &= ~FDI_LINK_TRAIN_NONE; +			temp |= FDI_LINK_TRAIN_PATTERN_1; +			I915_WRITE(fdi_tx_reg, temp); +			I915_READ(fdi_tx_reg); -		temp = I915_READ(fdi_rx_reg); -		temp &= ~FDI_LINK_TRAIN_NONE; -		temp |= FDI_LINK_TRAIN_PATTERN_1; -		I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE); -		I915_READ(fdi_rx_reg); +			temp = I915_READ(fdi_rx_reg); +			temp &= ~FDI_LINK_TRAIN_NONE; +			temp |= FDI_LINK_TRAIN_PATTERN_1; +			I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE); +			I915_READ(fdi_rx_reg); -		udelay(150); +			udelay(150); -		/* Train FDI. */ -		/* umask FDI RX Interrupt symbol_lock and bit_lock bit -		   for train result */ -		temp = I915_READ(fdi_rx_imr_reg); -		temp &= ~FDI_RX_SYMBOL_LOCK; -		temp &= ~FDI_RX_BIT_LOCK; -		I915_WRITE(fdi_rx_imr_reg, temp); -		I915_READ(fdi_rx_imr_reg); -		udelay(150); +			/* Train FDI. */ +			/* umask FDI RX Interrupt symbol_lock and bit_lock bit +			   for train result */ +			temp = I915_READ(fdi_rx_imr_reg); +			temp &= ~FDI_RX_SYMBOL_LOCK; +			temp &= ~FDI_RX_BIT_LOCK; +			I915_WRITE(fdi_rx_imr_reg, temp); +			I915_READ(fdi_rx_imr_reg); +			udelay(150); -		temp = I915_READ(fdi_rx_iir_reg); -		DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); +			temp = I915_READ(fdi_rx_iir_reg); +			DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); -		if ((temp & FDI_RX_BIT_LOCK) == 0) { -			for (j = 0; j < tries; j++) { -				temp = I915_READ(fdi_rx_iir_reg); -				DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); -				if (temp & FDI_RX_BIT_LOCK) -					break; -				udelay(200); -			} -			if (j != tries) +			if ((temp & FDI_RX_BIT_LOCK) == 0) { +				for (j = 0; j < tries; j++) { +					temp = I915_READ(fdi_rx_iir_reg); +					DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); +					if (temp & FDI_RX_BIT_LOCK) +						break; +					udelay(200); +				} +				if (j != tries) +					I915_WRITE(fdi_rx_iir_reg, +							temp | FDI_RX_BIT_LOCK); +				else +					DRM_DEBUG("train 1 fail\n"); +			} else {  				I915_WRITE(fdi_rx_iir_reg,  						temp | FDI_RX_BIT_LOCK); -			else -				DRM_DEBUG("train 1 fail\n"); -		} else { -			I915_WRITE(fdi_rx_iir_reg, -					temp | FDI_RX_BIT_LOCK); -			DRM_DEBUG("train 1 ok 2!\n"); -		} -		temp = I915_READ(fdi_tx_reg); -		temp &= ~FDI_LINK_TRAIN_NONE; -		temp |= FDI_LINK_TRAIN_PATTERN_2; -		I915_WRITE(fdi_tx_reg, temp); +				DRM_DEBUG("train 1 ok 2!\n"); +			} +			temp = I915_READ(fdi_tx_reg); +			temp &= ~FDI_LINK_TRAIN_NONE; +			temp |= FDI_LINK_TRAIN_PATTERN_2; +			I915_WRITE(fdi_tx_reg, temp); -		temp = I915_READ(fdi_rx_reg); -		temp &= ~FDI_LINK_TRAIN_NONE; -		temp |= FDI_LINK_TRAIN_PATTERN_2; -		I915_WRITE(fdi_rx_reg, temp); +			temp = I915_READ(fdi_rx_reg); +			temp &= ~FDI_LINK_TRAIN_NONE; +			temp |= FDI_LINK_TRAIN_PATTERN_2; +			I915_WRITE(fdi_rx_reg, temp); -		udelay(150); +			udelay(150); -		temp = I915_READ(fdi_rx_iir_reg); -		DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); +			temp = I915_READ(fdi_rx_iir_reg); +			DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); -		if ((temp & FDI_RX_SYMBOL_LOCK) == 0) { -			for (j = 0; j < tries; j++) { -				temp = I915_READ(fdi_rx_iir_reg); -				DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); -				if (temp & FDI_RX_SYMBOL_LOCK) -					break; -				udelay(200); -			} -			if (j != tries) { +			if ((temp & FDI_RX_SYMBOL_LOCK) == 0) { +				for (j = 0; j < tries; j++) { +					temp = I915_READ(fdi_rx_iir_reg); +					DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); +					if (temp & FDI_RX_SYMBOL_LOCK) +						break; +					udelay(200); +				} +				if (j != tries) { +					I915_WRITE(fdi_rx_iir_reg, +							temp | FDI_RX_SYMBOL_LOCK); +					DRM_DEBUG("train 2 ok 1!\n"); +				} else +					DRM_DEBUG("train 2 fail\n"); +			} else {  				I915_WRITE(fdi_rx_iir_reg,  						temp | FDI_RX_SYMBOL_LOCK); -				DRM_DEBUG("train 2 ok 1!\n"); -			} else -				DRM_DEBUG("train 2 fail\n"); -		} else { -			I915_WRITE(fdi_rx_iir_reg, temp | FDI_RX_SYMBOL_LOCK); -			DRM_DEBUG("train 2 ok 2!\n"); -		} -		DRM_DEBUG("train done\n"); +				DRM_DEBUG("train 2 ok 2!\n"); +			} +			DRM_DEBUG("train done\n"); -		/* set transcoder timing */ -		I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg)); -		I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg)); -		I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg)); +			/* set transcoder timing */ +			I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg)); +			I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg)); +			I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg)); -		I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg)); -		I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg)); -		I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg)); +			I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg)); +			I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg)); +			I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg)); -		/* enable PCH transcoder */ -		temp = I915_READ(transconf_reg); -		I915_WRITE(transconf_reg, temp | TRANS_ENABLE); -		I915_READ(transconf_reg); +			/* enable PCH transcoder */ +			temp = I915_READ(transconf_reg); +			I915_WRITE(transconf_reg, temp | TRANS_ENABLE); +			I915_READ(transconf_reg); -		while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0) -			; +			while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0) +				; -		/* enable normal */ +			/* enable normal */ -		temp = I915_READ(fdi_tx_reg); -		temp &= ~FDI_LINK_TRAIN_NONE; -		I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE | -				FDI_TX_ENHANCE_FRAME_ENABLE); -		I915_READ(fdi_tx_reg); +			temp = I915_READ(fdi_tx_reg); +			temp &= ~FDI_LINK_TRAIN_NONE; +			I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE | +					FDI_TX_ENHANCE_FRAME_ENABLE); +			I915_READ(fdi_tx_reg); -		temp = I915_READ(fdi_rx_reg); -		temp &= ~FDI_LINK_TRAIN_NONE; -		I915_WRITE(fdi_rx_reg, temp | FDI_LINK_TRAIN_NONE | -				FDI_RX_ENHANCE_FRAME_ENABLE); -		I915_READ(fdi_rx_reg); +			temp = I915_READ(fdi_rx_reg); +			temp &= ~FDI_LINK_TRAIN_NONE; +			I915_WRITE(fdi_rx_reg, temp | FDI_LINK_TRAIN_NONE | +					FDI_RX_ENHANCE_FRAME_ENABLE); +			I915_READ(fdi_rx_reg); -		/* wait one idle pattern time */ -		udelay(100); +			/* wait one idle pattern time */ +			udelay(100); + +		}  		intel_crtc_load_lut(crtc); @@ -1200,8 +1348,7 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)  	case DRM_MODE_DPMS_OFF:  		DRM_DEBUG("crtc %d dpms off\n", pipe); -		/* Disable the VGA plane that we never use */ -		I915_WRITE(CPU_VGACNTRL, VGA_DISP_DISABLE); +		i915_disable_vga(dev);  		/* Disable display plane */  		temp = I915_READ(dspcntr_reg); @@ -1217,17 +1364,23 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)  		if ((temp & PIPEACONF_ENABLE) != 0) {  			I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);  			I915_READ(pipeconf_reg); +			n = 0;  			/* wait for cpu pipe off, pipe state */ -			while ((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0) -				; +			while ((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0) { +				n++; +				if (n < 60) { +					udelay(500); +					continue; +				} else { +					DRM_DEBUG("pipe %d off delay\n", pipe); +					break; +				} +			}  		} else  			DRM_DEBUG("crtc %d is disabled\n", pipe); -		/* IGDNG-A : disable cpu panel fitter ? */ -		temp = I915_READ(pf_ctl_reg); -		if ((temp & PF_ENABLE) != 0) { -			I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE); -			I915_READ(pf_ctl_reg); +		if (HAS_eDP) { +			igdng_disable_pll_edp(crtc);  		}  		/* disable CPU FDI tx and PCH FDI rx */ @@ -1239,6 +1392,8 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)  		I915_WRITE(fdi_rx_reg, temp & ~FDI_RX_ENABLE);  		I915_READ(fdi_rx_reg); +		udelay(100); +  		/* still set train pattern 1 */  		temp = I915_READ(fdi_tx_reg);  		temp &= ~FDI_LINK_TRAIN_NONE; @@ -1250,14 +1405,25 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)  		temp |= FDI_LINK_TRAIN_PATTERN_1;  		I915_WRITE(fdi_rx_reg, temp); +		udelay(100); +  		/* disable PCH transcoder */  		temp = I915_READ(transconf_reg);  		if ((temp & TRANS_ENABLE) != 0) {  			I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE);  			I915_READ(transconf_reg); +			n = 0;  			/* wait for PCH transcoder off, transcoder state */ -			while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) != 0) -				; +			while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) != 0) { +				n++; +				if (n < 60) { +					udelay(500); +					continue; +				} else { +					DRM_DEBUG("transcoder %d off delay\n", pipe); +					break; +				} +			}  		}  		/* disable PCH DPLL */ @@ -1275,6 +1441,22 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)  			I915_READ(fdi_rx_reg);  		} +		/* Disable CPU FDI TX PLL */ +		temp = I915_READ(fdi_tx_reg); +		if ((temp & FDI_TX_PLL_ENABLE) != 0) { +			I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_PLL_ENABLE); +			I915_READ(fdi_tx_reg); +			udelay(100); +		} + +		/* Disable PF */ +		temp = I915_READ(pf_ctl_reg); +		if ((temp & PF_ENABLE) != 0) { +			I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE); +			I915_READ(pf_ctl_reg); +		} +		I915_WRITE(pf_win_size, 0); +  		/* Wait for the clocks to turn off. */  		udelay(150);  		break; @@ -1342,7 +1524,7 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)  		//intel_crtc_dpms_video(crtc, FALSE); TODO  		/* Disable the VGA plane that we never use */ -		I915_WRITE(VGACNTRL, VGA_DISP_DISABLE); +		i915_disable_vga(dev);  		/* Disable display plane */  		temp = I915_READ(dspcntr_reg); @@ -1623,48 +1805,72 @@ static struct intel_watermark_params igd_cursor_hplloff_wm = {  	IGD_FIFO_LINE_SIZE  };  static struct intel_watermark_params i945_wm_info = { -	I915_FIFO_LINE_SIZE, +	I945_FIFO_SIZE,  	I915_MAX_WM,  	1, -	0, -	IGD_FIFO_LINE_SIZE +	2, +	I915_FIFO_LINE_SIZE  };  static struct intel_watermark_params i915_wm_info = { -	I945_FIFO_SIZE, +	I915_FIFO_SIZE,  	I915_MAX_WM,  	1, -	0, +	2,  	I915_FIFO_LINE_SIZE  };  static struct intel_watermark_params i855_wm_info = {  	I855GM_FIFO_SIZE,  	I915_MAX_WM,  	1, -	0, +	2,  	I830_FIFO_LINE_SIZE  };  static struct intel_watermark_params i830_wm_info = {  	I830_FIFO_SIZE,  	I915_MAX_WM,  	1, -	0, +	2,  	I830_FIFO_LINE_SIZE  }; +/** + * intel_calculate_wm - calculate watermark level + * @clock_in_khz: pixel clock + * @wm: chip FIFO params + * @pixel_size: display pixel size + * @latency_ns: memory latency for the platform + * + * Calculate the watermark level (the level at which the display plane will + * start fetching from memory again).  Each chip has a different display + * FIFO size and allocation, so the caller needs to figure that out and pass + * in the correct intel_watermark_params structure. + * + * As the pixel clock runs, the FIFO will be drained at a rate that depends + * on the pixel size.  When it reaches the watermark level, it'll start + * fetching FIFO line sized based chunks from memory until the FIFO fills + * past the watermark point.  If the FIFO drains completely, a FIFO underrun + * will occur, and a display engine hang could result. + */  static unsigned long intel_calculate_wm(unsigned long clock_in_khz,  					struct intel_watermark_params *wm,  					int pixel_size,  					unsigned long latency_ns)  { -	unsigned long bytes_required, wm_size; +	long entries_required, wm_size; + +	entries_required = (clock_in_khz * pixel_size * latency_ns) / 1000000; +	entries_required /= wm->cacheline_size; + +	DRM_DEBUG("FIFO entries required for mode: %d\n", entries_required); + +	wm_size = wm->fifo_size - (entries_required + wm->guard_size); -	bytes_required = (clock_in_khz * pixel_size * latency_ns) / 1000000; -	bytes_required /= wm->cacheline_size; -	wm_size = wm->fifo_size - bytes_required - wm->guard_size; +	DRM_DEBUG("FIFO watermark level: %d\n", wm_size); -	if (wm_size > wm->max_wm) +	/* Don't promote wm_size to unsigned... */ +	if (wm_size > (long)wm->max_wm)  		wm_size = wm->max_wm; -	if (wm_size == 0) +	if (wm_size <= 0)  		wm_size = wm->default_wm;  	return wm_size;  } @@ -1799,8 +2005,40 @@ static void igd_enable_cxsr(struct drm_device *dev, unsigned long clock,  	return;  } -const static int latency_ns = 5000; /* default for non-igd platforms */ +const static int latency_ns = 3000; /* default for non-igd platforms */ +static int intel_get_fifo_size(struct drm_device *dev, int plane) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	uint32_t dsparb = I915_READ(DSPARB); +	int size; + +	if (IS_I9XX(dev)) { +		if (plane == 0) +			size = dsparb & 0x7f; +		else +			size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) - +				(dsparb & 0x7f); +	} else if (IS_I85X(dev)) { +		if (plane == 0) +			size = dsparb & 0x1ff; +		else +			size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) - +				(dsparb & 0x1ff); +		size >>= 1; /* Convert to cachelines */ +	} else if (IS_845G(dev)) { +		size = dsparb & 0x7f; +		size >>= 2; /* Convert to cachelines */ +	} else { +		size = dsparb & 0x7f; +		size >>= 1; /* Convert to cachelines */ +	} + +	DRM_DEBUG("FIFO size - (0x%08x) %s: %d\n", dsparb, plane ? "B" : "A", +		  size); + +	return size; +}  static void i965_update_wm(struct drm_device *dev)  { @@ -1817,101 +2055,89 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,  			   int planeb_clock, int sr_hdisplay, int pixel_size)  {  	struct drm_i915_private *dev_priv = dev->dev_private; -	uint32_t fwater_lo = I915_READ(FW_BLC) & MM_FIFO_WATERMARK; -	uint32_t fwater_hi = I915_READ(FW_BLC2) & LM_FIFO_WATERMARK; -	int bsize, asize, cwm, bwm = 1, awm = 1, srwm = 1; -	uint32_t dsparb = I915_READ(DSPARB); -	int planea_entries, planeb_entries; -	struct intel_watermark_params *wm_params; +	uint32_t fwater_lo; +	uint32_t fwater_hi; +	int total_size, cacheline_size, cwm, srwm = 1; +	int planea_wm, planeb_wm; +	struct intel_watermark_params planea_params, planeb_params;  	unsigned long line_time_us;  	int sr_clock, sr_entries = 0; +	/* Create copies of the base settings for each pipe */  	if (IS_I965GM(dev) || IS_I945GM(dev)) -		wm_params = &i945_wm_info; +		planea_params = planeb_params = i945_wm_info;  	else if (IS_I9XX(dev)) -		wm_params = &i915_wm_info; +		planea_params = planeb_params = i915_wm_info;  	else -		wm_params = &i855_wm_info; +		planea_params = planeb_params = i855_wm_info; -	planea_entries = intel_calculate_wm(planea_clock, wm_params, -					    pixel_size, latency_ns); -	planeb_entries = intel_calculate_wm(planeb_clock, wm_params, -					    pixel_size, latency_ns); +	/* Grab a couple of global values before we overwrite them */ +	total_size = planea_params.fifo_size; +	cacheline_size = planea_params.cacheline_size; -	DRM_DEBUG("FIFO entries - A: %d, B: %d\n", planea_entries, -		  planeb_entries); +	/* Update per-plane FIFO sizes */ +	planea_params.fifo_size = intel_get_fifo_size(dev, 0); +	planeb_params.fifo_size = intel_get_fifo_size(dev, 1); -	if (IS_I9XX(dev)) { -		asize = dsparb & 0x7f; -		bsize = (dsparb >> DSPARB_CSTART_SHIFT) & 0x7f; -	} else { -		asize = dsparb & 0x1ff; -		bsize = (dsparb >> DSPARB_BEND_SHIFT) & 0x1ff; -	} -	DRM_DEBUG("FIFO size - A: %d, B: %d\n", asize, bsize); - -	/* Two extra entries for padding */ -	awm = asize - (planea_entries + 2); -	bwm = bsize - (planeb_entries + 2); - -	/* Sanity check against potentially bad FIFO allocations */ -	if (awm <= 0) { -		/* pipe is on but has too few FIFO entries */ -		if (planea_entries != 0) -			DRM_DEBUG("plane A needs more FIFO entries\n"); -		awm = 1; -	} -	if (bwm <= 0) { -		if (planeb_entries != 0) -			DRM_DEBUG("plane B needs more FIFO entries\n"); -		bwm = 1; -	} +	planea_wm = intel_calculate_wm(planea_clock, &planea_params, +				       pixel_size, latency_ns); +	planeb_wm = intel_calculate_wm(planeb_clock, &planeb_params, +				       pixel_size, latency_ns); +	DRM_DEBUG("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm);  	/*  	 * Overlay gets an aggressive default since video jitter is bad.  	 */  	cwm = 2; -	/* Calc sr entries for one pipe configs */ -	if (!planea_clock || !planeb_clock) { +	/* Calc sr entries for one plane configs */ +	if (sr_hdisplay && (!planea_clock || !planeb_clock)) { +		/* self-refresh has much higher latency */ +		const static int sr_latency_ns = 6000; +  		sr_clock = planea_clock ? planea_clock : planeb_clock; -		line_time_us = (sr_hdisplay * 1000) / sr_clock; -		sr_entries = (((latency_ns / line_time_us) + 1) * pixel_size * -			      sr_hdisplay) / 1000; -		sr_entries = roundup(sr_entries / wm_params->cacheline_size, 1); -		if (sr_entries < wm_params->fifo_size) -			srwm = wm_params->fifo_size - sr_entries; +		line_time_us = ((sr_hdisplay * 1000) / sr_clock); + +		/* Use ns/us then divide to preserve precision */ +		sr_entries = (((sr_latency_ns / line_time_us) + 1) * +			      pixel_size * sr_hdisplay) / 1000; +		sr_entries = roundup(sr_entries / cacheline_size, 1); +		DRM_DEBUG("self-refresh entries: %d\n", sr_entries); +		srwm = total_size - sr_entries; +		if (srwm < 0) +			srwm = 1; +		if (IS_I9XX(dev)) +			I915_WRITE(FW_BLC_SELF, (srwm & 0x3f));  	}  	DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n", -		  awm, bwm, cwm, srwm); +		  planea_wm, planeb_wm, cwm, srwm); -	fwater_lo = fwater_lo | ((bwm & 0x3f) << 16) | (awm & 0x3f); -	fwater_hi = fwater_hi | (cwm & 0x1f); +	fwater_lo = ((planeb_wm & 0x3f) << 16) | (planea_wm & 0x3f); +	fwater_hi = (cwm & 0x1f); + +	/* Set request length to 8 cachelines per fetch */ +	fwater_lo = fwater_lo | (1 << 24) | (1 << 8); +	fwater_hi = fwater_hi | (1 << 8);  	I915_WRITE(FW_BLC, fwater_lo);  	I915_WRITE(FW_BLC2, fwater_hi); -	if (IS_I9XX(dev)) -		I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN | (srwm & 0x3f));  }  static void i830_update_wm(struct drm_device *dev, int planea_clock,  			   int pixel_size)  {  	struct drm_i915_private *dev_priv = dev->dev_private; -	uint32_t dsparb = I915_READ(DSPARB); -	uint32_t fwater_lo = I915_READ(FW_BLC) & MM_FIFO_WATERMARK; -	unsigned int asize, awm; -	int planea_entries; - -	planea_entries = intel_calculate_wm(planea_clock, &i830_wm_info, -					    pixel_size, latency_ns); +	uint32_t fwater_lo = I915_READ(FW_BLC) & ~0xfff; +	int planea_wm; -	asize = dsparb & 0x7f; +	i830_wm_info.fifo_size = intel_get_fifo_size(dev, 0); -	awm = asize - planea_entries; +	planea_wm = intel_calculate_wm(planea_clock, &i830_wm_info, +				       pixel_size, latency_ns); +	fwater_lo |= (3<<8) | planea_wm; -	fwater_lo = fwater_lo | awm; +	DRM_DEBUG("Setting FIFO watermarks - A: %d\n", planea_wm);  	I915_WRITE(FW_BLC, fwater_lo);  } @@ -1984,7 +2210,7 @@ static void intel_update_watermarks(struct drm_device *dev)  	if (enabled <= 0)  		return; -	/* Single pipe configs can enable self refresh */ +	/* Single plane configs can enable self refresh */  	if (enabled == 1 && IS_IGD(dev))  		igd_enable_cxsr(dev, sr_clock, pixel_size);  	else if (IS_IGD(dev)) @@ -2028,6 +2254,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,  	u32 dpll = 0, fp = 0, dspcntr, pipeconf;  	bool ok, is_sdvo = false, is_dvo = false;  	bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false; +	bool is_edp = false;  	struct drm_mode_config *mode_config = &dev->mode_config;  	struct drm_connector *connector;  	const intel_limit_t *limit; @@ -2043,6 +2270,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,  	int lvds_reg = LVDS;  	u32 temp;  	int sdvo_pixel_multiply; +	int target_clock;  	drm_vblank_pre_modeset(dev, pipe); @@ -2074,6 +2302,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,  		case INTEL_OUTPUT_DISPLAYPORT:  			is_dp = true;  			break; +		case INTEL_OUTPUT_EDP: +			is_edp = true; +			break;  		}  		num_outputs++; @@ -2125,11 +2356,29 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,  	}  	/* FDI link */ -	if (IS_IGDNG(dev)) -		igdng_compute_m_n(3, 4, /* lane num 4 */ -				adjusted_mode->clock, -				270000, /* lane clock */ -				&m_n); +	if (IS_IGDNG(dev)) { +		int lane, link_bw; +		/* eDP doesn't require FDI link, so just set DP M/N +		   according to current link config */ +		if (is_edp) { +			struct drm_connector *edp; +			target_clock = mode->clock; +			edp = intel_pipe_get_output(crtc); +			intel_edp_link_config(to_intel_output(edp), +					&lane, &link_bw); +		} else { +			/* DP over FDI requires target mode clock +			   instead of link clock */ +			if (is_dp) +				target_clock = mode->clock; +			else +				target_clock = adjusted_mode->clock; +			lane = 4; +			link_bw = 270000; +		} +		igdng_compute_m_n(3, lane, target_clock, +				  link_bw, &m_n); +	}  	if (IS_IGD(dev))  		fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2; @@ -2250,29 +2499,15 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,  		dpll_reg = pch_dpll_reg;  	} -	if (dpll & DPLL_VCO_ENABLE) { +	if (is_edp) { +		igdng_disable_pll_edp(crtc); +	} else if ((dpll & DPLL_VCO_ENABLE)) {  		I915_WRITE(fp_reg, fp);  		I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);  		I915_READ(dpll_reg);  		udelay(150);  	} -	if (IS_IGDNG(dev)) { -		/* enable PCH clock reference source */ -		/* XXX need to change the setting for other outputs */ -		u32 temp; -		temp = I915_READ(PCH_DREF_CONTROL); -		temp &= ~DREF_NONSPREAD_SOURCE_MASK; -		temp |= DREF_NONSPREAD_CK505_ENABLE; -		temp &= ~DREF_SSC_SOURCE_MASK; -		temp |= DREF_SSC_SOURCE_ENABLE; -		temp &= ~DREF_SSC1_ENABLE; -		/* if no eDP, disable source output to CPU */ -		temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK; -		temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE; -		I915_WRITE(PCH_DREF_CONTROL, temp); -	} -  	/* The LVDS pin pair needs to be on before the DPLLs are enabled.  	 * This is an exception to the general rule that mode_set doesn't turn  	 * things on. @@ -2304,23 +2539,25 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,  	if (is_dp)  		intel_dp_set_m_n(crtc, mode, adjusted_mode); -	I915_WRITE(fp_reg, fp); -	I915_WRITE(dpll_reg, dpll); -	I915_READ(dpll_reg); -	/* Wait for the clocks to stabilize. */ -	udelay(150); - -	if (IS_I965G(dev) && !IS_IGDNG(dev)) { -		sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; -		I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | -			   ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); -	} else { -		/* write it again -- the BIOS does, after all */ +	if (!is_edp) { +		I915_WRITE(fp_reg, fp);  		I915_WRITE(dpll_reg, dpll); +		I915_READ(dpll_reg); +		/* Wait for the clocks to stabilize. */ +		udelay(150); + +		if (IS_I965G(dev) && !IS_IGDNG(dev)) { +			sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; +			I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | +					((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); +		} else { +			/* write it again -- the BIOS does, after all */ +			I915_WRITE(dpll_reg, dpll); +		} +		I915_READ(dpll_reg); +		/* Wait for the clocks to stabilize. */ +		udelay(150);  	} -	I915_READ(dpll_reg); -	/* Wait for the clocks to stabilize. */ -	udelay(150);  	I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |  		   ((adjusted_mode->crtc_htotal - 1) << 16)); @@ -2350,10 +2587,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,  		I915_WRITE(link_m1_reg, m_n.link_m);  		I915_WRITE(link_n1_reg, m_n.link_n); -		 /* enable FDI RX PLL too */ -		temp = I915_READ(fdi_rx_reg); -		I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE); -		udelay(200); +		if (is_edp) { +			igdng_set_pll_edp(crtc, adjusted_mode->clock); +		} else { +			/* enable FDI RX PLL too */ +			temp = I915_READ(fdi_rx_reg); +			I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE); +			udelay(200); +		}  	}  	I915_WRITE(pipeconf_reg, pipeconf); @@ -2951,12 +3192,17 @@ static void intel_setup_outputs(struct drm_device *dev)  	if (IS_IGDNG(dev)) {  		int found; +		if (IS_MOBILE(dev) && (I915_READ(DP_A) & DP_DETECTED)) +			intel_dp_init(dev, DP_A); +  		if (I915_READ(HDMIB) & PORT_DETECTED) {  			/* check SDVOB */  			/* found = intel_sdvo_init(dev, HDMIB); */  			found = 0;  			if (!found)  				intel_hdmi_init(dev, HDMIB); +			if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED)) +				intel_dp_init(dev, PCH_DP_B);  		}  		if (I915_READ(HDMIC) & PORT_DETECTED) @@ -2965,6 +3211,12 @@ static void intel_setup_outputs(struct drm_device *dev)  		if (I915_READ(HDMID) & PORT_DETECTED)  			intel_hdmi_init(dev, HDMID); +		if (I915_READ(PCH_DP_C) & DP_DETECTED) +			intel_dp_init(dev, PCH_DP_C); + +		if (I915_READ(PCH_DP_D) & DP_DETECTED) +			intel_dp_init(dev, PCH_DP_D); +  	} else if (IS_I9XX(dev)) {  		int found;  		u32 reg; @@ -3039,6 +3291,10 @@ static void intel_setup_outputs(struct drm_device *dev)  				     (1 << 1));  			clone_mask = (1 << INTEL_OUTPUT_DISPLAYPORT);  			break; +		case INTEL_OUTPUT_EDP: +			crtc_mask = (1 << 1); +			clone_mask = (1 << INTEL_OUTPUT_EDP); +			break;  		}  		encoder->possible_crtcs = crtc_mask;  		encoder->possible_clones = intel_connector_clones(dev, clone_mask); @@ -3148,6 +3404,9 @@ void intel_modeset_init(struct drm_device *dev)  	if (IS_I965G(dev)) {  		dev->mode_config.max_width = 8192;  		dev->mode_config.max_height = 8192; +	} else if (IS_I9XX(dev)) { +		dev->mode_config.max_width = 4096; +		dev->mode_config.max_height = 4096;  	} else {  		dev->mode_config.max_width = 2048;  		dev->mode_config.max_height = 2048; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6770ae88370..a6ff15ac548 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -40,6 +40,8 @@  #define DP_LINK_CONFIGURATION_SIZE	9 +#define IS_eDP(i) ((i)->type == INTEL_OUTPUT_EDP) +  struct intel_dp_priv {  	uint32_t output_reg;  	uint32_t DP; @@ -63,6 +65,19 @@ intel_dp_link_train(struct intel_output *intel_output, uint32_t DP,  static void  intel_dp_link_down(struct intel_output *intel_output, uint32_t DP); +void +intel_edp_link_config (struct intel_output *intel_output, +		int *lane_num, int *link_bw) +{ +	struct intel_dp_priv   *dp_priv = intel_output->dev_priv; + +	*lane_num = dp_priv->lane_count; +	if (dp_priv->link_bw == DP_LINK_BW_1_62) +		*link_bw = 162000; +	else if (dp_priv->link_bw == DP_LINK_BW_2_7) +		*link_bw = 270000; +} +  static int  intel_dp_max_lane_count(struct intel_output *intel_output)  { @@ -206,7 +221,13 @@ intel_dp_aux_ch(struct intel_output *intel_output,  	 * and would like to run at 2MHz. So, take the  	 * hrawclk value and divide by 2 and use that  	 */ -	aux_clock_divider = intel_hrawclk(dev) / 2; +	if (IS_eDP(intel_output)) +		aux_clock_divider = 225; /* eDP input clock at 450Mhz */ +	else if (IS_IGDNG(dev)) +		aux_clock_divider = 62; /* IGDNG: input clock fixed at 125Mhz */ +	else +		aux_clock_divider = intel_hrawclk(dev) / 2; +  	/* Must try at least 3 times according to DP spec */  	for (try = 0; try < 5; try++) {  		/* Load the send data into the aux channel data registers */ @@ -236,7 +257,7 @@ intel_dp_aux_ch(struct intel_output *intel_output,  		}  		/* Clear done status and any errors */ -		I915_WRITE(ch_ctl, (ctl | +		I915_WRITE(ch_ctl, (status |  				DP_AUX_CH_CTL_DONE |  				DP_AUX_CH_CTL_TIME_OUT_ERROR |  				DP_AUX_CH_CTL_RECEIVE_ERROR)); @@ -295,7 +316,7 @@ intel_dp_aux_native_write(struct intel_output *intel_output,  		return -1;  	msg[0] = AUX_NATIVE_WRITE << 4;  	msg[1] = address >> 8; -	msg[2] = address; +	msg[2] = address & 0xff;  	msg[3] = send_bytes - 1;  	memcpy(&msg[4], send, send_bytes);  	msg_bytes = send_bytes + 4; @@ -387,8 +408,8 @@ intel_dp_i2c_init(struct intel_output *intel_output, const char *name)  	memset(&dp_priv->adapter, '\0', sizeof (dp_priv->adapter));  	dp_priv->adapter.owner = THIS_MODULE;  	dp_priv->adapter.class = I2C_CLASS_DDC; -	strncpy (dp_priv->adapter.name, name, sizeof dp_priv->adapter.name - 1); -	dp_priv->adapter.name[sizeof dp_priv->adapter.name - 1] = '\0'; +	strncpy (dp_priv->adapter.name, name, sizeof(dp_priv->adapter.name) - 1); +	dp_priv->adapter.name[sizeof(dp_priv->adapter.name) - 1] = '\0';  	dp_priv->adapter.algo_data = &dp_priv->algo;  	dp_priv->adapter.dev.parent = &intel_output->base.kdev; @@ -493,22 +514,40 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,  	intel_dp_compute_m_n(3, lane_count,  			     mode->clock, adjusted_mode->clock, &m_n); -	if (intel_crtc->pipe == 0) { -		I915_WRITE(PIPEA_GMCH_DATA_M, -		       ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | -		       m_n.gmch_m); -		I915_WRITE(PIPEA_GMCH_DATA_N, -		       m_n.gmch_n); -		I915_WRITE(PIPEA_DP_LINK_M, m_n.link_m); -		I915_WRITE(PIPEA_DP_LINK_N, m_n.link_n); +	if (IS_IGDNG(dev)) { +		if (intel_crtc->pipe == 0) { +			I915_WRITE(TRANSA_DATA_M1, +				   ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | +				   m_n.gmch_m); +			I915_WRITE(TRANSA_DATA_N1, m_n.gmch_n); +			I915_WRITE(TRANSA_DP_LINK_M1, m_n.link_m); +			I915_WRITE(TRANSA_DP_LINK_N1, m_n.link_n); +		} else { +			I915_WRITE(TRANSB_DATA_M1, +				   ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | +				   m_n.gmch_m); +			I915_WRITE(TRANSB_DATA_N1, m_n.gmch_n); +			I915_WRITE(TRANSB_DP_LINK_M1, m_n.link_m); +			I915_WRITE(TRANSB_DP_LINK_N1, m_n.link_n); +		}  	} else { -		I915_WRITE(PIPEB_GMCH_DATA_M, -		       ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | -		       m_n.gmch_m); -		I915_WRITE(PIPEB_GMCH_DATA_N, -		       m_n.gmch_n); -		I915_WRITE(PIPEB_DP_LINK_M, m_n.link_m); -		I915_WRITE(PIPEB_DP_LINK_N, m_n.link_n); +		if (intel_crtc->pipe == 0) { +			I915_WRITE(PIPEA_GMCH_DATA_M, +				   ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | +				   m_n.gmch_m); +			I915_WRITE(PIPEA_GMCH_DATA_N, +				   m_n.gmch_n); +			I915_WRITE(PIPEA_DP_LINK_M, m_n.link_m); +			I915_WRITE(PIPEA_DP_LINK_N, m_n.link_n); +		} else { +			I915_WRITE(PIPEB_GMCH_DATA_M, +				   ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | +				   m_n.gmch_m); +			I915_WRITE(PIPEB_GMCH_DATA_N, +					m_n.gmch_n); +			I915_WRITE(PIPEB_DP_LINK_M, m_n.link_m); +			I915_WRITE(PIPEB_DP_LINK_N, m_n.link_n); +		}  	}  } @@ -556,8 +595,38 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,  	if (intel_crtc->pipe == 1)  		dp_priv->DP |= DP_PIPEB_SELECT; + +	if (IS_eDP(intel_output)) { +		/* don't miss out required setting for eDP */ +		dp_priv->DP |= DP_PLL_ENABLE; +		if (adjusted_mode->clock < 200000) +			dp_priv->DP |= DP_PLL_FREQ_160MHZ; +		else +			dp_priv->DP |= DP_PLL_FREQ_270MHZ; +	}  } +static void igdng_edp_backlight_on (struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	u32 pp; + +	DRM_DEBUG("\n"); +	pp = I915_READ(PCH_PP_CONTROL); +	pp |= EDP_BLC_ENABLE; +	I915_WRITE(PCH_PP_CONTROL, pp); +} + +static void igdng_edp_backlight_off (struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	u32 pp; + +	DRM_DEBUG("\n"); +	pp = I915_READ(PCH_PP_CONTROL); +	pp &= ~EDP_BLC_ENABLE; +	I915_WRITE(PCH_PP_CONTROL, pp); +}  static void  intel_dp_dpms(struct drm_encoder *encoder, int mode) @@ -569,11 +638,17 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)  	uint32_t dp_reg = I915_READ(dp_priv->output_reg);  	if (mode != DRM_MODE_DPMS_ON) { -		if (dp_reg & DP_PORT_EN) +		if (dp_reg & DP_PORT_EN) {  			intel_dp_link_down(intel_output, dp_priv->DP); +			if (IS_eDP(intel_output)) +				igdng_edp_backlight_off(dev); +		}  	} else { -		if (!(dp_reg & DP_PORT_EN)) +		if (!(dp_reg & DP_PORT_EN)) {  			intel_dp_link_train(intel_output, dp_priv->DP, dp_priv->link_configuration); +			if (IS_eDP(intel_output)) +				igdng_edp_backlight_on(dev); +		}  	}  	dp_priv->dpms_mode = mode;  } @@ -935,6 +1010,23 @@ intel_dp_link_down(struct intel_output *intel_output, uint32_t DP)  	struct drm_i915_private *dev_priv = dev->dev_private;  	struct intel_dp_priv *dp_priv = intel_output->dev_priv; +	DRM_DEBUG("\n"); + +	if (IS_eDP(intel_output)) { +		DP &= ~DP_PLL_ENABLE; +		I915_WRITE(dp_priv->output_reg, DP); +		POSTING_READ(dp_priv->output_reg); +		udelay(100); +	} + +	DP &= ~DP_LINK_TRAIN_MASK; +	I915_WRITE(dp_priv->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE); +	POSTING_READ(dp_priv->output_reg); + +	udelay(17000); + +	if (IS_eDP(intel_output)) +		DP |= DP_LINK_TRAIN_OFF;  	I915_WRITE(dp_priv->output_reg, DP & ~DP_PORT_EN);  	POSTING_READ(dp_priv->output_reg);  } @@ -978,6 +1070,24 @@ intel_dp_check_link_status(struct intel_output *intel_output)  		intel_dp_link_train(intel_output, dp_priv->DP, dp_priv->link_configuration);  } +static enum drm_connector_status +igdng_dp_detect(struct drm_connector *connector) +{ +	struct intel_output *intel_output = to_intel_output(connector); +	struct intel_dp_priv *dp_priv = intel_output->dev_priv; +	enum drm_connector_status status; + +	status = connector_status_disconnected; +	if (intel_dp_aux_native_read(intel_output, +				     0x000, dp_priv->dpcd, +				     sizeof (dp_priv->dpcd)) == sizeof (dp_priv->dpcd)) +	{ +		if (dp_priv->dpcd[0] != 0) +			status = connector_status_connected; +	} +	return status; +} +  /**   * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection.   * @@ -996,6 +1106,9 @@ intel_dp_detect(struct drm_connector *connector)  	dp_priv->has_audio = false; +	if (IS_IGDNG(dev)) +		return igdng_dp_detect(connector); +  	temp = I915_READ(PORT_HOTPLUG_EN);  	I915_WRITE(PORT_HOTPLUG_EN, @@ -1039,11 +1152,27 @@ intel_dp_detect(struct drm_connector *connector)  static int intel_dp_get_modes(struct drm_connector *connector)  {  	struct intel_output *intel_output = to_intel_output(connector); +	struct drm_device *dev = intel_output->base.dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	int ret;  	/* We should parse the EDID data and find out if it has an audio sink  	 */ -	return intel_ddc_get_modes(intel_output); +	ret = intel_ddc_get_modes(intel_output); +	if (ret) +		return ret; + +	/* if eDP has no EDID, try to use fixed panel mode from VBT */ +	if (IS_eDP(intel_output)) { +		if (dev_priv->panel_fixed_mode != NULL) { +			struct drm_display_mode *mode; +			mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode); +			drm_mode_probed_add(connector, mode); +			return 1; +		} +	} +	return 0;  }  static void @@ -1106,6 +1235,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)  	struct drm_connector *connector;  	struct intel_output *intel_output;  	struct intel_dp_priv *dp_priv; +	const char *name = NULL;  	intel_output = kcalloc(sizeof(struct intel_output) +   			       sizeof(struct intel_dp_priv), 1, GFP_KERNEL); @@ -1119,7 +1249,10 @@ intel_dp_init(struct drm_device *dev, int output_reg)  			   DRM_MODE_CONNECTOR_DisplayPort);  	drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs); -	intel_output->type = INTEL_OUTPUT_DISPLAYPORT; +	if (output_reg == DP_A) +		intel_output->type = INTEL_OUTPUT_EDP; +	else +		intel_output->type = INTEL_OUTPUT_DISPLAYPORT;  	connector->interlace_allowed = true;  	connector->doublescan_allowed = 0; @@ -1139,12 +1272,41 @@ intel_dp_init(struct drm_device *dev, int output_reg)  	drm_sysfs_connector_add(connector);  	/* Set up the DDC bus. */ -	intel_dp_i2c_init(intel_output, -			  (output_reg == DP_B) ? "DPDDC-B" : -			  (output_reg == DP_C) ? "DPDDC-C" : "DPDDC-D"); +	switch (output_reg) { +		case DP_A: +			name = "DPDDC-A"; +			break; +		case DP_B: +		case PCH_DP_B: +			name = "DPDDC-B"; +			break; +		case DP_C: +		case PCH_DP_C: +			name = "DPDDC-C"; +			break; +		case DP_D: +		case PCH_DP_D: +			name = "DPDDC-D"; +			break; +	} + +	intel_dp_i2c_init(intel_output, name); +  	intel_output->ddc_bus = &dp_priv->adapter;  	intel_output->hot_plug = intel_dp_hot_plug; +	if (output_reg == DP_A) { +		/* initialize panel mode from VBT if available for eDP */ +		if (dev_priv->lfp_lvds_vbt_mode) { +			dev_priv->panel_fixed_mode = +				drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); +			if (dev_priv->panel_fixed_mode) { +				dev_priv->panel_fixed_mode->type |= +					DRM_MODE_TYPE_PREFERRED; +			} +		} +	} +  	/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written  	 * 0xd.  Failure to do so will result in spurious interrupts being  	 * generated on the port when a cable is not attached. diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 004541c935a..d6f92ea1b55 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -55,6 +55,7 @@  #define INTEL_OUTPUT_TVOUT 5  #define INTEL_OUTPUT_HDMI 6  #define INTEL_OUTPUT_DISPLAYPORT 7 +#define INTEL_OUTPUT_EDP 8  #define INTEL_DVO_CHIP_NONE 0  #define INTEL_DVO_CHIP_LVDS 1 @@ -121,6 +122,8 @@ extern void intel_dp_init(struct drm_device *dev, int dp_reg);  void  intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,  		 struct drm_display_mode *adjusted_mode); +extern void intel_edp_link_config (struct intel_output *, int *, int *); +  extern void intel_crtc_load_lut(struct drm_crtc *crtc);  extern void intel_encoder_prepare (struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 9e30daae37d..1842290cded 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -130,16 +130,17 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,  }  static enum drm_connector_status -intel_hdmi_edid_detect(struct drm_connector *connector) +intel_hdmi_detect(struct drm_connector *connector)  {  	struct intel_output *intel_output = to_intel_output(connector);  	struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;  	struct edid *edid = NULL;  	enum drm_connector_status status = connector_status_disconnected; +	hdmi_priv->has_hdmi_sink = false;  	edid = drm_get_edid(&intel_output->base,  			    intel_output->ddc_bus); -	hdmi_priv->has_hdmi_sink = false; +  	if (edid) {  		if (edid->input & DRM_EDID_INPUT_DIGITAL) {  			status = connector_status_connected; @@ -148,65 +149,8 @@ intel_hdmi_edid_detect(struct drm_connector *connector)  		intel_output->base.display_info.raw_edid = NULL;  		kfree(edid);  	} -	return status; -} - -static enum drm_connector_status -igdng_hdmi_detect(struct drm_connector *connector) -{ -	struct intel_output *intel_output = to_intel_output(connector); -	struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv; - -	/* FIXME hotplug detect */ - -	hdmi_priv->has_hdmi_sink = false; -	return intel_hdmi_edid_detect(connector); -} - -static enum drm_connector_status -intel_hdmi_detect(struct drm_connector *connector) -{ -	struct drm_device *dev = connector->dev; -	struct drm_i915_private *dev_priv = dev->dev_private; -	struct intel_output *intel_output = to_intel_output(connector); -	struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv; -	u32 temp, bit; - -	if (IS_IGDNG(dev)) -		return igdng_hdmi_detect(connector); - -	temp = I915_READ(PORT_HOTPLUG_EN); - -	switch (hdmi_priv->sdvox_reg) { -	case SDVOB: -		temp |= HDMIB_HOTPLUG_INT_EN; -		break; -	case SDVOC: -		temp |= HDMIC_HOTPLUG_INT_EN; -		break; -	default: -		return connector_status_unknown; -	} - -	I915_WRITE(PORT_HOTPLUG_EN, temp); - -	POSTING_READ(PORT_HOTPLUG_EN); - -	switch (hdmi_priv->sdvox_reg) { -	case SDVOB: -		bit = HDMIB_HOTPLUG_INT_STATUS; -		break; -	case SDVOC: -		bit = HDMIC_HOTPLUG_INT_STATUS; -		break; -	default: -		return connector_status_unknown; -	} -	if ((I915_READ(PORT_HOTPLUG_STAT) & bit) != 0) -		return intel_hdmi_edid_detect(connector); -	else -		return connector_status_disconnected; +	return status;  }  static int intel_hdmi_get_modes(struct drm_connector *connector) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 5df486fbe05..b78c550ae86 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -768,6 +768,14 @@ static const struct dmi_system_id intel_no_lvds[] = {  	},  	{  		.callback = intel_no_lvds_dmi_callback, +		.ident = "AOpen Mini PC MP915", +		.matches = { +			DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"), +			DMI_MATCH(DMI_BOARD_NAME, "i915GMx-F"), +		}, +	}, +	{ +		.callback = intel_no_lvds_dmi_callback,  		.ident = "Aopen i945GTt-VFA",  		.matches = {  			DMI_MATCH(DMI_PRODUCT_VERSION, "AO00001JW"), @@ -872,6 +880,10 @@ void intel_lvds_init(struct drm_device *dev)  	if (IS_IGDNG(dev)) {  		if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)  			return; +		if (dev_priv->edp_support) { +			DRM_DEBUG("disable LVDS for eDP support\n"); +			return; +		}  		gpio = PCH_GPIOC;  	} diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index abef69c8a49..91238f0c39a 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -31,6 +31,7 @@  #include "drm.h"  #include "drm_crtc.h"  #include "intel_drv.h" +#include "drm_edid.h"  #include "i915_drm.h"  #include "i915_drv.h"  #include "intel_sdvo_regs.h" @@ -54,6 +55,12 @@ struct intel_sdvo_priv {  	/* Pixel clock limitations reported by the SDVO device, in kHz */  	int pixel_clock_min, pixel_clock_max; +	/* +	* For multiple function SDVO device, +	* this is for current attached outputs. +	*/ +	uint16_t attached_output; +  	/**  	 * This is set if we're going to treat the device as TV-out.  	 * @@ -113,6 +120,9 @@ struct intel_sdvo_priv {  	u32 save_SDVOX;  }; +static bool +intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags); +  /**   * Writes the SDVOB or SDVOC with the given value, but always writes both   * SDVOB and SDVOC to work around apparent hardware issues (according to @@ -1434,41 +1444,96 @@ void intel_sdvo_set_hotplug(struct drm_connector *connector, int on)  	intel_sdvo_read_response(intel_output, &response, 2);  } -static void -intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) +static bool +intel_sdvo_multifunc_encoder(struct intel_output *intel_output) +{ +	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; +	int caps = 0; + +	if (sdvo_priv->caps.output_flags & +		(SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) +		caps++; +	if (sdvo_priv->caps.output_flags & +		(SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1)) +		caps++; +	if (sdvo_priv->caps.output_flags & +		(SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_SVID0)) +		caps++; +	if (sdvo_priv->caps.output_flags & +		(SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_CVBS1)) +		caps++; +	if (sdvo_priv->caps.output_flags & +		(SDVO_OUTPUT_YPRPB0 | SDVO_OUTPUT_YPRPB1)) +		caps++; + +	if (sdvo_priv->caps.output_flags & +		(SDVO_OUTPUT_SCART0 | SDVO_OUTPUT_SCART1)) +		caps++; + +	if (sdvo_priv->caps.output_flags & +		(SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1)) +		caps++; + +	return (caps > 1); +} + +enum drm_connector_status +intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response)  {  	struct intel_output *intel_output = to_intel_output(connector);  	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; +	enum drm_connector_status status = connector_status_connected;  	struct edid *edid = NULL;  	edid = drm_get_edid(&intel_output->base,  			    intel_output->ddc_bus);  	if (edid != NULL) { -		sdvo_priv->is_hdmi = drm_detect_hdmi_monitor(edid); +		/* Don't report the output as connected if it's a DVI-I +		 * connector with a non-digital EDID coming out. +		 */ +		if (response & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) { +			if (edid->input & DRM_EDID_INPUT_DIGITAL) +				sdvo_priv->is_hdmi = +					drm_detect_hdmi_monitor(edid); +			else +				status = connector_status_disconnected; +		} +  		kfree(edid);  		intel_output->base.display_info.raw_edid = NULL; -	} + +	} else if (response & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) +		status = connector_status_disconnected; + +	return status;  }  static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector)  { -	u8 response[2]; +	uint16_t response;  	u8 status;  	struct intel_output *intel_output = to_intel_output(connector); +	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;  	intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);  	status = intel_sdvo_read_response(intel_output, &response, 2); -	DRM_DEBUG_KMS("SDVO response %d %d\n", response[0], response[1]); +	DRM_DEBUG_KMS("SDVO response %d %d\n", response & 0xff, response >> 8);  	if (status != SDVO_CMD_STATUS_SUCCESS)  		return connector_status_unknown; -	if ((response[0] != 0) || (response[1] != 0)) { -		intel_sdvo_hdmi_sink_detect(connector); -		return connector_status_connected; -	} else +	if (response == 0)  		return connector_status_disconnected; + +	if (intel_sdvo_multifunc_encoder(intel_output) && +		sdvo_priv->attached_output != response) { +		if (sdvo_priv->controlled_output != response && +			intel_sdvo_output_setup(intel_output, response) != true) +			return connector_status_unknown; +		sdvo_priv->attached_output = response; +	} +	return intel_sdvo_hdmi_sink_detect(connector, response);  }  static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) @@ -1865,16 +1930,100 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int output_device)  		return 0x72;  } +static bool +intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags) +{ +	struct drm_connector *connector = &intel_output->base; +	struct drm_encoder *encoder = &intel_output->enc; +	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; +	bool ret = true, registered = false; + +	sdvo_priv->is_tv = false; +	intel_output->needs_tv_clock = false; +	sdvo_priv->is_lvds = false; + +	if (device_is_registered(&connector->kdev)) { +		drm_sysfs_connector_remove(connector); +		registered = true; +	} + +	if (flags & +	    (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) { +		if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) +			sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS0; +		else +			sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS1; + +		encoder->encoder_type = DRM_MODE_ENCODER_TMDS; +		connector->connector_type = DRM_MODE_CONNECTOR_DVID; + +		if (intel_sdvo_get_supp_encode(intel_output, +					       &sdvo_priv->encode) && +		    intel_sdvo_get_digital_encoding_mode(intel_output) && +		    sdvo_priv->is_hdmi) { +			/* enable hdmi encoding mode if supported */ +			intel_sdvo_set_encode(intel_output, SDVO_ENCODE_HDMI); +			intel_sdvo_set_colorimetry(intel_output, +						   SDVO_COLORIMETRY_RGB256); +			connector->connector_type = DRM_MODE_CONNECTOR_HDMIA; +		} +	} else if (flags & SDVO_OUTPUT_SVID0) { + +		sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0; +		encoder->encoder_type = DRM_MODE_ENCODER_TVDAC; +		connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO; +		sdvo_priv->is_tv = true; +		intel_output->needs_tv_clock = true; +	} else if (flags & SDVO_OUTPUT_RGB0) { + +		sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0; +		encoder->encoder_type = DRM_MODE_ENCODER_DAC; +		connector->connector_type = DRM_MODE_CONNECTOR_VGA; +	} else if (flags & SDVO_OUTPUT_RGB1) { + +		sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1; +		encoder->encoder_type = DRM_MODE_ENCODER_DAC; +		connector->connector_type = DRM_MODE_CONNECTOR_VGA; +	} else if (flags & SDVO_OUTPUT_LVDS0) { + +		sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0; +		encoder->encoder_type = DRM_MODE_ENCODER_LVDS; +		connector->connector_type = DRM_MODE_CONNECTOR_LVDS; +		sdvo_priv->is_lvds = true; +	} else if (flags & SDVO_OUTPUT_LVDS1) { + +		sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1; +		encoder->encoder_type = DRM_MODE_ENCODER_LVDS; +		connector->connector_type = DRM_MODE_CONNECTOR_LVDS; +		sdvo_priv->is_lvds = true; +	} else { + +		unsigned char bytes[2]; + +		sdvo_priv->controlled_output = 0; +		memcpy(bytes, &sdvo_priv->caps.output_flags, 2); +		DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%02x%02x)\n", +			      SDVO_NAME(sdvo_priv), +			      bytes[0], bytes[1]); +		ret = false; +	} + +	if (ret && registered) +		ret = drm_sysfs_connector_add(connector) == 0 ? true : false; + + +	return ret; + +} +  bool intel_sdvo_init(struct drm_device *dev, int output_device)  {  	struct drm_connector *connector;  	struct intel_output *intel_output;  	struct intel_sdvo_priv *sdvo_priv; -	int connector_type;  	u8 ch[0x40];  	int i; -	int encoder_type;  	intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL);  	if (!intel_output) { @@ -1923,87 +2072,28 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)  	intel_output->ddc_bus->algo = &intel_sdvo_i2c_bit_algo;  	/* In defaut case sdvo lvds is false */ -	sdvo_priv->is_lvds = false;  	intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps); -	if (sdvo_priv->caps.output_flags & -	    (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) { -		if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) -			sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS0; -		else -			sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS1; - -		encoder_type = DRM_MODE_ENCODER_TMDS; -		connector_type = DRM_MODE_CONNECTOR_DVID; - -		if (intel_sdvo_get_supp_encode(intel_output, -					       &sdvo_priv->encode) && -		    intel_sdvo_get_digital_encoding_mode(intel_output) && -		    sdvo_priv->is_hdmi) { -			/* enable hdmi encoding mode if supported */ -			intel_sdvo_set_encode(intel_output, SDVO_ENCODE_HDMI); -			intel_sdvo_set_colorimetry(intel_output, -						   SDVO_COLORIMETRY_RGB256); -			connector_type = DRM_MODE_CONNECTOR_HDMIA; -		} -	} -	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_SVID0) -	{ -		sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0; -		encoder_type = DRM_MODE_ENCODER_TVDAC; -		connector_type = DRM_MODE_CONNECTOR_SVIDEO; -		sdvo_priv->is_tv = true; -		intel_output->needs_tv_clock = true; -	} -	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0) -	{ -		sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0; -		encoder_type = DRM_MODE_ENCODER_DAC; -		connector_type = DRM_MODE_CONNECTOR_VGA; -	} -	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1) -	{ -		sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1; -		encoder_type = DRM_MODE_ENCODER_DAC; -		connector_type = DRM_MODE_CONNECTOR_VGA; -	} -	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS0) -	{ -		sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0; -		encoder_type = DRM_MODE_ENCODER_LVDS; -		connector_type = DRM_MODE_CONNECTOR_LVDS; -		sdvo_priv->is_lvds = true; -	} -	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS1) -	{ -		sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1; -		encoder_type = DRM_MODE_ENCODER_LVDS; -		connector_type = DRM_MODE_CONNECTOR_LVDS; -		sdvo_priv->is_lvds = true; -	} -	else -	{ -		unsigned char bytes[2]; - -		sdvo_priv->controlled_output = 0; -		memcpy (bytes, &sdvo_priv->caps.output_flags, 2); -		DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%02x%02x)\n", -				  SDVO_NAME(sdvo_priv), -				  bytes[0], bytes[1]); -		encoder_type = DRM_MODE_ENCODER_NONE; -		connector_type = DRM_MODE_CONNECTOR_Unknown; +	if (intel_sdvo_output_setup(intel_output, +				    sdvo_priv->caps.output_flags) != true) { +		DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n", +			  output_device == SDVOB ? 'B' : 'C');  		goto err_i2c;  	} +  	connector = &intel_output->base;  	drm_connector_init(dev, connector, &intel_sdvo_connector_funcs, -			   connector_type); +			   connector->connector_type); +  	drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs);  	connector->interlace_allowed = 0;  	connector->doublescan_allowed = 0;  	connector->display_info.subpixel_order = SubPixelHorizontalRGB; -	drm_encoder_init(dev, &intel_output->enc, &intel_sdvo_enc_funcs, encoder_type); +	drm_encoder_init(dev, &intel_output->enc, +			&intel_sdvo_enc_funcs, intel_output->enc.encoder_type); +  	drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs);  	drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index a43c98e3f07..da4ab4dc163 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1490,6 +1490,27 @@ static struct input_res {  	{"1920x1080", 1920, 1080},  }; +/* + * Chose preferred mode  according to line number of TV format + */ +static void +intel_tv_chose_preferred_modes(struct drm_connector *connector, +			       struct drm_display_mode *mode_ptr) +{ +	struct intel_output *intel_output = to_intel_output(connector); +	const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output); + +	if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480) +		mode_ptr->type |= DRM_MODE_TYPE_PREFERRED; +	else if (tv_mode->nbr_end > 480) { +		if (tv_mode->progressive == true && tv_mode->nbr_end < 720) { +			if (mode_ptr->vdisplay == 720) +				mode_ptr->type |= DRM_MODE_TYPE_PREFERRED; +		} else if (mode_ptr->vdisplay == 1080) +				mode_ptr->type |= DRM_MODE_TYPE_PREFERRED; +	} +} +  /**   * Stub get_modes function.   * @@ -1544,6 +1565,7 @@ intel_tv_get_modes(struct drm_connector *connector)  		mode_ptr->clock = (int) tmp;  		mode_ptr->type = DRM_MODE_TYPE_DRIVER; +		intel_tv_chose_preferred_modes(connector, mode_ptr);  		drm_mode_probed_add(connector, mode_ptr);  		count++;  	} diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index 5fae1e074b4..013d3805994 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -13,7 +13,8 @@ radeon-$(CONFIG_DRM_RADEON_KMS) += radeon_device.o radeon_kms.o \  	radeon_encoders.o radeon_display.o radeon_cursor.o radeon_i2c.o \  	radeon_clocks.o radeon_fb.o radeon_gem.o radeon_ring.o radeon_irq_kms.o \  	radeon_cs.o radeon_bios.o radeon_benchmark.o r100.o r300.o r420.o \ -	rs400.o rs600.o rs690.o rv515.o r520.o r600.o rs780.o rv770.o +	rs400.o rs600.o rs690.o rv515.o r520.o r600.o rs780.o rv770.o \ +	radeon_test.o  radeon-$(CONFIG_COMPAT) += radeon_ioc32.o diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index c0080cc9bf8..74d034f77c6 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -31,6 +31,132 @@  #include "atom.h"  #include "atom-bits.h" +static void atombios_overscan_setup(struct drm_crtc *crtc, +				    struct drm_display_mode *mode, +				    struct drm_display_mode *adjusted_mode) +{ +	struct drm_device *dev = crtc->dev; +	struct radeon_device *rdev = dev->dev_private; +	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); +	SET_CRTC_OVERSCAN_PS_ALLOCATION args; +	int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan); +	int a1, a2; + +	memset(&args, 0, sizeof(args)); + +	args.usOverscanRight = 0; +	args.usOverscanLeft = 0; +	args.usOverscanBottom = 0; +	args.usOverscanTop = 0; +	args.ucCRTC = radeon_crtc->crtc_id; + +	switch (radeon_crtc->rmx_type) { +	case RMX_CENTER: +		args.usOverscanTop = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2; +		args.usOverscanBottom = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2; +		args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2; +		args.usOverscanRight = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2; +		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +		break; +	case RMX_ASPECT: +		a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay; +		a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay; + +		if (a1 > a2) { +			args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2; +			args.usOverscanRight = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2; +		} else if (a2 > a1) { +			args.usOverscanLeft = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2; +			args.usOverscanRight = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2; +		} +		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +		break; +	case RMX_FULL: +	default: +		args.usOverscanRight = 0; +		args.usOverscanLeft = 0; +		args.usOverscanBottom = 0; +		args.usOverscanTop = 0; +		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +		break; +	} +} + +static void atombios_scaler_setup(struct drm_crtc *crtc) +{ +	struct drm_device *dev = crtc->dev; +	struct radeon_device *rdev = dev->dev_private; +	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); +	ENABLE_SCALER_PS_ALLOCATION args; +	int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); +	/* fixme - fill in enc_priv for atom dac */ +	enum radeon_tv_std tv_std = TV_STD_NTSC; + +	if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id) +		return; + +	memset(&args, 0, sizeof(args)); + +	args.ucScaler = radeon_crtc->crtc_id; + +	if (radeon_crtc->devices & (ATOM_DEVICE_TV_SUPPORT)) { +		switch (tv_std) { +		case TV_STD_NTSC: +		default: +			args.ucTVStandard = ATOM_TV_NTSC; +			break; +		case TV_STD_PAL: +			args.ucTVStandard = ATOM_TV_PAL; +			break; +		case TV_STD_PAL_M: +			args.ucTVStandard = ATOM_TV_PALM; +			break; +		case TV_STD_PAL_60: +			args.ucTVStandard = ATOM_TV_PAL60; +			break; +		case TV_STD_NTSC_J: +			args.ucTVStandard = ATOM_TV_NTSCJ; +			break; +		case TV_STD_SCART_PAL: +			args.ucTVStandard = ATOM_TV_PAL; /* ??? */ +			break; +		case TV_STD_SECAM: +			args.ucTVStandard = ATOM_TV_SECAM; +			break; +		case TV_STD_PAL_CN: +			args.ucTVStandard = ATOM_TV_PALCN; +			break; +		} +		args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; +	} else if (radeon_crtc->devices & (ATOM_DEVICE_CV_SUPPORT)) { +		args.ucTVStandard = ATOM_TV_CV; +		args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; +	} else { +		switch (radeon_crtc->rmx_type) { +		case RMX_FULL: +			args.ucEnable = ATOM_SCALER_EXPANSION; +			break; +		case RMX_CENTER: +			args.ucEnable = ATOM_SCALER_CENTER; +			break; +		case RMX_ASPECT: +			args.ucEnable = ATOM_SCALER_EXPANSION; +			break; +		default: +			if (ASIC_IS_AVIVO(rdev)) +				args.ucEnable = ATOM_SCALER_DISABLE; +			else +				args.ucEnable = ATOM_SCALER_CENTER; +			break; +		} +	} +	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +	if (radeon_crtc->devices & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT) +	    && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_RV570) { +		atom_rv515_force_tv_scaler(rdev); +	} +} +  static void atombios_lock_crtc(struct drm_crtc *crtc, int lock)  {  	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); @@ -203,6 +329,12 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)  	if (ASIC_IS_AVIVO(rdev)) {  		uint32_t ss_cntl; +		if ((rdev->family == CHIP_RS600) || +		    (rdev->family == CHIP_RS690) || +		    (rdev->family == CHIP_RS740)) +			pll_flags |= (RADEON_PLL_USE_FRAC_FB_DIV | +				      RADEON_PLL_PREFER_CLOSEST_LOWER); +  		if (ASIC_IS_DCE32(rdev) && mode->clock > 200000)	/* range limits??? */  			pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;  		else @@ -321,7 +453,7 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,  	struct drm_gem_object *obj;  	struct drm_radeon_gem_object *obj_priv;  	uint64_t fb_location; -	uint32_t fb_format, fb_pitch_pixels; +	uint32_t fb_format, fb_pitch_pixels, tiling_flags;  	if (!crtc->fb)  		return -EINVAL; @@ -358,7 +490,14 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,  		return -EINVAL;  	} -	/* TODO tiling */ +	radeon_object_get_tiling_flags(obj->driver_private, +				       &tiling_flags, NULL); +	if (tiling_flags & RADEON_TILING_MACRO) +		fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE; + +	if (tiling_flags & RADEON_TILING_MICRO) +		fb_format |= AVIVO_D1GRPH_TILED; +  	if (radeon_crtc->crtc_id == 0)  		WREG32(AVIVO_D1VGA_CONTROL, 0);  	else @@ -509,6 +648,9 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc,  		radeon_crtc_set_base(crtc, x, y, old_fb);  		radeon_legacy_atom_set_surface(crtc);  	} +	atombios_overscan_setup(crtc, mode, adjusted_mode); +	atombios_scaler_setup(crtc); +	radeon_bandwidth_update(rdev);  	return 0;  } @@ -516,6 +658,8 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,  				     struct drm_display_mode *mode,  				     struct drm_display_mode *adjusted_mode)  { +	if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) +		return false;  	return true;  } @@ -548,148 +692,3 @@ void radeon_atombios_init_crtc(struct drm_device *dev,  		    AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL;  	drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs);  } - -void radeon_init_disp_bw_avivo(struct drm_device *dev, -			       struct drm_display_mode *mode1, -			       uint32_t pixel_bytes1, -			       struct drm_display_mode *mode2, -			       uint32_t pixel_bytes2) -{ -	struct radeon_device *rdev = dev->dev_private; -	fixed20_12 min_mem_eff; -	fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff; -	fixed20_12 sclk_ff, mclk_ff; -	uint32_t dc_lb_memory_split, temp; - -	min_mem_eff.full = rfixed_const_8(0); -	if (rdev->disp_priority == 2) { -		uint32_t mc_init_misc_lat_timer = 0; -		if (rdev->family == CHIP_RV515) -			mc_init_misc_lat_timer = -			    RREG32_MC(RV515_MC_INIT_MISC_LAT_TIMER); -		else if (rdev->family == CHIP_RS690) -			mc_init_misc_lat_timer = -			    RREG32_MC(RS690_MC_INIT_MISC_LAT_TIMER); - -		mc_init_misc_lat_timer &= -		    ~(R300_MC_DISP1R_INIT_LAT_MASK << -		      R300_MC_DISP1R_INIT_LAT_SHIFT); -		mc_init_misc_lat_timer &= -		    ~(R300_MC_DISP0R_INIT_LAT_MASK << -		      R300_MC_DISP0R_INIT_LAT_SHIFT); - -		if (mode2) -			mc_init_misc_lat_timer |= -			    (1 << R300_MC_DISP1R_INIT_LAT_SHIFT); -		if (mode1) -			mc_init_misc_lat_timer |= -			    (1 << R300_MC_DISP0R_INIT_LAT_SHIFT); - -		if (rdev->family == CHIP_RV515) -			WREG32_MC(RV515_MC_INIT_MISC_LAT_TIMER, -				  mc_init_misc_lat_timer); -		else if (rdev->family == CHIP_RS690) -			WREG32_MC(RS690_MC_INIT_MISC_LAT_TIMER, -				  mc_init_misc_lat_timer); -	} - -	/* -	 * determine is there is enough bw for current mode -	 */ -	temp_ff.full = rfixed_const(100); -	mclk_ff.full = rfixed_const(rdev->clock.default_mclk); -	mclk_ff.full = rfixed_div(mclk_ff, temp_ff); -	sclk_ff.full = rfixed_const(rdev->clock.default_sclk); -	sclk_ff.full = rfixed_div(sclk_ff, temp_ff); - -	temp = (rdev->mc.vram_width / 8) * (rdev->mc.vram_is_ddr ? 2 : 1); -	temp_ff.full = rfixed_const(temp); -	mem_bw.full = rfixed_mul(mclk_ff, temp_ff); -	mem_bw.full = rfixed_mul(mem_bw, min_mem_eff); - -	pix_clk.full = 0; -	pix_clk2.full = 0; -	peak_disp_bw.full = 0; -	if (mode1) { -		temp_ff.full = rfixed_const(1000); -		pix_clk.full = rfixed_const(mode1->clock);	/* convert to fixed point */ -		pix_clk.full = rfixed_div(pix_clk, temp_ff); -		temp_ff.full = rfixed_const(pixel_bytes1); -		peak_disp_bw.full += rfixed_mul(pix_clk, temp_ff); -	} -	if (mode2) { -		temp_ff.full = rfixed_const(1000); -		pix_clk2.full = rfixed_const(mode2->clock);	/* convert to fixed point */ -		pix_clk2.full = rfixed_div(pix_clk2, temp_ff); -		temp_ff.full = rfixed_const(pixel_bytes2); -		peak_disp_bw.full += rfixed_mul(pix_clk2, temp_ff); -	} - -	if (peak_disp_bw.full >= mem_bw.full) { -		DRM_ERROR -		    ("You may not have enough display bandwidth for current mode\n" -		     "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n"); -		printk("peak disp bw %d, mem_bw %d\n", -		       rfixed_trunc(peak_disp_bw), rfixed_trunc(mem_bw)); -	} - -	/* -	 * Line Buffer Setup -	 * There is a single line buffer shared by both display controllers. -	 * DC_LB_MEMORY_SPLIT controls how that line buffer is shared between the display -	 * controllers.  The paritioning can either be done manually or via one of four -	 * preset allocations specified in bits 1:0: -	 * 0 - line buffer is divided in half and shared between each display controller -	 * 1 - D1 gets 3/4 of the line buffer, D2 gets 1/4 -	 * 2 - D1 gets the whole buffer -	 * 3 - D1 gets 1/4 of the line buffer, D2 gets 3/4 -	 * Setting bit 2 of DC_LB_MEMORY_SPLIT controls switches to manual allocation mode. -	 * In manual allocation mode, D1 always starts at 0, D1 end/2 is specified in bits -	 * 14:4; D2 allocation follows D1. -	 */ - -	/* is auto or manual better ? */ -	dc_lb_memory_split = -	    RREG32(AVIVO_DC_LB_MEMORY_SPLIT) & ~AVIVO_DC_LB_MEMORY_SPLIT_MASK; -	dc_lb_memory_split &= ~AVIVO_DC_LB_MEMORY_SPLIT_SHIFT_MODE; -#if 1 -	/* auto */ -	if (mode1 && mode2) { -		if (mode1->hdisplay > mode2->hdisplay) { -			if (mode1->hdisplay > 2560) -				dc_lb_memory_split |= -				    AVIVO_DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q; -			else -				dc_lb_memory_split |= -				    AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; -		} else if (mode2->hdisplay > mode1->hdisplay) { -			if (mode2->hdisplay > 2560) -				dc_lb_memory_split |= -				    AVIVO_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q; -			else -				dc_lb_memory_split |= -				    AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; -		} else -			dc_lb_memory_split |= -			    AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; -	} else if (mode1) { -		dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1_ONLY; -	} else if (mode2) { -		dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q; -	} -#else -	/* manual */ -	dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_SHIFT_MODE; -	dc_lb_memory_split &= -	    ~(AVIVO_DC_LB_DISP1_END_ADR_MASK << -	      AVIVO_DC_LB_DISP1_END_ADR_SHIFT); -	if (mode1) { -		dc_lb_memory_split |= -		    ((((mode1->hdisplay / 2) + 64) & AVIVO_DC_LB_DISP1_END_ADR_MASK) -		     << AVIVO_DC_LB_DISP1_END_ADR_SHIFT); -	} else if (mode2) { -		dc_lb_memory_split |= (0 << AVIVO_DC_LB_DISP1_END_ADR_SHIFT); -	} -#endif -	WREG32(AVIVO_DC_LB_MEMORY_SPLIT, dc_lb_memory_split); -} diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index c550932a108..90ff8e0ac04 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -110,7 +110,7 @@ int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)  	if (i < 0 || i > rdev->gart.num_gpu_pages) {  		return -EINVAL;  	} -	rdev->gart.table.ram.ptr[i] = cpu_to_le32((uint32_t)addr); +	rdev->gart.table.ram.ptr[i] = cpu_to_le32(lower_32_bits(addr));  	return 0;  } @@ -173,8 +173,12 @@ void r100_mc_setup(struct radeon_device *rdev)  		DRM_ERROR("Failed to register debugfs file for R100 MC !\n");  	}  	/* Write VRAM size in case we are limiting it */ -	WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size); -	tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1; +	WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.real_vram_size); +	/* Novell bug 204882 for RN50/M6/M7 with 8/16/32MB VRAM, +	 * if the aperture is 64MB but we have 32MB VRAM +	 * we report only 32MB VRAM but we have to set MC_FB_LOCATION +	 * to 64MB, otherwise the gpu accidentially dies */ +	tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;  	tmp = REG_SET(RADEON_MC_FB_TOP, tmp >> 16);  	tmp |= REG_SET(RADEON_MC_FB_START, rdev->mc.vram_location >> 16);  	WREG32(RADEON_MC_FB_LOCATION, tmp); @@ -215,7 +219,6 @@ int r100_mc_init(struct radeon_device *rdev)  	r100_pci_gart_disable(rdev);  	/* Setup GPU memory space */ -	rdev->mc.vram_location = 0xFFFFFFFFUL;  	rdev->mc.gtt_location = 0xFFFFFFFFUL;  	if (rdev->flags & RADEON_IS_AGP) {  		r = radeon_agp_init(rdev); @@ -251,6 +254,72 @@ void r100_mc_fini(struct radeon_device *rdev)  /* + * Interrupts + */ +int r100_irq_set(struct radeon_device *rdev) +{ +	uint32_t tmp = 0; + +	if (rdev->irq.sw_int) { +		tmp |= RADEON_SW_INT_ENABLE; +	} +	if (rdev->irq.crtc_vblank_int[0]) { +		tmp |= RADEON_CRTC_VBLANK_MASK; +	} +	if (rdev->irq.crtc_vblank_int[1]) { +		tmp |= RADEON_CRTC2_VBLANK_MASK; +	} +	WREG32(RADEON_GEN_INT_CNTL, tmp); +	return 0; +} + +static inline uint32_t r100_irq_ack(struct radeon_device *rdev) +{ +	uint32_t irqs = RREG32(RADEON_GEN_INT_STATUS); +	uint32_t irq_mask = RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT | +		RADEON_CRTC2_VBLANK_STAT; + +	if (irqs) { +		WREG32(RADEON_GEN_INT_STATUS, irqs); +	} +	return irqs & irq_mask; +} + +int r100_irq_process(struct radeon_device *rdev) +{ +	uint32_t status; + +	status = r100_irq_ack(rdev); +	if (!status) { +		return IRQ_NONE; +	} +	while (status) { +		/* SW interrupt */ +		if (status & RADEON_SW_INT_TEST) { +			radeon_fence_process(rdev); +		} +		/* Vertical blank interrupts */ +		if (status & RADEON_CRTC_VBLANK_STAT) { +			drm_handle_vblank(rdev->ddev, 0); +		} +		if (status & RADEON_CRTC2_VBLANK_STAT) { +			drm_handle_vblank(rdev->ddev, 1); +		} +		status = r100_irq_ack(rdev); +	} +	return IRQ_HANDLED; +} + +u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc) +{ +	if (crtc == 0) +		return RREG32(RADEON_CRTC_CRNT_FRAME); +	else +		return RREG32(RADEON_CRTC2_CRNT_FRAME); +} + + +/*   * Fence emission   */  void r100_fence_ring_emit(struct radeon_device *rdev, @@ -719,13 +788,14 @@ int r100_cs_packet_parse(struct radeon_cs_parser *p,  			 unsigned idx)  {  	struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx]; -	uint32_t header = ib_chunk->kdata[idx]; +	uint32_t header;  	if (idx >= ib_chunk->length_dw) {  		DRM_ERROR("Can not parse packet at %d after CS end %d !\n",  			  idx, ib_chunk->length_dw);  		return -EINVAL;  	} +	header = ib_chunk->kdata[idx];  	pkt->idx = idx;  	pkt->type = CP_PACKET_GET_TYPE(header);  	pkt->count = CP_PACKET_GET_COUNT(header); @@ -753,6 +823,102 @@ int r100_cs_packet_parse(struct radeon_cs_parser *p,  }  /** + * r100_cs_packet_next_vline() - parse userspace VLINE packet + * @parser:		parser structure holding parsing context. + * + * Userspace sends a special sequence for VLINE waits. + * PACKET0 - VLINE_START_END + value + * PACKET0 - WAIT_UNTIL +_value + * RELOC (P3) - crtc_id in reloc. + * + * This function parses this and relocates the VLINE START END + * and WAIT UNTIL packets to the correct crtc. + * It also detects a switched off crtc and nulls out the + * wait in that case. + */ +int r100_cs_packet_parse_vline(struct radeon_cs_parser *p) +{ +	struct radeon_cs_chunk *ib_chunk; +	struct drm_mode_object *obj; +	struct drm_crtc *crtc; +	struct radeon_crtc *radeon_crtc; +	struct radeon_cs_packet p3reloc, waitreloc; +	int crtc_id; +	int r; +	uint32_t header, h_idx, reg; + +	ib_chunk = &p->chunks[p->chunk_ib_idx]; + +	/* parse the wait until */ +	r = r100_cs_packet_parse(p, &waitreloc, p->idx); +	if (r) +		return r; + +	/* check its a wait until and only 1 count */ +	if (waitreloc.reg != RADEON_WAIT_UNTIL || +	    waitreloc.count != 0) { +		DRM_ERROR("vline wait had illegal wait until segment\n"); +		r = -EINVAL; +		return r; +	} + +	if (ib_chunk->kdata[waitreloc.idx + 1] != RADEON_WAIT_CRTC_VLINE) { +		DRM_ERROR("vline wait had illegal wait until\n"); +		r = -EINVAL; +		return r; +	} + +	/* jump over the NOP */ +	r = r100_cs_packet_parse(p, &p3reloc, p->idx); +	if (r) +		return r; + +	h_idx = p->idx - 2; +	p->idx += waitreloc.count; +	p->idx += p3reloc.count; + +	header = ib_chunk->kdata[h_idx]; +	crtc_id = ib_chunk->kdata[h_idx + 5]; +	reg = ib_chunk->kdata[h_idx] >> 2; +	mutex_lock(&p->rdev->ddev->mode_config.mutex); +	obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC); +	if (!obj) { +		DRM_ERROR("cannot find crtc %d\n", crtc_id); +		r = -EINVAL; +		goto out; +	} +	crtc = obj_to_crtc(obj); +	radeon_crtc = to_radeon_crtc(crtc); +	crtc_id = radeon_crtc->crtc_id; + +	if (!crtc->enabled) { +		/* if the CRTC isn't enabled - we need to nop out the wait until */ +		ib_chunk->kdata[h_idx + 2] = PACKET2(0); +		ib_chunk->kdata[h_idx + 3] = PACKET2(0); +	} else if (crtc_id == 1) { +		switch (reg) { +		case AVIVO_D1MODE_VLINE_START_END: +			header &= R300_CP_PACKET0_REG_MASK; +			header |= AVIVO_D2MODE_VLINE_START_END >> 2; +			break; +		case RADEON_CRTC_GUI_TRIG_VLINE: +			header &= R300_CP_PACKET0_REG_MASK; +			header |= RADEON_CRTC2_GUI_TRIG_VLINE >> 2; +			break; +		default: +			DRM_ERROR("unknown crtc reloc\n"); +			r = -EINVAL; +			goto out; +		} +		ib_chunk->kdata[h_idx] = header; +		ib_chunk->kdata[h_idx + 3] |= RADEON_ENG_DISPLAY_SELECT_CRTC1; +	} +out: +	mutex_unlock(&p->rdev->ddev->mode_config.mutex); +	return r; +} + +/**   * r100_cs_packet_next_reloc() - parse next packet which should be reloc packet3   * @parser:		parser structure holding parsing context.   * @data:		pointer to relocation data @@ -814,6 +980,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,  	unsigned idx;  	bool onereg;  	int r; +	u32 tile_flags = 0;  	ib = p->ib->ptr;  	ib_chunk = &p->chunks[p->chunk_ib_idx]; @@ -825,6 +992,15 @@ static int r100_packet0_check(struct radeon_cs_parser *p,  	}  	for (i = 0; i <= pkt->count; i++, idx++, reg += 4) {  		switch (reg) { +		case RADEON_CRTC_GUI_TRIG_VLINE: +			r = r100_cs_packet_parse_vline(p); +			if (r) { +				DRM_ERROR("No reloc for ib[%d]=0x%04X\n", +						idx, reg); +				r100_cs_dump_packet(p, pkt); +				return r; +			} +			break;  		/* FIXME: only allow PACKET3 blit? easier to check for out of  		 * range access */  		case RADEON_DST_PITCH_OFFSET: @@ -838,7 +1014,20 @@ static int r100_packet0_check(struct radeon_cs_parser *p,  			}  			tmp = ib_chunk->kdata[idx] & 0x003fffff;  			tmp += (((u32)reloc->lobj.gpu_offset) >> 10); -			ib[idx] = (ib_chunk->kdata[idx] & 0xffc00000) | tmp; + +			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) +				tile_flags |= RADEON_DST_TILE_MACRO; +			if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) { +				if (reg == RADEON_SRC_PITCH_OFFSET) { +					DRM_ERROR("Cannot src blit from microtiled surface\n"); +					r100_cs_dump_packet(p, pkt); +					return -EINVAL; +				} +				tile_flags |= RADEON_DST_TILE_MICRO; +			} + +			tmp |= tile_flags; +			ib[idx] = (ib_chunk->kdata[idx] & 0x3fc00000) | tmp;  			break;  		case RADEON_RB3D_DEPTHOFFSET:  		case RADEON_RB3D_COLOROFFSET: @@ -869,6 +1058,11 @@ static int r100_packet0_check(struct radeon_cs_parser *p,  		case R300_TX_OFFSET_0+52:  		case R300_TX_OFFSET_0+56:  		case R300_TX_OFFSET_0+60: +			/* rn50 has no 3D engine so fail on any 3d setup */ +			if (ASIC_IS_RN50(p->rdev)) { +				DRM_ERROR("attempt to use RN50 3D engine failed\n"); +				return -EINVAL; +			}  			r = r100_cs_packet_next_reloc(p, &reloc);  			if (r) {  				DRM_ERROR("No reloc for ib[%d]=0x%04X\n", @@ -878,6 +1072,25 @@ static int r100_packet0_check(struct radeon_cs_parser *p,  			}  			ib[idx] = ib_chunk->kdata[idx] + ((u32)reloc->lobj.gpu_offset);  			break; +		case R300_RB3D_COLORPITCH0: +		case RADEON_RB3D_COLORPITCH: +			r = r100_cs_packet_next_reloc(p, &reloc); +			if (r) { +				DRM_ERROR("No reloc for ib[%d]=0x%04X\n", +					  idx, reg); +				r100_cs_dump_packet(p, pkt); +				return r; +			} + +			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) +				tile_flags |= RADEON_COLOR_TILE_ENABLE; +			if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) +				tile_flags |= RADEON_COLOR_MICROTILE_ENABLE; + +			tmp = ib_chunk->kdata[idx] & ~(0x7 << 16); +			tmp |= tile_flags; +			ib[idx] = tmp; +			break;  		default:  			/* FIXME: we don't want to allow anyothers packet */  			break; @@ -1256,29 +1469,100 @@ static void r100_vram_get_type(struct radeon_device *rdev)  	}  } -void r100_vram_info(struct radeon_device *rdev) +static u32 r100_get_accessible_vram(struct radeon_device *rdev)  { -	r100_vram_get_type(rdev); +	u32 aper_size; +	u8 byte; + +	aper_size = RREG32(RADEON_CONFIG_APER_SIZE); + +	/* Set HDP_APER_CNTL only on cards that are known not to be broken, +	 * that is has the 2nd generation multifunction PCI interface +	 */ +	if (rdev->family == CHIP_RV280 || +	    rdev->family >= CHIP_RV350) { +		WREG32_P(RADEON_HOST_PATH_CNTL, RADEON_HDP_APER_CNTL, +		       ~RADEON_HDP_APER_CNTL); +		DRM_INFO("Generation 2 PCI interface, using max accessible memory\n"); +		return aper_size * 2; +	} + +	/* Older cards have all sorts of funny issues to deal with. First +	 * check if it's a multifunction card by reading the PCI config +	 * header type... Limit those to one aperture size +	 */ +	pci_read_config_byte(rdev->pdev, 0xe, &byte); +	if (byte & 0x80) { +		DRM_INFO("Generation 1 PCI interface in multifunction mode\n"); +		DRM_INFO("Limiting VRAM to one aperture\n"); +		return aper_size; +	} + +	/* Single function older card. We read HDP_APER_CNTL to see how the BIOS +	 * have set it up. We don't write this as it's broken on some ASICs but +	 * we expect the BIOS to have done the right thing (might be too optimistic...) +	 */ +	if (RREG32(RADEON_HOST_PATH_CNTL) & RADEON_HDP_APER_CNTL) +		return aper_size * 2; +	return aper_size; +} + +void r100_vram_init_sizes(struct radeon_device *rdev) +{ +	u64 config_aper_size; +	u32 accessible; + +	config_aper_size = RREG32(RADEON_CONFIG_APER_SIZE);  	if (rdev->flags & RADEON_IS_IGP) {  		uint32_t tom;  		/* read NB_TOM to get the amount of ram stolen for the GPU */  		tom = RREG32(RADEON_NB_TOM); -		rdev->mc.vram_size = (((tom >> 16) - (tom & 0xffff) + 1) << 16); -		WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size); +		rdev->mc.real_vram_size = (((tom >> 16) - (tom & 0xffff) + 1) << 16); +		/* for IGPs we need to keep VRAM where it was put by the BIOS */ +		rdev->mc.vram_location = (tom & 0xffff) << 16; +		WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.real_vram_size); +		rdev->mc.mc_vram_size = rdev->mc.real_vram_size;  	} else { -		rdev->mc.vram_size = RREG32(RADEON_CONFIG_MEMSIZE); +		rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE);  		/* Some production boards of m6 will report 0  		 * if it's 8 MB  		 */ -		if (rdev->mc.vram_size == 0) { -			rdev->mc.vram_size = 8192 * 1024; -			WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size); +		if (rdev->mc.real_vram_size == 0) { +			rdev->mc.real_vram_size = 8192 * 1024; +			WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.real_vram_size);  		} +		/* let driver place VRAM */ +		rdev->mc.vram_location = 0xFFFFFFFFUL; +		 /* Fix for RN50, M6, M7 with 8/16/32(??) MBs of VRAM -  +		  * Novell bug 204882 + along with lots of ubuntu ones */ +		if (config_aper_size > rdev->mc.real_vram_size) +			rdev->mc.mc_vram_size = config_aper_size; +		else +			rdev->mc.mc_vram_size = rdev->mc.real_vram_size;  	} +	/* work out accessible VRAM */ +	accessible = r100_get_accessible_vram(rdev); +  	rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);  	rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); + +	if (accessible > rdev->mc.aper_size) +		accessible = rdev->mc.aper_size; + +	if (rdev->mc.mc_vram_size > rdev->mc.aper_size) +		rdev->mc.mc_vram_size = rdev->mc.aper_size; + +	if (rdev->mc.real_vram_size > rdev->mc.aper_size) +		rdev->mc.real_vram_size = rdev->mc.aper_size; +} + +void r100_vram_info(struct radeon_device *rdev) +{ +	r100_vram_get_type(rdev); + +	r100_vram_init_sizes(rdev);  } @@ -1338,26 +1622,6 @@ void r100_pll_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)  	r100_pll_errata_after_data(rdev);  } -uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg) -{ -	if (reg < 0x10000) -		return readl(((void __iomem *)rdev->rmmio) + reg); -	else { -		writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); -		return readl(((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); -	} -} - -void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) -{ -	if (reg < 0x10000) -		writel(v, ((void __iomem *)rdev->rmmio) + reg); -	else { -		writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); -		writel(v, ((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); -	} -} -  int r100_init(struct radeon_device *rdev)  {  	return 0; @@ -1533,3 +1797,530 @@ int r100_debugfs_mc_info_init(struct radeon_device *rdev)  	return 0;  #endif  } + +int r100_set_surface_reg(struct radeon_device *rdev, int reg, +			 uint32_t tiling_flags, uint32_t pitch, +			 uint32_t offset, uint32_t obj_size) +{ +	int surf_index = reg * 16; +	int flags = 0; + +	/* r100/r200 divide by 16 */ +	if (rdev->family < CHIP_R300) +		flags = pitch / 16; +	else +		flags = pitch / 8; + +	if (rdev->family <= CHIP_RS200) { +		if ((tiling_flags & (RADEON_TILING_MACRO|RADEON_TILING_MICRO)) +				 == (RADEON_TILING_MACRO|RADEON_TILING_MICRO)) +			flags |= RADEON_SURF_TILE_COLOR_BOTH; +		if (tiling_flags & RADEON_TILING_MACRO) +			flags |= RADEON_SURF_TILE_COLOR_MACRO; +	} else if (rdev->family <= CHIP_RV280) { +		if (tiling_flags & (RADEON_TILING_MACRO)) +			flags |= R200_SURF_TILE_COLOR_MACRO; +		if (tiling_flags & RADEON_TILING_MICRO) +			flags |= R200_SURF_TILE_COLOR_MICRO; +	} else { +		if (tiling_flags & RADEON_TILING_MACRO) +			flags |= R300_SURF_TILE_MACRO; +		if (tiling_flags & RADEON_TILING_MICRO) +			flags |= R300_SURF_TILE_MICRO; +	} + +	DRM_DEBUG("writing surface %d %d %x %x\n", reg, flags, offset, offset+obj_size-1); +	WREG32(RADEON_SURFACE0_INFO + surf_index, flags); +	WREG32(RADEON_SURFACE0_LOWER_BOUND + surf_index, offset); +	WREG32(RADEON_SURFACE0_UPPER_BOUND + surf_index, offset + obj_size - 1); +	return 0; +} + +void r100_clear_surface_reg(struct radeon_device *rdev, int reg) +{ +	int surf_index = reg * 16; +	WREG32(RADEON_SURFACE0_INFO + surf_index, 0); +} + +void r100_bandwidth_update(struct radeon_device *rdev) +{ +	fixed20_12 trcd_ff, trp_ff, tras_ff, trbs_ff, tcas_ff; +	fixed20_12 sclk_ff, mclk_ff, sclk_eff_ff, sclk_delay_ff; +	fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff, crit_point_ff; +	uint32_t temp, data, mem_trcd, mem_trp, mem_tras; +	fixed20_12 memtcas_ff[8] = { +		fixed_init(1), +		fixed_init(2), +		fixed_init(3), +		fixed_init(0), +		fixed_init_half(1), +		fixed_init_half(2), +		fixed_init(0), +	}; +	fixed20_12 memtcas_rs480_ff[8] = { +		fixed_init(0), +		fixed_init(1), +		fixed_init(2), +		fixed_init(3), +		fixed_init(0), +		fixed_init_half(1), +		fixed_init_half(2), +		fixed_init_half(3), +	}; +	fixed20_12 memtcas2_ff[8] = { +		fixed_init(0), +		fixed_init(1), +		fixed_init(2), +		fixed_init(3), +		fixed_init(4), +		fixed_init(5), +		fixed_init(6), +		fixed_init(7), +	}; +	fixed20_12 memtrbs[8] = { +		fixed_init(1), +		fixed_init_half(1), +		fixed_init(2), +		fixed_init_half(2), +		fixed_init(3), +		fixed_init_half(3), +		fixed_init(4), +		fixed_init_half(4) +	}; +	fixed20_12 memtrbs_r4xx[8] = { +		fixed_init(4), +		fixed_init(5), +		fixed_init(6), +		fixed_init(7), +		fixed_init(8), +		fixed_init(9), +		fixed_init(10), +		fixed_init(11) +	}; +	fixed20_12 min_mem_eff; +	fixed20_12 mc_latency_sclk, mc_latency_mclk, k1; +	fixed20_12 cur_latency_mclk, cur_latency_sclk; +	fixed20_12 disp_latency, disp_latency_overhead, disp_drain_rate, +		disp_drain_rate2, read_return_rate; +	fixed20_12 time_disp1_drop_priority; +	int c; +	int cur_size = 16;       /* in octawords */ +	int critical_point = 0, critical_point2; +/* 	uint32_t read_return_rate, time_disp1_drop_priority; */ +	int stop_req, max_stop_req; +	struct drm_display_mode *mode1 = NULL; +	struct drm_display_mode *mode2 = NULL; +	uint32_t pixel_bytes1 = 0; +	uint32_t pixel_bytes2 = 0; + +	if (rdev->mode_info.crtcs[0]->base.enabled) { +		mode1 = &rdev->mode_info.crtcs[0]->base.mode; +		pixel_bytes1 = rdev->mode_info.crtcs[0]->base.fb->bits_per_pixel / 8; +	} +	if (rdev->mode_info.crtcs[1]->base.enabled) { +		mode2 = &rdev->mode_info.crtcs[1]->base.mode; +		pixel_bytes2 = rdev->mode_info.crtcs[1]->base.fb->bits_per_pixel / 8; +	} + +	min_mem_eff.full = rfixed_const_8(0); +	/* get modes */ +	if ((rdev->disp_priority == 2) && ASIC_IS_R300(rdev)) { +		uint32_t mc_init_misc_lat_timer = RREG32(R300_MC_INIT_MISC_LAT_TIMER); +		mc_init_misc_lat_timer &= ~(R300_MC_DISP1R_INIT_LAT_MASK << R300_MC_DISP1R_INIT_LAT_SHIFT); +		mc_init_misc_lat_timer &= ~(R300_MC_DISP0R_INIT_LAT_MASK << R300_MC_DISP0R_INIT_LAT_SHIFT); +		/* check crtc enables */ +		if (mode2) +			mc_init_misc_lat_timer |= (1 << R300_MC_DISP1R_INIT_LAT_SHIFT); +		if (mode1) +			mc_init_misc_lat_timer |= (1 << R300_MC_DISP0R_INIT_LAT_SHIFT); +		WREG32(R300_MC_INIT_MISC_LAT_TIMER, mc_init_misc_lat_timer); +	} + +	/* +	 * determine is there is enough bw for current mode +	 */ +	mclk_ff.full = rfixed_const(rdev->clock.default_mclk); +	temp_ff.full = rfixed_const(100); +	mclk_ff.full = rfixed_div(mclk_ff, temp_ff); +	sclk_ff.full = rfixed_const(rdev->clock.default_sclk); +	sclk_ff.full = rfixed_div(sclk_ff, temp_ff); + +	temp = (rdev->mc.vram_width / 8) * (rdev->mc.vram_is_ddr ? 2 : 1); +	temp_ff.full = rfixed_const(temp); +	mem_bw.full = rfixed_mul(mclk_ff, temp_ff); + +	pix_clk.full = 0; +	pix_clk2.full = 0; +	peak_disp_bw.full = 0; +	if (mode1) { +		temp_ff.full = rfixed_const(1000); +		pix_clk.full = rfixed_const(mode1->clock); /* convert to fixed point */ +		pix_clk.full = rfixed_div(pix_clk, temp_ff); +		temp_ff.full = rfixed_const(pixel_bytes1); +		peak_disp_bw.full += rfixed_mul(pix_clk, temp_ff); +	} +	if (mode2) { +		temp_ff.full = rfixed_const(1000); +		pix_clk2.full = rfixed_const(mode2->clock); /* convert to fixed point */ +		pix_clk2.full = rfixed_div(pix_clk2, temp_ff); +		temp_ff.full = rfixed_const(pixel_bytes2); +		peak_disp_bw.full += rfixed_mul(pix_clk2, temp_ff); +	} + +	mem_bw.full = rfixed_mul(mem_bw, min_mem_eff); +	if (peak_disp_bw.full >= mem_bw.full) { +		DRM_ERROR("You may not have enough display bandwidth for current mode\n" +			  "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n"); +	} + +	/*  Get values from the EXT_MEM_CNTL register...converting its contents. */ +	temp = RREG32(RADEON_MEM_TIMING_CNTL); +	if ((rdev->family == CHIP_RV100) || (rdev->flags & RADEON_IS_IGP)) { /* RV100, M6, IGPs */ +		mem_trcd = ((temp >> 2) & 0x3) + 1; +		mem_trp  = ((temp & 0x3)) + 1; +		mem_tras = ((temp & 0x70) >> 4) + 1; +	} else if (rdev->family == CHIP_R300 || +		   rdev->family == CHIP_R350) { /* r300, r350 */ +		mem_trcd = (temp & 0x7) + 1; +		mem_trp = ((temp >> 8) & 0x7) + 1; +		mem_tras = ((temp >> 11) & 0xf) + 4; +	} else if (rdev->family == CHIP_RV350 || +		   rdev->family <= CHIP_RV380) { +		/* rv3x0 */ +		mem_trcd = (temp & 0x7) + 3; +		mem_trp = ((temp >> 8) & 0x7) + 3; +		mem_tras = ((temp >> 11) & 0xf) + 6; +	} else if (rdev->family == CHIP_R420 || +		   rdev->family == CHIP_R423 || +		   rdev->family == CHIP_RV410) { +		/* r4xx */ +		mem_trcd = (temp & 0xf) + 3; +		if (mem_trcd > 15) +			mem_trcd = 15; +		mem_trp = ((temp >> 8) & 0xf) + 3; +		if (mem_trp > 15) +			mem_trp = 15; +		mem_tras = ((temp >> 12) & 0x1f) + 6; +		if (mem_tras > 31) +			mem_tras = 31; +	} else { /* RV200, R200 */ +		mem_trcd = (temp & 0x7) + 1; +		mem_trp = ((temp >> 8) & 0x7) + 1; +		mem_tras = ((temp >> 12) & 0xf) + 4; +	} +	/* convert to FF */ +	trcd_ff.full = rfixed_const(mem_trcd); +	trp_ff.full = rfixed_const(mem_trp); +	tras_ff.full = rfixed_const(mem_tras); + +	/* Get values from the MEM_SDRAM_MODE_REG register...converting its */ +	temp = RREG32(RADEON_MEM_SDRAM_MODE_REG); +	data = (temp & (7 << 20)) >> 20; +	if ((rdev->family == CHIP_RV100) || rdev->flags & RADEON_IS_IGP) { +		if (rdev->family == CHIP_RS480) /* don't think rs400 */ +			tcas_ff = memtcas_rs480_ff[data]; +		else +			tcas_ff = memtcas_ff[data]; +	} else +		tcas_ff = memtcas2_ff[data]; + +	if (rdev->family == CHIP_RS400 || +	    rdev->family == CHIP_RS480) { +		/* extra cas latency stored in bits 23-25 0-4 clocks */ +		data = (temp >> 23) & 0x7; +		if (data < 5) +			tcas_ff.full += rfixed_const(data); +	} + +	if (ASIC_IS_R300(rdev) && !(rdev->flags & RADEON_IS_IGP)) { +		/* on the R300, Tcas is included in Trbs. +		 */ +		temp = RREG32(RADEON_MEM_CNTL); +		data = (R300_MEM_NUM_CHANNELS_MASK & temp); +		if (data == 1) { +			if (R300_MEM_USE_CD_CH_ONLY & temp) { +				temp = RREG32(R300_MC_IND_INDEX); +				temp &= ~R300_MC_IND_ADDR_MASK; +				temp |= R300_MC_READ_CNTL_CD_mcind; +				WREG32(R300_MC_IND_INDEX, temp); +				temp = RREG32(R300_MC_IND_DATA); +				data = (R300_MEM_RBS_POSITION_C_MASK & temp); +			} else { +				temp = RREG32(R300_MC_READ_CNTL_AB); +				data = (R300_MEM_RBS_POSITION_A_MASK & temp); +			} +		} else { +			temp = RREG32(R300_MC_READ_CNTL_AB); +			data = (R300_MEM_RBS_POSITION_A_MASK & temp); +		} +		if (rdev->family == CHIP_RV410 || +		    rdev->family == CHIP_R420 || +		    rdev->family == CHIP_R423) +			trbs_ff = memtrbs_r4xx[data]; +		else +			trbs_ff = memtrbs[data]; +		tcas_ff.full += trbs_ff.full; +	} + +	sclk_eff_ff.full = sclk_ff.full; + +	if (rdev->flags & RADEON_IS_AGP) { +		fixed20_12 agpmode_ff; +		agpmode_ff.full = rfixed_const(radeon_agpmode); +		temp_ff.full = rfixed_const_666(16); +		sclk_eff_ff.full -= rfixed_mul(agpmode_ff, temp_ff); +	} +	/* TODO PCIE lanes may affect this - agpmode == 16?? */ + +	if (ASIC_IS_R300(rdev)) { +		sclk_delay_ff.full = rfixed_const(250); +	} else { +		if ((rdev->family == CHIP_RV100) || +		    rdev->flags & RADEON_IS_IGP) { +			if (rdev->mc.vram_is_ddr) +				sclk_delay_ff.full = rfixed_const(41); +			else +				sclk_delay_ff.full = rfixed_const(33); +		} else { +			if (rdev->mc.vram_width == 128) +				sclk_delay_ff.full = rfixed_const(57); +			else +				sclk_delay_ff.full = rfixed_const(41); +		} +	} + +	mc_latency_sclk.full = rfixed_div(sclk_delay_ff, sclk_eff_ff); + +	if (rdev->mc.vram_is_ddr) { +		if (rdev->mc.vram_width == 32) { +			k1.full = rfixed_const(40); +			c  = 3; +		} else { +			k1.full = rfixed_const(20); +			c  = 1; +		} +	} else { +		k1.full = rfixed_const(40); +		c  = 3; +	} + +	temp_ff.full = rfixed_const(2); +	mc_latency_mclk.full = rfixed_mul(trcd_ff, temp_ff); +	temp_ff.full = rfixed_const(c); +	mc_latency_mclk.full += rfixed_mul(tcas_ff, temp_ff); +	temp_ff.full = rfixed_const(4); +	mc_latency_mclk.full += rfixed_mul(tras_ff, temp_ff); +	mc_latency_mclk.full += rfixed_mul(trp_ff, temp_ff); +	mc_latency_mclk.full += k1.full; + +	mc_latency_mclk.full = rfixed_div(mc_latency_mclk, mclk_ff); +	mc_latency_mclk.full += rfixed_div(temp_ff, sclk_eff_ff); + +	/* +	  HW cursor time assuming worst case of full size colour cursor. +	*/ +	temp_ff.full = rfixed_const((2 * (cur_size - (rdev->mc.vram_is_ddr + 1)))); +	temp_ff.full += trcd_ff.full; +	if (temp_ff.full < tras_ff.full) +		temp_ff.full = tras_ff.full; +	cur_latency_mclk.full = rfixed_div(temp_ff, mclk_ff); + +	temp_ff.full = rfixed_const(cur_size); +	cur_latency_sclk.full = rfixed_div(temp_ff, sclk_eff_ff); +	/* +	  Find the total latency for the display data. +	*/ +	disp_latency_overhead.full = rfixed_const(80); +	disp_latency_overhead.full = rfixed_div(disp_latency_overhead, sclk_ff); +	mc_latency_mclk.full += disp_latency_overhead.full + cur_latency_mclk.full; +	mc_latency_sclk.full += disp_latency_overhead.full + cur_latency_sclk.full; + +	if (mc_latency_mclk.full > mc_latency_sclk.full) +		disp_latency.full = mc_latency_mclk.full; +	else +		disp_latency.full = mc_latency_sclk.full; + +	/* setup Max GRPH_STOP_REQ default value */ +	if (ASIC_IS_RV100(rdev)) +		max_stop_req = 0x5c; +	else +		max_stop_req = 0x7c; + +	if (mode1) { +		/*  CRTC1 +		    Set GRPH_BUFFER_CNTL register using h/w defined optimal values. +		    GRPH_STOP_REQ <= MIN[ 0x7C, (CRTC_H_DISP + 1) * (bit depth) / 0x10 ] +		*/ +		stop_req = mode1->hdisplay * pixel_bytes1 / 16; + +		if (stop_req > max_stop_req) +			stop_req = max_stop_req; + +		/* +		  Find the drain rate of the display buffer. +		*/ +		temp_ff.full = rfixed_const((16/pixel_bytes1)); +		disp_drain_rate.full = rfixed_div(pix_clk, temp_ff); + +		/* +		  Find the critical point of the display buffer. +		*/ +		crit_point_ff.full = rfixed_mul(disp_drain_rate, disp_latency); +		crit_point_ff.full += rfixed_const_half(0); + +		critical_point = rfixed_trunc(crit_point_ff); + +		if (rdev->disp_priority == 2) { +			critical_point = 0; +		} + +		/* +		  The critical point should never be above max_stop_req-4.  Setting +		  GRPH_CRITICAL_CNTL = 0 will thus force high priority all the time. +		*/ +		if (max_stop_req - critical_point < 4) +			critical_point = 0; + +		if (critical_point == 0 && mode2 && rdev->family == CHIP_R300) { +			/* some R300 cards have problem with this set to 0, when CRTC2 is enabled.*/ +			critical_point = 0x10; +		} + +		temp = RREG32(RADEON_GRPH_BUFFER_CNTL); +		temp &= ~(RADEON_GRPH_STOP_REQ_MASK); +		temp |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT); +		temp &= ~(RADEON_GRPH_START_REQ_MASK); +		if ((rdev->family == CHIP_R350) && +		    (stop_req > 0x15)) { +			stop_req -= 0x10; +		} +		temp |= (stop_req << RADEON_GRPH_START_REQ_SHIFT); +		temp |= RADEON_GRPH_BUFFER_SIZE; +		temp &= ~(RADEON_GRPH_CRITICAL_CNTL   | +			  RADEON_GRPH_CRITICAL_AT_SOF | +			  RADEON_GRPH_STOP_CNTL); +		/* +		  Write the result into the register. +		*/ +		WREG32(RADEON_GRPH_BUFFER_CNTL, ((temp & ~RADEON_GRPH_CRITICAL_POINT_MASK) | +						       (critical_point << RADEON_GRPH_CRITICAL_POINT_SHIFT))); + +#if 0 +		if ((rdev->family == CHIP_RS400) || +		    (rdev->family == CHIP_RS480)) { +			/* attempt to program RS400 disp regs correctly ??? */ +			temp = RREG32(RS400_DISP1_REG_CNTL); +			temp &= ~(RS400_DISP1_START_REQ_LEVEL_MASK | +				  RS400_DISP1_STOP_REQ_LEVEL_MASK); +			WREG32(RS400_DISP1_REQ_CNTL1, (temp | +						       (critical_point << RS400_DISP1_START_REQ_LEVEL_SHIFT) | +						       (critical_point << RS400_DISP1_STOP_REQ_LEVEL_SHIFT))); +			temp = RREG32(RS400_DMIF_MEM_CNTL1); +			temp &= ~(RS400_DISP1_CRITICAL_POINT_START_MASK | +				  RS400_DISP1_CRITICAL_POINT_STOP_MASK); +			WREG32(RS400_DMIF_MEM_CNTL1, (temp | +						      (critical_point << RS400_DISP1_CRITICAL_POINT_START_SHIFT) | +						      (critical_point << RS400_DISP1_CRITICAL_POINT_STOP_SHIFT))); +		} +#endif + +		DRM_DEBUG("GRPH_BUFFER_CNTL from to %x\n", +			  /* 	  (unsigned int)info->SavedReg->grph_buffer_cntl, */ +			  (unsigned int)RREG32(RADEON_GRPH_BUFFER_CNTL)); +	} + +	if (mode2) { +		u32 grph2_cntl; +		stop_req = mode2->hdisplay * pixel_bytes2 / 16; + +		if (stop_req > max_stop_req) +			stop_req = max_stop_req; + +		/* +		  Find the drain rate of the display buffer. +		*/ +		temp_ff.full = rfixed_const((16/pixel_bytes2)); +		disp_drain_rate2.full = rfixed_div(pix_clk2, temp_ff); + +		grph2_cntl = RREG32(RADEON_GRPH2_BUFFER_CNTL); +		grph2_cntl &= ~(RADEON_GRPH_STOP_REQ_MASK); +		grph2_cntl |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT); +		grph2_cntl &= ~(RADEON_GRPH_START_REQ_MASK); +		if ((rdev->family == CHIP_R350) && +		    (stop_req > 0x15)) { +			stop_req -= 0x10; +		} +		grph2_cntl |= (stop_req << RADEON_GRPH_START_REQ_SHIFT); +		grph2_cntl |= RADEON_GRPH_BUFFER_SIZE; +		grph2_cntl &= ~(RADEON_GRPH_CRITICAL_CNTL   | +			  RADEON_GRPH_CRITICAL_AT_SOF | +			  RADEON_GRPH_STOP_CNTL); + +		if ((rdev->family == CHIP_RS100) || +		    (rdev->family == CHIP_RS200)) +			critical_point2 = 0; +		else { +			temp = (rdev->mc.vram_width * rdev->mc.vram_is_ddr + 1)/128; +			temp_ff.full = rfixed_const(temp); +			temp_ff.full = rfixed_mul(mclk_ff, temp_ff); +			if (sclk_ff.full < temp_ff.full) +				temp_ff.full = sclk_ff.full; + +			read_return_rate.full = temp_ff.full; + +			if (mode1) { +				temp_ff.full = read_return_rate.full - disp_drain_rate.full; +				time_disp1_drop_priority.full = rfixed_div(crit_point_ff, temp_ff); +			} else { +				time_disp1_drop_priority.full = 0; +			} +			crit_point_ff.full = disp_latency.full + time_disp1_drop_priority.full + disp_latency.full; +			crit_point_ff.full = rfixed_mul(crit_point_ff, disp_drain_rate2); +			crit_point_ff.full += rfixed_const_half(0); + +			critical_point2 = rfixed_trunc(crit_point_ff); + +			if (rdev->disp_priority == 2) { +				critical_point2 = 0; +			} + +			if (max_stop_req - critical_point2 < 4) +				critical_point2 = 0; + +		} + +		if (critical_point2 == 0 && rdev->family == CHIP_R300) { +			/* some R300 cards have problem with this set to 0 */ +			critical_point2 = 0x10; +		} + +		WREG32(RADEON_GRPH2_BUFFER_CNTL, ((grph2_cntl & ~RADEON_GRPH_CRITICAL_POINT_MASK) | +						  (critical_point2 << RADEON_GRPH_CRITICAL_POINT_SHIFT))); + +		if ((rdev->family == CHIP_RS400) || +		    (rdev->family == CHIP_RS480)) { +#if 0 +			/* attempt to program RS400 disp2 regs correctly ??? */ +			temp = RREG32(RS400_DISP2_REQ_CNTL1); +			temp &= ~(RS400_DISP2_START_REQ_LEVEL_MASK | +				  RS400_DISP2_STOP_REQ_LEVEL_MASK); +			WREG32(RS400_DISP2_REQ_CNTL1, (temp | +						       (critical_point2 << RS400_DISP1_START_REQ_LEVEL_SHIFT) | +						       (critical_point2 << RS400_DISP1_STOP_REQ_LEVEL_SHIFT))); +			temp = RREG32(RS400_DISP2_REQ_CNTL2); +			temp &= ~(RS400_DISP2_CRITICAL_POINT_START_MASK | +				  RS400_DISP2_CRITICAL_POINT_STOP_MASK); +			WREG32(RS400_DISP2_REQ_CNTL2, (temp | +						       (critical_point2 << RS400_DISP2_CRITICAL_POINT_START_SHIFT) | +						       (critical_point2 << RS400_DISP2_CRITICAL_POINT_STOP_SHIFT))); +#endif +			WREG32(RS400_DISP2_REQ_CNTL1, 0x105DC1CC); +			WREG32(RS400_DISP2_REQ_CNTL2, 0x2749D000); +			WREG32(RS400_DMIF_MEM_CNTL1,  0x29CA71DC); +			WREG32(RS400_DISP1_REQ_CNTL1, 0x28FBC3AC); +		} + +		DRM_DEBUG("GRPH2_BUFFER_CNTL from to %x\n", +			  (unsigned int)RREG32(RADEON_GRPH2_BUFFER_CNTL)); +	} +} diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index e2ed5bc0817..c47579dcafa 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -30,6 +30,8 @@  #include "drm.h"  #include "radeon_reg.h"  #include "radeon.h" +#include "radeon_drm.h" +#include "radeon_share.h"  /* r300,r350,rv350,rv370,rv380 depends on : */  void r100_hdp_reset(struct radeon_device *rdev); @@ -44,6 +46,7 @@ int r100_gui_wait_for_idle(struct radeon_device *rdev);  int r100_cs_packet_parse(struct radeon_cs_parser *p,  			 struct radeon_cs_packet *pkt,  			 unsigned idx); +int r100_cs_packet_parse_vline(struct radeon_cs_parser *p);  int r100_cs_packet_next_reloc(struct radeon_cs_parser *p,  			      struct radeon_cs_reloc **cs_reloc);  int r100_cs_parse_packet0(struct radeon_cs_parser *p, @@ -80,8 +83,8 @@ void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev)  		WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp | RADEON_PCIE_TX_GART_INVALIDATE_TLB);  		(void)RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL);  		WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); -		mb();  	} +	mb();  }  int rv370_pcie_gart_enable(struct radeon_device *rdev) @@ -150,8 +153,13 @@ int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)  	if (i < 0 || i > rdev->gart.num_gpu_pages) {  		return -EINVAL;  	} -	addr = (((u32)addr) >> 8) | ((upper_32_bits(addr) & 0xff) << 4) | 0xC; -	writel(cpu_to_le32(addr), ((void __iomem *)ptr) + (i * 4)); +	addr = (lower_32_bits(addr) >> 8) | +	       ((upper_32_bits(addr) & 0xff) << 24) | +	       0xc; +	/* on x86 we want this to be CPU endian, on powerpc +	 * on powerpc without HW swappers, it'll get swapped on way +	 * into VRAM - so no need for cpu_to_le32 on VRAM tables */ +	writel(addr, ((void __iomem *)ptr) + (i * 4));  	return 0;  } @@ -579,35 +587,12 @@ void r300_vram_info(struct radeon_device *rdev)  	} else {  		rdev->mc.vram_width = 64;  	} -	rdev->mc.vram_size = RREG32(RADEON_CONFIG_MEMSIZE); -	rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); -	rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); +	r100_vram_init_sizes(rdev);  }  /* - * Indirect registers accessor - */ -uint32_t rv370_pcie_rreg(struct radeon_device *rdev, uint32_t reg) -{ -	uint32_t r; - -	WREG8(RADEON_PCIE_INDEX, ((reg) & 0xff)); -	(void)RREG32(RADEON_PCIE_INDEX); -	r = RREG32(RADEON_PCIE_DATA); -	return r; -} - -void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) -{ -	WREG8(RADEON_PCIE_INDEX, ((reg) & 0xff)); -	(void)RREG32(RADEON_PCIE_INDEX); -	WREG32(RADEON_PCIE_DATA, (v)); -	(void)RREG32(RADEON_PCIE_DATA); -} - -/*   * PCIE Lanes   */ @@ -970,7 +955,7 @@ static inline void r300_cs_track_clear(struct r300_cs_track *track)  static const unsigned r300_reg_safe_bm[159] = {  	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, -	0xFFFFFFBF, 0xFFFFFFFF, 0xFFFFFFBF, 0xFFFFFFFF, +	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,  	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,  	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,  	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, @@ -1019,7 +1004,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,  	struct radeon_cs_reloc *reloc;  	struct r300_cs_track *track;  	volatile uint32_t *ib; -	uint32_t tmp; +	uint32_t tmp, tile_flags = 0;  	unsigned i;  	int r; @@ -1027,6 +1012,16 @@ static int r300_packet0_check(struct radeon_cs_parser *p,  	ib_chunk = &p->chunks[p->chunk_ib_idx];  	track = (struct r300_cs_track*)p->track;  	switch(reg) { +	case AVIVO_D1MODE_VLINE_START_END: +	case RADEON_CRTC_GUI_TRIG_VLINE: +		r = r100_cs_packet_parse_vline(p); +		if (r) { +			DRM_ERROR("No reloc for ib[%d]=0x%04X\n", +					idx, reg); +			r100_cs_dump_packet(p, pkt); +			return r; +		} +		break;  	case RADEON_DST_PITCH_OFFSET:  	case RADEON_SRC_PITCH_OFFSET:  		r = r100_cs_packet_next_reloc(p, &reloc); @@ -1038,7 +1033,19 @@ static int r300_packet0_check(struct radeon_cs_parser *p,  		}  		tmp = ib_chunk->kdata[idx] & 0x003fffff;  		tmp += (((u32)reloc->lobj.gpu_offset) >> 10); -		ib[idx] = (ib_chunk->kdata[idx] & 0xffc00000) | tmp; + +		if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) +			tile_flags |= RADEON_DST_TILE_MACRO; +		if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) { +			if (reg == RADEON_SRC_PITCH_OFFSET) { +				DRM_ERROR("Cannot src blit from microtiled surface\n"); +				r100_cs_dump_packet(p, pkt); +				return -EINVAL; +			} +			tile_flags |= RADEON_DST_TILE_MICRO; +		} +		tmp |= tile_flags; +		ib[idx] = (ib_chunk->kdata[idx] & 0x3fc00000) | tmp;  		break;  	case R300_RB3D_COLOROFFSET0:  	case R300_RB3D_COLOROFFSET1: @@ -1127,6 +1134,23 @@ static int r300_packet0_check(struct radeon_cs_parser *p,  		/* RB3D_COLORPITCH1 */  		/* RB3D_COLORPITCH2 */  		/* RB3D_COLORPITCH3 */ +		r = r100_cs_packet_next_reloc(p, &reloc); +		if (r) { +			DRM_ERROR("No reloc for ib[%d]=0x%04X\n", +				  idx, reg); +			r100_cs_dump_packet(p, pkt); +			return r; +		} + +		if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) +			tile_flags |= R300_COLOR_TILE_ENABLE; +		if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) +			tile_flags |= R300_COLOR_MICROTILE_ENABLE; + +		tmp = ib_chunk->kdata[idx] & ~(0x7 << 16); +		tmp |= tile_flags; +		ib[idx] = tmp; +  		i = (reg - 0x4E38) >> 2;  		track->cb[i].pitch = ib_chunk->kdata[idx] & 0x3FFE;  		switch (((ib_chunk->kdata[idx] >> 21) & 0xF)) { @@ -1182,6 +1206,23 @@ static int r300_packet0_check(struct radeon_cs_parser *p,  		break;  	case 0x4F24:  		/* ZB_DEPTHPITCH */ +		r = r100_cs_packet_next_reloc(p, &reloc); +		if (r) { +			DRM_ERROR("No reloc for ib[%d]=0x%04X\n", +				  idx, reg); +			r100_cs_dump_packet(p, pkt); +			return r; +		} + +		if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) +			tile_flags |= R300_DEPTHMACROTILE_ENABLE; +		if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) +			tile_flags |= R300_DEPTHMICROTILE_TILED;; + +		tmp = ib_chunk->kdata[idx] & ~(0x7 << 16); +		tmp |= tile_flags; +		ib[idx] = tmp; +  		track->zb.pitch = ib_chunk->kdata[idx] & 0x3FFC;  		break;  	case 0x4104: @@ -1341,6 +1382,21 @@ static int r300_packet0_check(struct radeon_cs_parser *p,  		tmp = (ib_chunk->kdata[idx] >> 22) & 0xF;  		track->textures[i].txdepth = tmp;  		break; +	case R300_ZB_ZPASS_ADDR: +		r = r100_cs_packet_next_reloc(p, &reloc); +		if (r) { +			DRM_ERROR("No reloc for ib[%d]=0x%04X\n", +					idx, reg); +			r100_cs_dump_packet(p, pkt); +			return r; +		} +		ib[idx] = ib_chunk->kdata[idx] + ((u32)reloc->lobj.gpu_offset); +		break; +	case 0x4be8: +		/* valid register only on RV530 */ +		if (p->rdev->family == CHIP_RV530) +			break; +		/* fallthrough do not move */  	default:  		printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n",  		       reg, idx); diff --git a/drivers/gpu/drm/radeon/r300_reg.h b/drivers/gpu/drm/radeon/r300_reg.h index 70f48609515..4b7afef35a6 100644 --- a/drivers/gpu/drm/radeon/r300_reg.h +++ b/drivers/gpu/drm/radeon/r300_reg.h @@ -27,7 +27,9 @@  #ifndef _R300_REG_H_  #define _R300_REG_H_ - +#define R300_SURF_TILE_MACRO (1<<16) +#define R300_SURF_TILE_MICRO (2<<16) +#define R300_SURF_TILE_BOTH (3<<16)  #define R300_MC_INIT_MISC_LAT_TIMER	0x180 diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h index 9070a1c2ce2..e1d5e0331e1 100644 --- a/drivers/gpu/drm/radeon/r500_reg.h +++ b/drivers/gpu/drm/radeon/r500_reg.h @@ -350,6 +350,7 @@  #define AVIVO_D1CRTC_BLANK_CONTROL                              0x6084  #define AVIVO_D1CRTC_INTERLACE_CONTROL                          0x6088  #define AVIVO_D1CRTC_INTERLACE_STATUS                           0x608c +#define AVIVO_D1CRTC_FRAME_COUNT                                0x60a4  #define AVIVO_D1CRTC_STEREO_CONTROL                             0x60c4  /* master controls */ @@ -438,13 +439,15 @@  #       define AVIVO_DC_LB_DISP1_END_ADR_SHIFT  4  #       define AVIVO_DC_LB_DISP1_END_ADR_MASK   0x7ff -#define R500_DxMODE_INT_MASK 0x6540 -#define R500_D1MODE_INT_MASK (1<<0) -#define R500_D2MODE_INT_MASK (1<<8) -  #define AVIVO_D1MODE_DATA_FORMAT                0x6528  #       define AVIVO_D1MODE_INTERLEAVE_EN       (1 << 0)  #define AVIVO_D1MODE_DESKTOP_HEIGHT             0x652C +#define AVIVO_D1MODE_VBLANK_STATUS              0x6534 +#       define AVIVO_VBLANK_ACK                 (1 << 4) +#define AVIVO_D1MODE_VLINE_START_END            0x6538 +#define AVIVO_DxMODE_INT_MASK                   0x6540 +#       define AVIVO_D1MODE_INT_MASK            (1 << 0) +#       define AVIVO_D2MODE_INT_MASK            (1 << 8)  #define AVIVO_D1MODE_VIEWPORT_START             0x6580  #define AVIVO_D1MODE_VIEWPORT_SIZE              0x6584  #define AVIVO_D1MODE_EXT_OVERSCAN_LEFT_RIGHT    0x6588 @@ -474,6 +477,7 @@  #define AVIVO_D2CRTC_BLANK_CONTROL                              0x6884  #define AVIVO_D2CRTC_INTERLACE_CONTROL                          0x6888  #define AVIVO_D2CRTC_INTERLACE_STATUS                           0x688c +#define AVIVO_D2CRTC_FRAME_COUNT                                0x68a4  #define AVIVO_D2CRTC_STEREO_CONTROL                             0x68c4  #define AVIVO_D2GRPH_ENABLE                                     0x6900 @@ -496,6 +500,8 @@  #define AVIVO_D2CUR_SIZE                        0x6c10  #define AVIVO_D2CUR_POSITION                    0x6c14 +#define AVIVO_D2MODE_VBLANK_STATUS              0x6d34 +#define AVIVO_D2MODE_VLINE_START_END            0x6d38  #define AVIVO_D2MODE_VIEWPORT_START             0x6d80  #define AVIVO_D2MODE_VIEWPORT_SIZE              0x6d84  #define AVIVO_D2MODE_EXT_OVERSCAN_LEFT_RIGHT    0x6d88 @@ -746,4 +752,8 @@  #	define AVIVO_I2C_EN							(1 << 0)  #	define AVIVO_I2C_RESET						(1 << 8) +#define AVIVO_DISP_INTERRUPT_STATUS                             0x7edc +#       define AVIVO_D1_VBLANK_INTERRUPT                        (1 << 4) +#       define AVIVO_D2_VBLANK_INTERRUPT                        (1 << 5) +  #endif diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index 570a244bd88..09fb0b6ec7d 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -28,6 +28,7 @@  #include "drmP.h"  #include "radeon_reg.h"  #include "radeon.h" +#include "radeon_share.h"  /* r520,rv530,rv560,rv570,r580 depends on : */  void r100_hdp_reset(struct radeon_device *rdev); @@ -94,8 +95,8 @@ int r520_mc_init(struct radeon_device *rdev)  		       "programming pipes. Bad things might happen.\n");  	}  	/* Write VRAM size in case we are limiting it */ -	WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size); -	tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1; +	WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.real_vram_size); +	tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;  	tmp = REG_SET(R520_MC_FB_TOP, tmp >> 16);  	tmp |= REG_SET(R520_MC_FB_START, rdev->mc.vram_location >> 16);  	WREG32_MC(R520_MC_FB_LOCATION, tmp); @@ -226,9 +227,20 @@ static void r520_vram_get_type(struct radeon_device *rdev)  void r520_vram_info(struct radeon_device *rdev)  { +	fixed20_12 a; +  	r520_vram_get_type(rdev); -	rdev->mc.vram_size = RREG32(RADEON_CONFIG_MEMSIZE); -	rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); -	rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); +	r100_vram_init_sizes(rdev); +	/* FIXME: we should enforce default clock in case GPU is not in +	 * default setup +	 */ +	a.full = rfixed_const(100); +	rdev->pm.sclk.full = rfixed_const(rdev->clock.default_sclk); +	rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a); +} + +void r520_bandwidth_update(struct radeon_device *rdev) +{ +	rv515_bandwidth_avivo_update(rdev);  } diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index c45559fc97f..538cd907df6 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -67,7 +67,7 @@ int r600_mc_init(struct radeon_device *rdev)  		       "programming pipes. Bad things might happen.\n");  	} -	tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1; +	tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;  	tmp = REG_SET(R600_MC_FB_TOP, tmp >> 24);  	tmp |= REG_SET(R600_MC_FB_BASE, rdev->mc.vram_location >> 24);  	WREG32(R600_MC_VM_FB_LOCATION, tmp); @@ -140,7 +140,8 @@ void r600_vram_get_type(struct radeon_device *rdev)  void r600_vram_info(struct radeon_device *rdev)  {  	r600_vram_get_type(rdev); -	rdev->mc.vram_size = RREG32(R600_CONFIG_MEMSIZE); +	rdev->mc.real_vram_size = RREG32(R600_CONFIG_MEMSIZE); +	rdev->mc.mc_vram_size = rdev->mc.real_vram_size;  	/* Could aper size report 0 ? */  	rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c index 146f3570af8..20f17908b03 100644 --- a/drivers/gpu/drm/radeon/r600_cp.c +++ b/drivers/gpu/drm/radeon/r600_cp.c @@ -384,8 +384,9 @@ static void r600_cp_load_microcode(drm_radeon_private_t *dev_priv)  		DRM_INFO("Loading RV670 PFP Microcode\n");  		for (i = 0; i < PFP_UCODE_SIZE; i++)  			RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV670_pfp_microcode[i]); -	} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780)) { -		DRM_INFO("Loading RS780 CP Microcode\n"); +	} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) || +		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880)) { +		DRM_INFO("Loading RS780/RS880 CP Microcode\n");  		for (i = 0; i < PM4_UCODE_SIZE; i++) {  			RADEON_WRITE(R600_CP_ME_RAM_DATA,  				     RS780_cp_microcode[i][0]); @@ -396,7 +397,7 @@ static void r600_cp_load_microcode(drm_radeon_private_t *dev_priv)  		}  		RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0); -		DRM_INFO("Loading RS780 PFP Microcode\n"); +		DRM_INFO("Loading RS780/RS880 PFP Microcode\n");  		for (i = 0; i < PFP_UCODE_SIZE; i++)  			RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RS780_pfp_microcode[i]);  	} @@ -783,6 +784,7 @@ static void r600_gfx_init(struct drm_device *dev,  		break;  	case CHIP_RV610:  	case CHIP_RS780: +	case CHIP_RS880:  	case CHIP_RV620:  		dev_priv->r600_max_pipes = 1;  		dev_priv->r600_max_tile_pipes = 1; @@ -917,7 +919,8 @@ static void r600_gfx_init(struct drm_device *dev,  	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV630) ||  	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) ||  	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) || -	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780)) +	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) || +	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880))  		RADEON_WRITE(R600_DB_DEBUG, R600_PREZ_MUST_WAIT_FOR_POSTZ_DONE);  	else  		RADEON_WRITE(R600_DB_DEBUG, 0); @@ -935,7 +938,8 @@ static void r600_gfx_init(struct drm_device *dev,  	sq_ms_fifo_sizes = RADEON_READ(R600_SQ_MS_FIFO_SIZES);  	if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) ||  	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) || -	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780)) { +	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) || +	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880)) {  		sq_ms_fifo_sizes = (R600_CACHE_FIFO_SIZE(0xa) |  				    R600_FETCH_FIFO_HIWATER(0xa) |  				    R600_DONE_FIFO_HIWATER(0xe0) | @@ -978,7 +982,8 @@ static void r600_gfx_init(struct drm_device *dev,  					    R600_NUM_ES_STACK_ENTRIES(0));  	} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) ||  		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) || -		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780)) { +		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) || +		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880)) {  		/* no vertex cache */  		sq_config &= ~R600_VC_ENABLE; @@ -1035,7 +1040,8 @@ static void r600_gfx_init(struct drm_device *dev,  	if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV610) ||  	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV620) || -	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780)) +	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS780) || +	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS880))  		RADEON_WRITE(R600_VGT_CACHE_INVALIDATION, R600_CACHE_INVALIDATION(R600_TC_ONLY));  	else  		RADEON_WRITE(R600_VGT_CACHE_INVALIDATION, R600_CACHE_INVALIDATION(R600_VC_AND_TC)); @@ -1078,6 +1084,7 @@ static void r600_gfx_init(struct drm_device *dev,  		break;  	case CHIP_RV610:  	case CHIP_RS780: +	case CHIP_RS880:  	case CHIP_RV620:  		gs_prim_buffer_depth = 32;  		break; @@ -1123,6 +1130,7 @@ static void r600_gfx_init(struct drm_device *dev,  	switch (dev_priv->flags & RADEON_FAMILY_MASK) {  	case CHIP_RV610:  	case CHIP_RS780: +	case CHIP_RS880:  	case CHIP_RV620:  		tc_cntl = R600_TC_L2_SIZE(8);  		break; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index d61f2fc61df..79ad98264e3 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -64,6 +64,7 @@ extern int radeon_agpmode;  extern int radeon_vram_limit;  extern int radeon_gart_size;  extern int radeon_benchmarking; +extern int radeon_testing;  extern int radeon_connector_table;  /* @@ -113,6 +114,7 @@ enum radeon_family {  	CHIP_RV770,  	CHIP_RV730,  	CHIP_RV710, +	CHIP_RS880,  	CHIP_LAST,  }; @@ -201,6 +203,14 @@ int radeon_fence_wait_last(struct radeon_device *rdev);  struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence);  void radeon_fence_unref(struct radeon_fence **fence); +/* + * Tiling registers + */ +struct radeon_surface_reg { +	struct radeon_object *robj; +}; + +#define RADEON_GEM_MAX_SURFACES 8  /*   * Radeon buffer. @@ -213,6 +223,7 @@ struct radeon_object_list {  	uint64_t		gpu_offset;  	unsigned		rdomain;  	unsigned		wdomain; +	uint32_t                tiling_flags;  };  int radeon_object_init(struct radeon_device *rdev); @@ -231,6 +242,7 @@ int radeon_object_pin(struct radeon_object *robj, uint32_t domain,  		      uint64_t *gpu_addr);  void radeon_object_unpin(struct radeon_object *robj);  int radeon_object_wait(struct radeon_object *robj); +int radeon_object_busy_domain(struct radeon_object *robj, uint32_t *cur_placement);  int radeon_object_evict_vram(struct radeon_device *rdev);  int radeon_object_mmap(struct radeon_object *robj, uint64_t *offset);  void radeon_object_force_delete(struct radeon_device *rdev); @@ -242,8 +254,15 @@ void radeon_object_list_clean(struct list_head *head);  int radeon_object_fbdev_mmap(struct radeon_object *robj,  			     struct vm_area_struct *vma);  unsigned long radeon_object_size(struct radeon_object *robj); - - +void radeon_object_clear_surface_reg(struct radeon_object *robj); +int radeon_object_check_tiling(struct radeon_object *robj, bool has_moved, +			       bool force_drop); +void radeon_object_set_tiling_flags(struct radeon_object *robj, +				    uint32_t tiling_flags, uint32_t pitch); +void radeon_object_get_tiling_flags(struct radeon_object *robj, uint32_t *tiling_flags, uint32_t *pitch); +void radeon_bo_move_notify(struct ttm_buffer_object *bo, +			   struct ttm_mem_reg *mem); +void radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo);  /*   * GEM objects.   */ @@ -315,8 +334,11 @@ struct radeon_mc {  	unsigned		gtt_location;  	unsigned		gtt_size;  	unsigned		vram_location; -	unsigned		vram_size; +	/* for some chips with <= 32MB we need to lie +	 * about vram size near mc fb location */ +	unsigned		mc_vram_size;  	unsigned		vram_width; +	unsigned		real_vram_size;  	int			vram_mtrr;  	bool			vram_is_ddr;  }; @@ -474,6 +496,39 @@ struct radeon_wb {  	uint64_t		gpu_addr;  }; +/** + * struct radeon_pm - power management datas + * @max_bandwidth:      maximum bandwidth the gpu has (MByte/s) + * @igp_sideport_mclk:  sideport memory clock Mhz (rs690,rs740,rs780,rs880) + * @igp_system_mclk:    system clock Mhz (rs690,rs740,rs780,rs880) + * @igp_ht_link_clk:    ht link clock Mhz (rs690,rs740,rs780,rs880) + * @igp_ht_link_width:  ht link width in bits (rs690,rs740,rs780,rs880) + * @k8_bandwidth:       k8 bandwidth the gpu has (MByte/s) (IGP) + * @sideport_bandwidth: sideport bandwidth the gpu has (MByte/s) (IGP) + * @ht_bandwidth:       ht bandwidth the gpu has (MByte/s) (IGP) + * @core_bandwidth:     core GPU bandwidth the gpu has (MByte/s) (IGP) + * @sclk:          	GPU clock Mhz (core bandwith depends of this clock) + * @needed_bandwidth:   current bandwidth needs + * + * It keeps track of various data needed to take powermanagement decision. + * Bandwith need is used to determine minimun clock of the GPU and memory. + * Equation between gpu/memory clock and available bandwidth is hw dependent + * (type of memory, bus size, efficiency, ...) + */ +struct radeon_pm { +	fixed20_12		max_bandwidth; +	fixed20_12		igp_sideport_mclk; +	fixed20_12		igp_system_mclk; +	fixed20_12		igp_ht_link_clk; +	fixed20_12		igp_ht_link_width; +	fixed20_12		k8_bandwidth; +	fixed20_12		sideport_bandwidth; +	fixed20_12		ht_bandwidth; +	fixed20_12		core_bandwidth; +	fixed20_12		sclk; +	fixed20_12		needed_bandwidth; +}; +  /*   * Benchmarking @@ -482,6 +537,12 @@ void radeon_benchmark(struct radeon_device *rdev);  /* + * Testing + */ +void radeon_test_moves(struct radeon_device *rdev); + + +/*   * Debugfs   */  int radeon_debugfs_add_files(struct radeon_device *rdev, @@ -514,6 +575,7 @@ struct radeon_asic {  	void (*ring_start)(struct radeon_device *rdev);  	int (*irq_set)(struct radeon_device *rdev);  	int (*irq_process)(struct radeon_device *rdev); +	u32 (*get_vblank_counter)(struct radeon_device *rdev, int crtc);  	void (*fence_ring_emit)(struct radeon_device *rdev, struct radeon_fence *fence);  	int (*cs_parse)(struct radeon_cs_parser *p);  	int (*copy_blit)(struct radeon_device *rdev, @@ -535,6 +597,11 @@ struct radeon_asic {  	void (*set_memory_clock)(struct radeon_device *rdev, uint32_t mem_clock);  	void (*set_pcie_lanes)(struct radeon_device *rdev, int lanes);  	void (*set_clock_gating)(struct radeon_device *rdev, int enable); +	int (*set_surface_reg)(struct radeon_device *rdev, int reg, +			       uint32_t tiling_flags, uint32_t pitch, +			       uint32_t offset, uint32_t obj_size); +	int (*clear_surface_reg)(struct radeon_device *rdev, int reg); +	void (*bandwidth_update)(struct radeon_device *rdev);  };  union radeon_asic_config { @@ -566,6 +633,10 @@ int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,  int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,  			      struct drm_file *filp);  int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); +int radeon_gem_set_tiling_ioctl(struct drm_device *dev, void *data, +				struct drm_file *filp); +int radeon_gem_get_tiling_ioctl(struct drm_device *dev, void *data, +				struct drm_file *filp);  /* @@ -594,17 +665,14 @@ struct radeon_device {  	struct radeon_object		*fbdev_robj;  	struct radeon_framebuffer	*fbdev_rfb;  	/* Register mmio */ -	unsigned long			rmmio_base; -	unsigned long			rmmio_size; +	resource_size_t			rmmio_base; +	resource_size_t			rmmio_size;  	void				*rmmio; -	radeon_rreg_t			mm_rreg; -	radeon_wreg_t			mm_wreg;  	radeon_rreg_t			mc_rreg;  	radeon_wreg_t			mc_wreg;  	radeon_rreg_t			pll_rreg;  	radeon_wreg_t			pll_wreg; -	radeon_rreg_t			pcie_rreg; -	radeon_wreg_t			pcie_wreg; +	uint32_t                        pcie_reg_mask;  	radeon_rreg_t			pciep_rreg;  	radeon_wreg_t			pciep_wreg;  	struct radeon_clock             clock; @@ -619,11 +687,14 @@ struct radeon_device {  	struct radeon_irq		irq;  	struct radeon_asic		*asic;  	struct radeon_gem		gem; +	struct radeon_pm		pm;  	struct mutex			cs_mutex;  	struct radeon_wb		wb;  	bool				gpu_lockup;  	bool				shutdown;  	bool				suspend; +	bool				need_dma32; +	struct radeon_surface_reg surface_regs[RADEON_GEM_MAX_SURFACES];  };  int radeon_device_init(struct radeon_device *rdev, @@ -633,22 +704,42 @@ int radeon_device_init(struct radeon_device *rdev,  void radeon_device_fini(struct radeon_device *rdev);  int radeon_gpu_wait_for_idle(struct radeon_device *rdev); +static inline uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg) +{ +	if (reg < 0x10000) +		return readl(((void __iomem *)rdev->rmmio) + reg); +	else { +		writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); +		return readl(((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); +	} +} + +static inline void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) +{ +	if (reg < 0x10000) +		writel(v, ((void __iomem *)rdev->rmmio) + reg); +	else { +		writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); +		writel(v, ((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); +	} +} +  /*   * Registers read & write functions.   */  #define RREG8(reg) readb(((void __iomem *)rdev->rmmio) + (reg))  #define WREG8(reg, v) writeb(v, ((void __iomem *)rdev->rmmio) + (reg)) -#define RREG32(reg) rdev->mm_rreg(rdev, (reg)) -#define WREG32(reg, v) rdev->mm_wreg(rdev, (reg), (v)) +#define RREG32(reg) r100_mm_rreg(rdev, (reg)) +#define WREG32(reg, v) r100_mm_wreg(rdev, (reg), (v))  #define REG_SET(FIELD, v) (((v) << FIELD##_SHIFT) & FIELD##_MASK)  #define REG_GET(FIELD, v) (((v) << FIELD##_SHIFT) & FIELD##_MASK)  #define RREG32_PLL(reg) rdev->pll_rreg(rdev, (reg))  #define WREG32_PLL(reg, v) rdev->pll_wreg(rdev, (reg), (v))  #define RREG32_MC(reg) rdev->mc_rreg(rdev, (reg))  #define WREG32_MC(reg, v) rdev->mc_wreg(rdev, (reg), (v)) -#define RREG32_PCIE(reg) rdev->pcie_rreg(rdev, (reg)) -#define WREG32_PCIE(reg, v) rdev->pcie_wreg(rdev, (reg), (v)) +#define RREG32_PCIE(reg) rv370_pcie_rreg(rdev, (reg)) +#define WREG32_PCIE(reg, v) rv370_pcie_wreg(rdev, (reg), (v))  #define WREG32_P(reg, val, mask)				\  	do {							\  		uint32_t tmp_ = RREG32(reg);			\ @@ -664,12 +755,32 @@ int radeon_gpu_wait_for_idle(struct radeon_device *rdev);  		WREG32_PLL(reg, tmp_);				\  	} while (0) +/* + * Indirect registers accessor + */ +static inline uint32_t rv370_pcie_rreg(struct radeon_device *rdev, uint32_t reg) +{ +	uint32_t r; + +	WREG32(RADEON_PCIE_INDEX, ((reg) & rdev->pcie_reg_mask)); +	r = RREG32(RADEON_PCIE_DATA); +	return r; +} + +static inline void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) +{ +	WREG32(RADEON_PCIE_INDEX, ((reg) & rdev->pcie_reg_mask)); +	WREG32(RADEON_PCIE_DATA, (v)); +} +  void r100_pll_errata_after_index(struct radeon_device *rdev);  /*   * ASICs helpers.   */ +#define ASIC_IS_RN50(rdev) ((rdev->pdev->device == 0x515e) || \ +			    (rdev->pdev->device == 0x5969))  #define ASIC_IS_RV100(rdev) ((rdev->family == CHIP_RV100) || \  		(rdev->family == CHIP_RV200) || \  		(rdev->family == CHIP_RS100) || \ @@ -788,6 +899,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v)  #define radeon_ring_start(rdev) (rdev)->asic->ring_start((rdev))  #define radeon_irq_set(rdev) (rdev)->asic->irq_set((rdev))  #define radeon_irq_process(rdev) (rdev)->asic->irq_process((rdev)) +#define radeon_get_vblank_counter(rdev, crtc) (rdev)->asic->get_vblank_counter((rdev), (crtc))  #define radeon_fence_ring_emit(rdev, fence) (rdev)->asic->fence_ring_emit((rdev), (fence))  #define radeon_copy_blit(rdev, s, d, np, f) (rdev)->asic->copy_blit((rdev), (s), (d), (np), (f))  #define radeon_copy_dma(rdev, s, d, np, f) (rdev)->asic->copy_dma((rdev), (s), (d), (np), (f)) @@ -796,5 +908,8 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v)  #define radeon_set_memory_clock(rdev, e) (rdev)->asic->set_engine_clock((rdev), (e))  #define radeon_set_pcie_lanes(rdev, l) (rdev)->asic->set_pcie_lanes((rdev), (l))  #define radeon_set_clock_gating(rdev, e) (rdev)->asic->set_clock_gating((rdev), (e)) +#define radeon_set_surface_reg(rdev, r, f, p, o, s) ((rdev)->asic->set_surface_reg((rdev), (r), (f), (p), (o), (s))) +#define radeon_clear_surface_reg(rdev, r) ((rdev)->asic->clear_surface_reg((rdev), (r))) +#define radeon_bandwidth_update(rdev) (rdev)->asic->bandwidth_update((rdev))  #endif diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index e2e567395df..7ca6c13569b 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -49,6 +49,7 @@ void r100_vram_info(struct radeon_device *rdev);  int r100_gpu_reset(struct radeon_device *rdev);  int r100_mc_init(struct radeon_device *rdev);  void r100_mc_fini(struct radeon_device *rdev); +u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc);  int r100_wb_init(struct radeon_device *rdev);  void r100_wb_fini(struct radeon_device *rdev);  int r100_gart_enable(struct radeon_device *rdev); @@ -71,6 +72,11 @@ int r100_copy_blit(struct radeon_device *rdev,  		   uint64_t dst_offset,  		   unsigned num_pages,  		   struct radeon_fence *fence); +int r100_set_surface_reg(struct radeon_device *rdev, int reg, +			 uint32_t tiling_flags, uint32_t pitch, +			 uint32_t offset, uint32_t obj_size); +int r100_clear_surface_reg(struct radeon_device *rdev, int reg); +void r100_bandwidth_update(struct radeon_device *rdev);  static struct radeon_asic r100_asic = {  	.init = &r100_init, @@ -91,6 +97,7 @@ static struct radeon_asic r100_asic = {  	.ring_start = &r100_ring_start,  	.irq_set = &r100_irq_set,  	.irq_process = &r100_irq_process, +	.get_vblank_counter = &r100_get_vblank_counter,  	.fence_ring_emit = &r100_fence_ring_emit,  	.cs_parse = &r100_cs_parse,  	.copy_blit = &r100_copy_blit, @@ -100,6 +107,9 @@ static struct radeon_asic r100_asic = {  	.set_memory_clock = NULL,  	.set_pcie_lanes = NULL,  	.set_clock_gating = &radeon_legacy_set_clock_gating, +	.set_surface_reg = r100_set_surface_reg, +	.clear_surface_reg = r100_clear_surface_reg, +	.bandwidth_update = &r100_bandwidth_update,  }; @@ -128,6 +138,7 @@ int r300_copy_dma(struct radeon_device *rdev,  		  uint64_t dst_offset,  		  unsigned num_pages,  		  struct radeon_fence *fence); +  static struct radeon_asic r300_asic = {  	.init = &r300_init,  	.errata = &r300_errata, @@ -147,6 +158,7 @@ static struct radeon_asic r300_asic = {  	.ring_start = &r300_ring_start,  	.irq_set = &r100_irq_set,  	.irq_process = &r100_irq_process, +	.get_vblank_counter = &r100_get_vblank_counter,  	.fence_ring_emit = &r300_fence_ring_emit,  	.cs_parse = &r300_cs_parse,  	.copy_blit = &r100_copy_blit, @@ -156,6 +168,9 @@ static struct radeon_asic r300_asic = {  	.set_memory_clock = NULL,  	.set_pcie_lanes = &rv370_set_pcie_lanes,  	.set_clock_gating = &radeon_legacy_set_clock_gating, +	.set_surface_reg = r100_set_surface_reg, +	.clear_surface_reg = r100_clear_surface_reg, +	.bandwidth_update = &r100_bandwidth_update,  };  /* @@ -184,6 +199,7 @@ static struct radeon_asic r420_asic = {  	.ring_start = &r300_ring_start,  	.irq_set = &r100_irq_set,  	.irq_process = &r100_irq_process, +	.get_vblank_counter = &r100_get_vblank_counter,  	.fence_ring_emit = &r300_fence_ring_emit,  	.cs_parse = &r300_cs_parse,  	.copy_blit = &r100_copy_blit, @@ -193,6 +209,9 @@ static struct radeon_asic r420_asic = {  	.set_memory_clock = &radeon_atom_set_memory_clock,  	.set_pcie_lanes = &rv370_set_pcie_lanes,  	.set_clock_gating = &radeon_atom_set_clock_gating, +	.set_surface_reg = r100_set_surface_reg, +	.clear_surface_reg = r100_clear_surface_reg, +	.bandwidth_update = &r100_bandwidth_update,  }; @@ -228,6 +247,7 @@ static struct radeon_asic rs400_asic = {  	.ring_start = &r300_ring_start,  	.irq_set = &r100_irq_set,  	.irq_process = &r100_irq_process, +	.get_vblank_counter = &r100_get_vblank_counter,  	.fence_ring_emit = &r300_fence_ring_emit,  	.cs_parse = &r300_cs_parse,  	.copy_blit = &r100_copy_blit, @@ -237,6 +257,9 @@ static struct radeon_asic rs400_asic = {  	.set_memory_clock = NULL,  	.set_pcie_lanes = NULL,  	.set_clock_gating = &radeon_legacy_set_clock_gating, +	.set_surface_reg = r100_set_surface_reg, +	.clear_surface_reg = r100_clear_surface_reg, +	.bandwidth_update = &r100_bandwidth_update,  }; @@ -248,12 +271,15 @@ void rs600_vram_info(struct radeon_device *rdev);  int rs600_mc_init(struct radeon_device *rdev);  void rs600_mc_fini(struct radeon_device *rdev);  int rs600_irq_set(struct radeon_device *rdev); +int rs600_irq_process(struct radeon_device *rdev); +u32 rs600_get_vblank_counter(struct radeon_device *rdev, int crtc);  int rs600_gart_enable(struct radeon_device *rdev);  void rs600_gart_disable(struct radeon_device *rdev);  void rs600_gart_tlb_flush(struct radeon_device *rdev);  int rs600_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr);  uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg);  void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); +void rs600_bandwidth_update(struct radeon_device *rdev);  static struct radeon_asic rs600_asic = {  	.init = &r300_init,  	.errata = &rs600_errata, @@ -272,7 +298,8 @@ static struct radeon_asic rs600_asic = {  	.cp_disable = &r100_cp_disable,  	.ring_start = &r300_ring_start,  	.irq_set = &rs600_irq_set, -	.irq_process = &r100_irq_process, +	.irq_process = &rs600_irq_process, +	.get_vblank_counter = &rs600_get_vblank_counter,  	.fence_ring_emit = &r300_fence_ring_emit,  	.cs_parse = &r300_cs_parse,  	.copy_blit = &r100_copy_blit, @@ -282,20 +309,23 @@ static struct radeon_asic rs600_asic = {  	.set_memory_clock = &radeon_atom_set_memory_clock,  	.set_pcie_lanes = NULL,  	.set_clock_gating = &radeon_atom_set_clock_gating, +	.bandwidth_update = &rs600_bandwidth_update,  };  /*   * rs690,rs740   */ +int rs690_init(struct radeon_device *rdev);  void rs690_errata(struct radeon_device *rdev);  void rs690_vram_info(struct radeon_device *rdev);  int rs690_mc_init(struct radeon_device *rdev);  void rs690_mc_fini(struct radeon_device *rdev);  uint32_t rs690_mc_rreg(struct radeon_device *rdev, uint32_t reg);  void rs690_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); +void rs690_bandwidth_update(struct radeon_device *rdev);  static struct radeon_asic rs690_asic = { -	.init = &r300_init, +	.init = &rs690_init,  	.errata = &rs690_errata,  	.vram_info = &rs690_vram_info,  	.gpu_reset = &r300_gpu_reset, @@ -312,7 +342,8 @@ static struct radeon_asic rs690_asic = {  	.cp_disable = &r100_cp_disable,  	.ring_start = &r300_ring_start,  	.irq_set = &rs600_irq_set, -	.irq_process = &r100_irq_process, +	.irq_process = &rs600_irq_process, +	.get_vblank_counter = &rs600_get_vblank_counter,  	.fence_ring_emit = &r300_fence_ring_emit,  	.cs_parse = &r300_cs_parse,  	.copy_blit = &r100_copy_blit, @@ -322,6 +353,9 @@ static struct radeon_asic rs690_asic = {  	.set_memory_clock = &radeon_atom_set_memory_clock,  	.set_pcie_lanes = NULL,  	.set_clock_gating = &radeon_atom_set_clock_gating, +	.set_surface_reg = r100_set_surface_reg, +	.clear_surface_reg = r100_clear_surface_reg, +	.bandwidth_update = &rs690_bandwidth_update,  }; @@ -339,6 +373,7 @@ void rv515_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);  void rv515_ring_start(struct radeon_device *rdev);  uint32_t rv515_pcie_rreg(struct radeon_device *rdev, uint32_t reg);  void rv515_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); +void rv515_bandwidth_update(struct radeon_device *rdev);  static struct radeon_asic rv515_asic = {  	.init = &rv515_init,  	.errata = &rv515_errata, @@ -356,8 +391,9 @@ static struct radeon_asic rv515_asic = {  	.cp_fini = &r100_cp_fini,  	.cp_disable = &r100_cp_disable,  	.ring_start = &rv515_ring_start, -	.irq_set = &r100_irq_set, -	.irq_process = &r100_irq_process, +	.irq_set = &rs600_irq_set, +	.irq_process = &rs600_irq_process, +	.get_vblank_counter = &rs600_get_vblank_counter,  	.fence_ring_emit = &r300_fence_ring_emit,  	.cs_parse = &r300_cs_parse,  	.copy_blit = &r100_copy_blit, @@ -367,6 +403,9 @@ static struct radeon_asic rv515_asic = {  	.set_memory_clock = &radeon_atom_set_memory_clock,  	.set_pcie_lanes = &rv370_set_pcie_lanes,  	.set_clock_gating = &radeon_atom_set_clock_gating, +	.set_surface_reg = r100_set_surface_reg, +	.clear_surface_reg = r100_clear_surface_reg, +	.bandwidth_update = &rv515_bandwidth_update,  }; @@ -377,6 +416,7 @@ void r520_errata(struct radeon_device *rdev);  void r520_vram_info(struct radeon_device *rdev);  int r520_mc_init(struct radeon_device *rdev);  void r520_mc_fini(struct radeon_device *rdev); +void r520_bandwidth_update(struct radeon_device *rdev);  static struct radeon_asic r520_asic = {  	.init = &rv515_init,  	.errata = &r520_errata, @@ -394,8 +434,9 @@ static struct radeon_asic r520_asic = {  	.cp_fini = &r100_cp_fini,  	.cp_disable = &r100_cp_disable,  	.ring_start = &rv515_ring_start, -	.irq_set = &r100_irq_set, -	.irq_process = &r100_irq_process, +	.irq_set = &rs600_irq_set, +	.irq_process = &rs600_irq_process, +	.get_vblank_counter = &rs600_get_vblank_counter,  	.fence_ring_emit = &r300_fence_ring_emit,  	.cs_parse = &r300_cs_parse,  	.copy_blit = &r100_copy_blit, @@ -405,6 +446,9 @@ static struct radeon_asic r520_asic = {  	.set_memory_clock = &radeon_atom_set_memory_clock,  	.set_pcie_lanes = &rv370_set_pcie_lanes,  	.set_clock_gating = &radeon_atom_set_clock_gating, +	.set_surface_reg = r100_set_surface_reg, +	.clear_surface_reg = r100_clear_surface_reg, +	.bandwidth_update = &r520_bandwidth_update,  };  /* diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 1f5a1a49098..fcfe5c02d74 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -103,7 +103,8 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_gpio(struct drm_device  static bool radeon_atom_apply_quirks(struct drm_device *dev,  				     uint32_t supported_device,  				     int *connector_type, -				     struct radeon_i2c_bus_rec *i2c_bus) +				     struct radeon_i2c_bus_rec *i2c_bus, +				     uint8_t *line_mux)  {  	/* Asus M2A-VM HDMI board lists the DVI port as HDMI */ @@ -127,8 +128,10 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,  	if ((dev->pdev->device == 0x5653) &&  	    (dev->pdev->subsystem_vendor == 0x1462) &&  	    (dev->pdev->subsystem_device == 0x0291)) { -		if (*connector_type == DRM_MODE_CONNECTOR_LVDS) +		if (*connector_type == DRM_MODE_CONNECTOR_LVDS) {  			i2c_bus->valid = false; +			*line_mux = 53; +		}  	}  	/* Funky macbooks */ @@ -526,7 +529,7 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct  		if (!radeon_atom_apply_quirks  		    (dev, (1 << i), &bios_connectors[i].connector_type, -		     &bios_connectors[i].ddc_bus)) +		     &bios_connectors[i].ddc_bus, &bios_connectors[i].line_mux))  			continue;  		bios_connectors[i].valid = true; diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c index c44403a2ca7..2e938f7496f 100644 --- a/drivers/gpu/drm/radeon/radeon_benchmark.c +++ b/drivers/gpu/drm/radeon/radeon_benchmark.c @@ -63,7 +63,7 @@ void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize,  		if (r) {  			goto out_cleanup;  		} -		r = radeon_copy_dma(rdev, saddr, daddr, size >> 14, fence); +		r = radeon_copy_dma(rdev, saddr, daddr, size / 4096, fence);  		if (r) {  			goto out_cleanup;  		} @@ -88,7 +88,7 @@ void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize,  		if (r) {  			goto out_cleanup;  		} -		r = radeon_copy_blit(rdev, saddr, daddr, size >> 14, fence); +		r = radeon_copy_blit(rdev, saddr, daddr, size / 4096, fence);  		if (r) {  			goto out_cleanup;  		} diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index afc4db280b9..2a027e00762 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -685,23 +685,15 @@ static const uint32_t default_tvdac_adj[CHIP_LAST] = {  	0x00780000,		/* rs480 */  }; -static struct radeon_encoder_tv_dac -    *radeon_legacy_get_tv_dac_info_from_table(struct radeon_device *rdev) +static void radeon_legacy_get_tv_dac_info_from_table(struct radeon_device *rdev, +						     struct radeon_encoder_tv_dac *tv_dac)  { -	struct radeon_encoder_tv_dac *tv_dac = NULL; - -	tv_dac = kzalloc(sizeof(struct radeon_encoder_tv_dac), GFP_KERNEL); - -	if (!tv_dac) -		return NULL; -  	tv_dac->ps2_tvdac_adj = default_tvdac_adj[rdev->family];  	if ((rdev->flags & RADEON_IS_MOBILITY) && (rdev->family == CHIP_RV250))  		tv_dac->ps2_tvdac_adj = 0x00880000;  	tv_dac->pal_tvdac_adj = tv_dac->ps2_tvdac_adj;  	tv_dac->ntsc_tvdac_adj = tv_dac->ps2_tvdac_adj; - -	return tv_dac; +	return;  }  struct radeon_encoder_tv_dac *radeon_combios_get_tv_dac_info(struct @@ -713,19 +705,18 @@ struct radeon_encoder_tv_dac *radeon_combios_get_tv_dac_info(struct  	uint16_t dac_info;  	uint8_t rev, bg, dac;  	struct radeon_encoder_tv_dac *tv_dac = NULL; +	int found = 0; + +	tv_dac = kzalloc(sizeof(struct radeon_encoder_tv_dac), GFP_KERNEL); +	if (!tv_dac) +		return NULL;  	if (rdev->bios == NULL) -		return radeon_legacy_get_tv_dac_info_from_table(rdev); +		goto out;  	/* first check TV table */  	dac_info = combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE);  	if (dac_info) { -		tv_dac = -		    kzalloc(sizeof(struct radeon_encoder_tv_dac), GFP_KERNEL); - -		if (!tv_dac) -			return NULL; -  		rev = RBIOS8(dac_info + 0x3);  		if (rev > 4) {  			bg = RBIOS8(dac_info + 0xc) & 0xf; @@ -739,6 +730,7 @@ struct radeon_encoder_tv_dac *radeon_combios_get_tv_dac_info(struct  			bg = RBIOS8(dac_info + 0x10) & 0xf;  			dac = RBIOS8(dac_info + 0x11) & 0xf;  			tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20); +			found = 1;  		} else if (rev > 1) {  			bg = RBIOS8(dac_info + 0xc) & 0xf;  			dac = (RBIOS8(dac_info + 0xc) >> 4) & 0xf; @@ -751,22 +743,15 @@ struct radeon_encoder_tv_dac *radeon_combios_get_tv_dac_info(struct  			bg = RBIOS8(dac_info + 0xe) & 0xf;  			dac = (RBIOS8(dac_info + 0xe) >> 4) & 0xf;  			tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20); +			found = 1;  		} -  		tv_dac->tv_std = radeon_combios_get_tv_info(encoder); - -	} else { +	} +	if (!found) {  		/* then check CRT table */  		dac_info =  		    combios_get_table_offset(dev, COMBIOS_CRT_INFO_TABLE);  		if (dac_info) { -			tv_dac = -			    kzalloc(sizeof(struct radeon_encoder_tv_dac), -				    GFP_KERNEL); - -			if (!tv_dac) -				return NULL; -  			rev = RBIOS8(dac_info) & 0x3;  			if (rev < 2) {  				bg = RBIOS8(dac_info + 0x3) & 0xf; @@ -775,6 +760,7 @@ struct radeon_encoder_tv_dac *radeon_combios_get_tv_dac_info(struct  				    (bg << 16) | (dac << 20);  				tv_dac->pal_tvdac_adj = tv_dac->ps2_tvdac_adj;  				tv_dac->ntsc_tvdac_adj = tv_dac->ps2_tvdac_adj; +				found = 1;  			} else {  				bg = RBIOS8(dac_info + 0x4) & 0xf;  				dac = RBIOS8(dac_info + 0x5) & 0xf; @@ -782,13 +768,17 @@ struct radeon_encoder_tv_dac *radeon_combios_get_tv_dac_info(struct  				    (bg << 16) | (dac << 20);  				tv_dac->pal_tvdac_adj = tv_dac->ps2_tvdac_adj;  				tv_dac->ntsc_tvdac_adj = tv_dac->ps2_tvdac_adj; +				found = 1;  			}  		} else {  			DRM_INFO("No TV DAC info found in BIOS\n"); -			return radeon_legacy_get_tv_dac_info_from_table(rdev);  		}  	} +out: +	if (!found) /* fallback to defaults */ +		radeon_legacy_get_tv_dac_info_from_table(rdev, tv_dac); +  	return tv_dac;  } diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index b843f9bdfb1..a169067efc4 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -127,17 +127,23 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)  				       sizeof(struct drm_radeon_cs_chunk))) {  			return -EFAULT;  		} +		p->chunks[i].length_dw = user_chunk.length_dw; +		p->chunks[i].kdata = NULL;  		p->chunks[i].chunk_id = user_chunk.chunk_id; +  		if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_RELOCS) {  			p->chunk_relocs_idx = i;  		}  		if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_IB) {  			p->chunk_ib_idx = i; +			/* zero length IB isn't useful */ +			if (p->chunks[i].length_dw == 0) +				return -EINVAL;  		} +  		p->chunks[i].length_dw = user_chunk.length_dw;  		cdata = (uint32_t *)(unsigned long)user_chunk.chunk_data; -		p->chunks[i].kdata = NULL;  		size = p->chunks[i].length_dw * sizeof(uint32_t);  		p->chunks[i].kdata = kzalloc(size, GFP_KERNEL);  		if (p->chunks[i].kdata == NULL) { diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index 5232441f119..b13c79e38bc 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -111,9 +111,11 @@ static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj,  	if (ASIC_IS_AVIVO(rdev))  		WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, gpu_addr); -	else +	else { +		radeon_crtc->legacy_cursor_offset = gpu_addr - radeon_crtc->legacy_display_base_addr;  		/* offset is from DISP(2)_BASE_ADDRESS */ -		WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, gpu_addr); +		WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, radeon_crtc->legacy_cursor_offset); +	}  }  int radeon_crtc_cursor_set(struct drm_crtc *crtc, @@ -245,6 +247,9 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,  		       (RADEON_CUR_LOCK  			| ((xorigin ? 0 : x) << 16)  			| (yorigin ? 0 : y))); +		/* offset is from DISP(2)_BASE_ADDRESS */ +		WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset + +								      (yorigin * 256)));  	}  	radeon_lock_cursor(crtc, false); diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index f97563db4e5..7693f7c67bd 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -48,6 +48,8 @@ static void radeon_surface_init(struct radeon_device *rdev)  			       i * (RADEON_SURFACE1_INFO - RADEON_SURFACE0_INFO),  			       0);  		} +		/* enable surfaces */ +		WREG32(RADEON_SURFACE_CNTL, 0);  	}  } @@ -119,7 +121,7 @@ int radeon_mc_setup(struct radeon_device *rdev)  	if (rdev->mc.vram_location != 0xFFFFFFFFUL) {  		/* vram location was already setup try to put gtt after  		 * if it fits */ -		tmp = rdev->mc.vram_location + rdev->mc.vram_size; +		tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size;  		tmp = (tmp + rdev->mc.gtt_size - 1) & ~(rdev->mc.gtt_size - 1);  		if ((0xFFFFFFFFUL - tmp) >= rdev->mc.gtt_size) {  			rdev->mc.gtt_location = tmp; @@ -134,13 +136,13 @@ int radeon_mc_setup(struct radeon_device *rdev)  	} else if (rdev->mc.gtt_location != 0xFFFFFFFFUL) {  		/* gtt location was already setup try to put vram before  		 * if it fits */ -		if (rdev->mc.vram_size < rdev->mc.gtt_location) { +		if (rdev->mc.mc_vram_size < rdev->mc.gtt_location) {  			rdev->mc.vram_location = 0;  		} else {  			tmp = rdev->mc.gtt_location + rdev->mc.gtt_size; -			tmp += (rdev->mc.vram_size - 1); -			tmp &= ~(rdev->mc.vram_size - 1); -			if ((0xFFFFFFFFUL - tmp) >= rdev->mc.vram_size) { +			tmp += (rdev->mc.mc_vram_size - 1); +			tmp &= ~(rdev->mc.mc_vram_size - 1); +			if ((0xFFFFFFFFUL - tmp) >= rdev->mc.mc_vram_size) {  				rdev->mc.vram_location = tmp;  			} else {  				printk(KERN_ERR "[drm] vram too big to fit " @@ -150,12 +152,16 @@ int radeon_mc_setup(struct radeon_device *rdev)  		}  	} else {  		rdev->mc.vram_location = 0; -		rdev->mc.gtt_location = rdev->mc.vram_size; +		tmp = rdev->mc.mc_vram_size; +		tmp = (tmp + rdev->mc.gtt_size - 1) & ~(rdev->mc.gtt_size - 1); +		rdev->mc.gtt_location = tmp;  	} -	DRM_INFO("radeon: VRAM %uM\n", rdev->mc.vram_size >> 20); +	DRM_INFO("radeon: VRAM %uM\n", rdev->mc.real_vram_size >> 20);  	DRM_INFO("radeon: VRAM from 0x%08X to 0x%08X\n",  		 rdev->mc.vram_location, -		 rdev->mc.vram_location + rdev->mc.vram_size - 1); +		 rdev->mc.vram_location + rdev->mc.mc_vram_size - 1); +	if (rdev->mc.real_vram_size != rdev->mc.mc_vram_size) +		DRM_INFO("radeon: VRAM less than aperture workaround enabled\n");  	DRM_INFO("radeon: GTT %uM\n", rdev->mc.gtt_size >> 20);  	DRM_INFO("radeon: GTT from 0x%08X to 0x%08X\n",  		 rdev->mc.gtt_location, @@ -219,25 +225,18 @@ void radeon_invalid_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)  void radeon_register_accessor_init(struct radeon_device *rdev)  { -	rdev->mm_rreg = &r100_mm_rreg; -	rdev->mm_wreg = &r100_mm_wreg;  	rdev->mc_rreg = &radeon_invalid_rreg;  	rdev->mc_wreg = &radeon_invalid_wreg;  	rdev->pll_rreg = &radeon_invalid_rreg;  	rdev->pll_wreg = &radeon_invalid_wreg; -	rdev->pcie_rreg = &radeon_invalid_rreg; -	rdev->pcie_wreg = &radeon_invalid_wreg;  	rdev->pciep_rreg = &radeon_invalid_rreg;  	rdev->pciep_wreg = &radeon_invalid_wreg;  	/* Don't change order as we are overridding accessor. */  	if (rdev->family < CHIP_RV515) { -		rdev->pcie_rreg = &rv370_pcie_rreg; -		rdev->pcie_wreg = &rv370_pcie_wreg; -	} -	if (rdev->family >= CHIP_RV515) { -		rdev->pcie_rreg = &rv515_pcie_rreg; -		rdev->pcie_wreg = &rv515_pcie_wreg; +		rdev->pcie_reg_mask = 0xff; +	} else { +		rdev->pcie_reg_mask = 0x7ff;  	}  	/* FIXME: not sure here */  	if (rdev->family <= CHIP_R580) { @@ -450,6 +449,7 @@ int radeon_device_init(struct radeon_device *rdev,  		       uint32_t flags)  {  	int r, ret; +	int dma_bits;  	DRM_INFO("radeon: Initializing kernel modesetting.\n");  	rdev->shutdown = false; @@ -492,8 +492,20 @@ int radeon_device_init(struct radeon_device *rdev,  		return r;  	} -	/* Report DMA addressing limitation */ -	r = pci_set_dma_mask(rdev->pdev, DMA_BIT_MASK(32)); +	/* set DMA mask + need_dma32 flags. +	 * PCIE - can handle 40-bits. +	 * IGP - can handle 40-bits (in theory) +	 * AGP - generally dma32 is safest +	 * PCI - only dma32 +	 */ +	rdev->need_dma32 = false; +	if (rdev->flags & RADEON_IS_AGP) +		rdev->need_dma32 = true; +	if (rdev->flags & RADEON_IS_PCI) +		rdev->need_dma32 = true; + +	dma_bits = rdev->need_dma32 ? 32 : 40; +	r = pci_set_dma_mask(rdev->pdev, DMA_BIT_MASK(dma_bits));  	if (r) {  		printk(KERN_WARNING "radeon: No suitable DMA available.\n");  	} @@ -546,27 +558,22 @@ int radeon_device_init(struct radeon_device *rdev,  			radeon_combios_asic_init(rdev->ddev);  		}  	} +	/* Initialize clocks */ +	r = radeon_clocks_init(rdev); +	if (r) { +		return r; +	}  	/* Get vram informations */  	radeon_vram_info(rdev); -	/* Device is severly broken if aper size > vram size. -	 * for RN50/M6/M7 - Novell bug 204882 ? -	 */ -	if (rdev->mc.vram_size < rdev->mc.aper_size) { -		rdev->mc.aper_size = rdev->mc.vram_size; -	} +  	/* Add an MTRR for the VRAM */  	rdev->mc.vram_mtrr = mtrr_add(rdev->mc.aper_base, rdev->mc.aper_size,  				      MTRR_TYPE_WRCOMB, 1);  	DRM_INFO("Detected VRAM RAM=%uM, BAR=%uM\n", -		 rdev->mc.vram_size >> 20, +		 rdev->mc.real_vram_size >> 20,  		 (unsigned)rdev->mc.aper_size >> 20);  	DRM_INFO("RAM width %dbits %cDR\n",  		 rdev->mc.vram_width, rdev->mc.vram_is_ddr ? 'D' : 'S'); -	/* Initialize clocks */ -	r = radeon_clocks_init(rdev); -	if (r) { -		return r; -	}  	/* Initialize memory controller (also test AGP) */  	r = radeon_mc_init(rdev);  	if (r) { @@ -626,6 +633,9 @@ int radeon_device_init(struct radeon_device *rdev,  	if (!ret) {  		DRM_INFO("radeon: kernel modesetting successfully initialized.\n");  	} +	if (radeon_testing) { +		radeon_test_moves(rdev); +	}  	if (radeon_benchmarking) {  		radeon_benchmark(rdev);  	} diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 3efcf1a526b..a8fa1bb84cf 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -187,6 +187,7 @@ static void radeon_crtc_init(struct drm_device *dev, int index)  	drm_mode_crtc_set_gamma_size(&radeon_crtc->base, 256);  	radeon_crtc->crtc_id = index; +	rdev->mode_info.crtcs[index] = radeon_crtc;  	radeon_crtc->mode_set.crtc = &radeon_crtc->base;  	radeon_crtc->mode_set.connectors = (struct drm_connector **)(radeon_crtc + 1); @@ -491,7 +492,11 @@ void radeon_compute_pll(struct radeon_pll *pll,  					tmp += (uint64_t)pll->reference_freq * 1000 * frac_feedback_div;  					current_freq = radeon_div(tmp, ref_div * post_div); -					error = abs(current_freq - freq); +					if (flags & RADEON_PLL_PREFER_CLOSEST_LOWER) { +						error = freq - current_freq; +						error = error < 0 ? 0xffffffff : error; +					} else +						error = abs(current_freq - freq);  					vco_diff = abs(vco - best_vco);  					if ((best_vco == 0 && error < best_error) || @@ -657,36 +662,51 @@ void radeon_modeset_fini(struct radeon_device *rdev)  	}  } -void radeon_init_disp_bandwidth(struct drm_device *dev) +bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, +				struct drm_display_mode *mode, +				struct drm_display_mode *adjusted_mode)  { -	struct radeon_device *rdev = dev->dev_private; -	struct drm_display_mode *modes[2]; -	int pixel_bytes[2]; -	struct drm_crtc *crtc; - -	pixel_bytes[0] = pixel_bytes[1] = 0; -	modes[0] = modes[1] = NULL; - -	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { -		struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); +	struct drm_device *dev = crtc->dev; +	struct drm_encoder *encoder; +	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); +	struct radeon_encoder *radeon_encoder; +	bool first = true; -		if (crtc->enabled && crtc->fb) { -			modes[radeon_crtc->crtc_id] = &crtc->mode; -			pixel_bytes[radeon_crtc->crtc_id] = crtc->fb->bits_per_pixel / 8; +	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { +		radeon_encoder = to_radeon_encoder(encoder); +		if (encoder->crtc != crtc) +			continue; +		if (first) { +			radeon_crtc->rmx_type = radeon_encoder->rmx_type; +			radeon_crtc->devices = radeon_encoder->devices; +			memcpy(&radeon_crtc->native_mode, +				&radeon_encoder->native_mode, +				sizeof(struct radeon_native_mode)); +			first = false; +		} else { +			if (radeon_crtc->rmx_type != radeon_encoder->rmx_type) { +				/* WARNING: Right now this can't happen but +				 * in the future we need to check that scaling +				 * are consistent accross different encoder +				 * (ie all encoder can work with the same +				 *  scaling). +				 */ +				DRM_ERROR("Scaling not consistent accross encoder.\n"); +				return false; +			}  		}  	} - -	if (ASIC_IS_AVIVO(rdev)) { -		radeon_init_disp_bw_avivo(dev, -					  modes[0], -					  pixel_bytes[0], -					  modes[1], -					  pixel_bytes[1]); +	if (radeon_crtc->rmx_type != RMX_OFF) { +		fixed20_12 a, b; +		a.full = rfixed_const(crtc->mode.vdisplay); +		b.full = rfixed_const(radeon_crtc->native_mode.panel_xres); +		radeon_crtc->vsc.full = rfixed_div(a, b); +		a.full = rfixed_const(crtc->mode.hdisplay); +		b.full = rfixed_const(radeon_crtc->native_mode.panel_yres); +		radeon_crtc->hsc.full = rfixed_div(a, b);  	} else { -		radeon_init_disp_bw_legacy(dev, -					   modes[0], -					   pixel_bytes[0], -					   modes[1], -					   pixel_bytes[1]); +		radeon_crtc->vsc.full = rfixed_const(1); +		radeon_crtc->hsc.full = rfixed_const(1);  	} +	return true;  } diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 84ba69f4878..0bd5879a495 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -89,6 +89,7 @@ int radeon_agpmode = 0;  int radeon_vram_limit = 0;  int radeon_gart_size = 512; /* default gart size */  int radeon_benchmarking = 0; +int radeon_testing = 0;  int radeon_connector_table = 0;  #endif @@ -117,6 +118,9 @@ module_param_named(gartsize, radeon_gart_size, int, 0600);  MODULE_PARM_DESC(benchmark, "Run benchmark");  module_param_named(benchmark, radeon_benchmarking, int, 0444); +MODULE_PARM_DESC(test, "Run tests"); +module_param_named(test, radeon_testing, int, 0444); +  MODULE_PARM_DESC(connector_table, "Force connector table");  module_param_named(connector_table, radeon_connector_table, int, 0444);  #endif @@ -314,6 +318,14 @@ static int __init radeon_init(void)  	driver = &driver_old;  	driver->num_ioctls = radeon_max_ioctl;  #if defined(CONFIG_DRM_RADEON_KMS) +#ifdef CONFIG_VGA_CONSOLE +	if (vgacon_text_force() && radeon_modeset == -1) { +		DRM_INFO("VGACON disable radeon kernel modesetting.\n"); +		driver = &driver_old; +		driver->driver_features &= ~DRIVER_MODESET; +		radeon_modeset = 0; +	} +#endif  	/* if enabled by default */  	if (radeon_modeset == -1) {  		DRM_INFO("radeon default to kernel modesetting.\n"); @@ -325,17 +337,8 @@ static int __init radeon_init(void)  		driver->driver_features |= DRIVER_MODESET;  		driver->num_ioctls = radeon_max_kms_ioctl;  	} -  	/* if the vga console setting is enabled still  	 * let modprobe override it */ -#ifdef CONFIG_VGA_CONSOLE -	if (vgacon_text_force() && radeon_modeset == -1) { -		DRM_INFO("VGACON disable radeon kernel modesetting.\n"); -		driver = &driver_old; -		driver->driver_features &= ~DRIVER_MODESET; -		radeon_modeset = 0; -	} -#endif  #endif  	return drm_init(driver);  } diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h index 127d0456f62..3933f8216a3 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.h +++ b/drivers/gpu/drm/radeon/radeon_drv.h @@ -143,6 +143,7 @@ enum radeon_family {  	CHIP_RV635,  	CHIP_RV670,  	CHIP_RS780, +	CHIP_RS880,  	CHIP_RV770,  	CHIP_RV730,  	CHIP_RV710, diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index c8ef0d14ffa..0a92706eac1 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -154,7 +154,6 @@ void radeon_rmx_mode_fixup(struct drm_encoder *encoder,  	if (mode->hdisplay < native_mode->panel_xres ||  	    mode->vdisplay < native_mode->panel_yres) { -		radeon_encoder->flags |= RADEON_USE_RMX;  		if (ASIC_IS_AVIVO(rdev)) {  			adjusted_mode->hdisplay = native_mode->panel_xres;  			adjusted_mode->vdisplay = native_mode->panel_yres; @@ -197,15 +196,13 @@ void radeon_rmx_mode_fixup(struct drm_encoder *encoder,  	}  } +  static bool radeon_atom_mode_fixup(struct drm_encoder *encoder,  				   struct drm_display_mode *mode,  				   struct drm_display_mode *adjusted_mode)  { -  	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); -	radeon_encoder->flags &= ~RADEON_USE_RMX; -  	drm_mode_set_crtcinfo(adjusted_mode, 0);  	if (radeon_encoder->rmx_type != RMX_OFF) @@ -808,234 +805,6 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action)  } -static void atom_rv515_force_tv_scaler(struct radeon_device *rdev) -{ - -	WREG32(0x659C, 0x0); -	WREG32(0x6594, 0x705); -	WREG32(0x65A4, 0x10001); -	WREG32(0x65D8, 0x0); -	WREG32(0x65B0, 0x0); -	WREG32(0x65C0, 0x0); -	WREG32(0x65D4, 0x0); -	WREG32(0x6578, 0x0); -	WREG32(0x657C, 0x841880A8); -	WREG32(0x6578, 0x1); -	WREG32(0x657C, 0x84208680); -	WREG32(0x6578, 0x2); -	WREG32(0x657C, 0xBFF880B0); -	WREG32(0x6578, 0x100); -	WREG32(0x657C, 0x83D88088); -	WREG32(0x6578, 0x101); -	WREG32(0x657C, 0x84608680); -	WREG32(0x6578, 0x102); -	WREG32(0x657C, 0xBFF080D0); -	WREG32(0x6578, 0x200); -	WREG32(0x657C, 0x83988068); -	WREG32(0x6578, 0x201); -	WREG32(0x657C, 0x84A08680); -	WREG32(0x6578, 0x202); -	WREG32(0x657C, 0xBFF080F8); -	WREG32(0x6578, 0x300); -	WREG32(0x657C, 0x83588058); -	WREG32(0x6578, 0x301); -	WREG32(0x657C, 0x84E08660); -	WREG32(0x6578, 0x302); -	WREG32(0x657C, 0xBFF88120); -	WREG32(0x6578, 0x400); -	WREG32(0x657C, 0x83188040); -	WREG32(0x6578, 0x401); -	WREG32(0x657C, 0x85008660); -	WREG32(0x6578, 0x402); -	WREG32(0x657C, 0xBFF88150); -	WREG32(0x6578, 0x500); -	WREG32(0x657C, 0x82D88030); -	WREG32(0x6578, 0x501); -	WREG32(0x657C, 0x85408640); -	WREG32(0x6578, 0x502); -	WREG32(0x657C, 0xBFF88180); -	WREG32(0x6578, 0x600); -	WREG32(0x657C, 0x82A08018); -	WREG32(0x6578, 0x601); -	WREG32(0x657C, 0x85808620); -	WREG32(0x6578, 0x602); -	WREG32(0x657C, 0xBFF081B8); -	WREG32(0x6578, 0x700); -	WREG32(0x657C, 0x82608010); -	WREG32(0x6578, 0x701); -	WREG32(0x657C, 0x85A08600); -	WREG32(0x6578, 0x702); -	WREG32(0x657C, 0x800081F0); -	WREG32(0x6578, 0x800); -	WREG32(0x657C, 0x8228BFF8); -	WREG32(0x6578, 0x801); -	WREG32(0x657C, 0x85E085E0); -	WREG32(0x6578, 0x802); -	WREG32(0x657C, 0xBFF88228); -	WREG32(0x6578, 0x10000); -	WREG32(0x657C, 0x82A8BF00); -	WREG32(0x6578, 0x10001); -	WREG32(0x657C, 0x82A08CC0); -	WREG32(0x6578, 0x10002); -	WREG32(0x657C, 0x8008BEF8); -	WREG32(0x6578, 0x10100); -	WREG32(0x657C, 0x81F0BF28); -	WREG32(0x6578, 0x10101); -	WREG32(0x657C, 0x83608CA0); -	WREG32(0x6578, 0x10102); -	WREG32(0x657C, 0x8018BED0); -	WREG32(0x6578, 0x10200); -	WREG32(0x657C, 0x8148BF38); -	WREG32(0x6578, 0x10201); -	WREG32(0x657C, 0x84408C80); -	WREG32(0x6578, 0x10202); -	WREG32(0x657C, 0x8008BEB8); -	WREG32(0x6578, 0x10300); -	WREG32(0x657C, 0x80B0BF78); -	WREG32(0x6578, 0x10301); -	WREG32(0x657C, 0x85008C20); -	WREG32(0x6578, 0x10302); -	WREG32(0x657C, 0x8020BEA0); -	WREG32(0x6578, 0x10400); -	WREG32(0x657C, 0x8028BF90); -	WREG32(0x6578, 0x10401); -	WREG32(0x657C, 0x85E08BC0); -	WREG32(0x6578, 0x10402); -	WREG32(0x657C, 0x8018BE90); -	WREG32(0x6578, 0x10500); -	WREG32(0x657C, 0xBFB8BFB0); -	WREG32(0x6578, 0x10501); -	WREG32(0x657C, 0x86C08B40); -	WREG32(0x6578, 0x10502); -	WREG32(0x657C, 0x8010BE90); -	WREG32(0x6578, 0x10600); -	WREG32(0x657C, 0xBF58BFC8); -	WREG32(0x6578, 0x10601); -	WREG32(0x657C, 0x87A08AA0); -	WREG32(0x6578, 0x10602); -	WREG32(0x657C, 0x8010BE98); -	WREG32(0x6578, 0x10700); -	WREG32(0x657C, 0xBF10BFF0); -	WREG32(0x6578, 0x10701); -	WREG32(0x657C, 0x886089E0); -	WREG32(0x6578, 0x10702); -	WREG32(0x657C, 0x8018BEB0); -	WREG32(0x6578, 0x10800); -	WREG32(0x657C, 0xBED8BFE8); -	WREG32(0x6578, 0x10801); -	WREG32(0x657C, 0x89408940); -	WREG32(0x6578, 0x10802); -	WREG32(0x657C, 0xBFE8BED8); -	WREG32(0x6578, 0x20000); -	WREG32(0x657C, 0x80008000); -	WREG32(0x6578, 0x20001); -	WREG32(0x657C, 0x90008000); -	WREG32(0x6578, 0x20002); -	WREG32(0x657C, 0x80008000); -	WREG32(0x6578, 0x20003); -	WREG32(0x657C, 0x80008000); -	WREG32(0x6578, 0x20100); -	WREG32(0x657C, 0x80108000); -	WREG32(0x6578, 0x20101); -	WREG32(0x657C, 0x8FE0BF70); -	WREG32(0x6578, 0x20102); -	WREG32(0x657C, 0xBFE880C0); -	WREG32(0x6578, 0x20103); -	WREG32(0x657C, 0x80008000); -	WREG32(0x6578, 0x20200); -	WREG32(0x657C, 0x8018BFF8); -	WREG32(0x6578, 0x20201); -	WREG32(0x657C, 0x8F80BF08); -	WREG32(0x6578, 0x20202); -	WREG32(0x657C, 0xBFD081A0); -	WREG32(0x6578, 0x20203); -	WREG32(0x657C, 0xBFF88000); -	WREG32(0x6578, 0x20300); -	WREG32(0x657C, 0x80188000); -	WREG32(0x6578, 0x20301); -	WREG32(0x657C, 0x8EE0BEC0); -	WREG32(0x6578, 0x20302); -	WREG32(0x657C, 0xBFB082A0); -	WREG32(0x6578, 0x20303); -	WREG32(0x657C, 0x80008000); -	WREG32(0x6578, 0x20400); -	WREG32(0x657C, 0x80188000); -	WREG32(0x6578, 0x20401); -	WREG32(0x657C, 0x8E00BEA0); -	WREG32(0x6578, 0x20402); -	WREG32(0x657C, 0xBF8883C0); -	WREG32(0x6578, 0x20403); -	WREG32(0x657C, 0x80008000); -	WREG32(0x6578, 0x20500); -	WREG32(0x657C, 0x80188000); -	WREG32(0x6578, 0x20501); -	WREG32(0x657C, 0x8D00BE90); -	WREG32(0x6578, 0x20502); -	WREG32(0x657C, 0xBF588500); -	WREG32(0x6578, 0x20503); -	WREG32(0x657C, 0x80008008); -	WREG32(0x6578, 0x20600); -	WREG32(0x657C, 0x80188000); -	WREG32(0x6578, 0x20601); -	WREG32(0x657C, 0x8BC0BE98); -	WREG32(0x6578, 0x20602); -	WREG32(0x657C, 0xBF308660); -	WREG32(0x6578, 0x20603); -	WREG32(0x657C, 0x80008008); -	WREG32(0x6578, 0x20700); -	WREG32(0x657C, 0x80108000); -	WREG32(0x6578, 0x20701); -	WREG32(0x657C, 0x8A80BEB0); -	WREG32(0x6578, 0x20702); -	WREG32(0x657C, 0xBF0087C0); -	WREG32(0x6578, 0x20703); -	WREG32(0x657C, 0x80008008); -	WREG32(0x6578, 0x20800); -	WREG32(0x657C, 0x80108000); -	WREG32(0x6578, 0x20801); -	WREG32(0x657C, 0x8920BED0); -	WREG32(0x6578, 0x20802); -	WREG32(0x657C, 0xBED08920); -	WREG32(0x6578, 0x20803); -	WREG32(0x657C, 0x80008010); -	WREG32(0x6578, 0x30000); -	WREG32(0x657C, 0x90008000); -	WREG32(0x6578, 0x30001); -	WREG32(0x657C, 0x80008000); -	WREG32(0x6578, 0x30100); -	WREG32(0x657C, 0x8FE0BF90); -	WREG32(0x6578, 0x30101); -	WREG32(0x657C, 0xBFF880A0); -	WREG32(0x6578, 0x30200); -	WREG32(0x657C, 0x8F60BF40); -	WREG32(0x6578, 0x30201); -	WREG32(0x657C, 0xBFE88180); -	WREG32(0x6578, 0x30300); -	WREG32(0x657C, 0x8EC0BF00); -	WREG32(0x6578, 0x30301); -	WREG32(0x657C, 0xBFC88280); -	WREG32(0x6578, 0x30400); -	WREG32(0x657C, 0x8DE0BEE0); -	WREG32(0x6578, 0x30401); -	WREG32(0x657C, 0xBFA083A0); -	WREG32(0x6578, 0x30500); -	WREG32(0x657C, 0x8CE0BED0); -	WREG32(0x6578, 0x30501); -	WREG32(0x657C, 0xBF7884E0); -	WREG32(0x6578, 0x30600); -	WREG32(0x657C, 0x8BA0BED8); -	WREG32(0x6578, 0x30601); -	WREG32(0x657C, 0xBF508640); -	WREG32(0x6578, 0x30700); -	WREG32(0x657C, 0x8A60BEE8); -	WREG32(0x6578, 0x30701); -	WREG32(0x657C, 0xBF2087A0); -	WREG32(0x6578, 0x30800); -	WREG32(0x657C, 0x8900BF00); -	WREG32(0x6578, 0x30801); -	WREG32(0x657C, 0xBF008900); -} -  static void  atombios_yuv_setup(struct drm_encoder *encoder, bool enable)  { @@ -1074,129 +843,6 @@ atombios_yuv_setup(struct drm_encoder *encoder, bool enable)  }  static void -atombios_overscan_setup(struct drm_encoder *encoder, -			struct drm_display_mode *mode, -			struct drm_display_mode *adjusted_mode) -{ -	struct drm_device *dev = encoder->dev; -	struct radeon_device *rdev = dev->dev_private; -	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); -	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); -	SET_CRTC_OVERSCAN_PS_ALLOCATION args; -	int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan); - -	memset(&args, 0, sizeof(args)); - -	args.usOverscanRight = 0; -	args.usOverscanLeft = 0; -	args.usOverscanBottom = 0; -	args.usOverscanTop = 0; -	args.ucCRTC = radeon_crtc->crtc_id; - -	if (radeon_encoder->flags & RADEON_USE_RMX) { -		if (radeon_encoder->rmx_type == RMX_FULL) { -			args.usOverscanRight = 0; -			args.usOverscanLeft = 0; -			args.usOverscanBottom = 0; -			args.usOverscanTop = 0; -		} else if (radeon_encoder->rmx_type == RMX_CENTER) { -			args.usOverscanTop = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2; -			args.usOverscanBottom = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2; -			args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2; -			args.usOverscanRight = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2; -		} else if (radeon_encoder->rmx_type == RMX_ASPECT) { -			int a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay; -			int a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay; - -			if (a1 > a2) { -				args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2; -				args.usOverscanRight = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2; -			} else if (a2 > a1) { -				args.usOverscanLeft = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2; -				args.usOverscanRight = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2; -			} -		} -	} - -	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - -} - -static void -atombios_scaler_setup(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 radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); -	ENABLE_SCALER_PS_ALLOCATION args; -	int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); -	/* fixme - fill in enc_priv for atom dac */ -	enum radeon_tv_std tv_std = TV_STD_NTSC; - -	if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id) -		return; - -	memset(&args, 0, sizeof(args)); - -	args.ucScaler = radeon_crtc->crtc_id; - -	if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) { -		switch (tv_std) { -		case TV_STD_NTSC: -		default: -			args.ucTVStandard = ATOM_TV_NTSC; -			break; -		case TV_STD_PAL: -			args.ucTVStandard = ATOM_TV_PAL; -			break; -		case TV_STD_PAL_M: -			args.ucTVStandard = ATOM_TV_PALM; -			break; -		case TV_STD_PAL_60: -			args.ucTVStandard = ATOM_TV_PAL60; -			break; -		case TV_STD_NTSC_J: -			args.ucTVStandard = ATOM_TV_NTSCJ; -			break; -		case TV_STD_SCART_PAL: -			args.ucTVStandard = ATOM_TV_PAL; /* ??? */ -			break; -		case TV_STD_SECAM: -			args.ucTVStandard = ATOM_TV_SECAM; -			break; -		case TV_STD_PAL_CN: -			args.ucTVStandard = ATOM_TV_PALCN; -			break; -		} -		args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; -	} else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) { -		args.ucTVStandard = ATOM_TV_CV; -		args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; -	} else if (radeon_encoder->flags & RADEON_USE_RMX) { -		if (radeon_encoder->rmx_type == RMX_FULL) -			args.ucEnable = ATOM_SCALER_EXPANSION; -		else if (radeon_encoder->rmx_type == RMX_CENTER) -			args.ucEnable = ATOM_SCALER_CENTER; -		else if (radeon_encoder->rmx_type == RMX_ASPECT) -			args.ucEnable = ATOM_SCALER_EXPANSION; -	} else { -		if (ASIC_IS_AVIVO(rdev)) -			args.ucEnable = ATOM_SCALER_DISABLE; -		else -			args.ucEnable = ATOM_SCALER_CENTER; -	} - -	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - -	if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT) -	    && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_RV570) { -		atom_rv515_force_tv_scaler(rdev); -	} - -} - -static void  radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)  {  	struct drm_device *dev = encoder->dev; @@ -1448,8 +1094,6 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,  	radeon_encoder->pixel_clock = adjusted_mode->clock;  	radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); -	atombios_overscan_setup(encoder, mode, adjusted_mode); -	atombios_scaler_setup(encoder);  	atombios_set_encoder_crtc_source(encoder);  	if (ASIC_IS_AVIVO(rdev)) { @@ -1667,6 +1311,7 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su  	radeon_encoder->encoder_id = encoder_id;  	radeon_encoder->devices = supported_device; +	radeon_encoder->rmx_type = RMX_OFF;  	switch (radeon_encoder->encoder_id) {  	case ENCODER_OBJECT_ID_INTERNAL_LVDS: diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 9e8f191eb64..ec383edf5f3 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -101,9 +101,10 @@ static int radeonfb_setcolreg(unsigned regno,  				break;  			case 24:  			case 32: -				fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | -					(green & 0xff00) | -					((blue  & 0xff00) >> 8); +				fb->pseudo_palette[regno] = +					(((red >> 8) & 0xff) << info->var.red.offset) | +					(((green >> 8) & 0xff) << info->var.green.offset) | +					(((blue >> 8) & 0xff) << info->var.blue.offset);  				break;  			}  		} @@ -154,6 +155,7 @@ static int radeonfb_check_var(struct fb_var_screeninfo *var,  		var->transp.length = 0;  		var->transp.offset = 0;  		break; +#ifdef __LITTLE_ENDIAN  	case 15:  		var->red.offset = 10;  		var->green.offset = 5; @@ -194,6 +196,28 @@ static int radeonfb_check_var(struct fb_var_screeninfo *var,  		var->transp.length = 8;  		var->transp.offset = 24;  		break; +#else +	case 24: +		var->red.offset = 8; +		var->green.offset = 16; +		var->blue.offset = 24; +		var->red.length = 8; +		var->green.length = 8; +		var->blue.length = 8; +		var->transp.length = 0; +		var->transp.offset = 0; +		break; +	case 32: +		var->red.offset = 8; +		var->green.offset = 16; +		var->blue.offset = 24; +		var->red.length = 8; +		var->green.length = 8; +		var->blue.length = 8; +		var->transp.length = 8; +		var->transp.offset = 0; +		break; +#endif  	default:  		return -EINVAL;  	} @@ -447,10 +471,10 @@ static struct notifier_block paniced = {  	.notifier_call = radeonfb_panic,  }; -static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp) +static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled)  {  	int aligned = width; -	int align_large = (ASIC_IS_AVIVO(rdev)); +	int align_large = (ASIC_IS_AVIVO(rdev)) || tiled;  	int pitch_mask = 0;  	switch (bpp / 8) { @@ -488,12 +512,13 @@ int radeonfb_create(struct radeon_device *rdev,  	u64 fb_gpuaddr;  	void *fbptr = NULL;  	unsigned long tmp; +	bool fb_tiled = false; /* useful for testing */  	mode_cmd.width = surface_width;  	mode_cmd.height = surface_height;  	mode_cmd.bpp = 32;  	/* need to align pitch with crtc limits */ -	mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp) * ((mode_cmd.bpp + 1) / 8); +	mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp, fb_tiled) * ((mode_cmd.bpp + 1) / 8);  	mode_cmd.depth = 24;  	size = mode_cmd.pitch * mode_cmd.height; @@ -511,6 +536,8 @@ int radeonfb_create(struct radeon_device *rdev,  	}  	robj = gobj->driver_private; +	if (fb_tiled) +		radeon_object_set_tiling_flags(robj, RADEON_TILING_MACRO|RADEON_TILING_SURFACE, mode_cmd.pitch);  	mutex_lock(&rdev->ddev->struct_mutex);  	fb = radeon_framebuffer_create(rdev->ddev, &mode_cmd, gobj);  	if (fb == NULL) { @@ -539,11 +566,16 @@ int radeonfb_create(struct radeon_device *rdev,  	}  	rfbdev = info->par; +	if (fb_tiled) +		radeon_object_check_tiling(robj, 0, 0); +  	ret = radeon_object_kmap(robj, &fbptr);  	if (ret) {  		goto out_unref;  	} +	memset_io(fbptr, 0, aligned_size); +  	strcpy(info->fix.id, "radeondrmfb");  	info->fix.type = FB_TYPE_PACKED_PIXELS;  	info->fix.visual = FB_VISUAL_TRUECOLOR; @@ -572,6 +604,11 @@ int radeonfb_create(struct radeon_device *rdev,  	info->var.width = -1;  	info->var.xres = fb_width;  	info->var.yres = fb_height; + +	/* setup aperture base/size for vesafb takeover */ +	info->aperture_base = rdev->ddev->mode_config.fb_base; +	info->aperture_size = rdev->mc.real_vram_size; +  	info->fix.mmio_start = 0;  	info->fix.mmio_len = 0;  	info->pixmap.size = 64*1024; @@ -600,6 +637,7 @@ int radeonfb_create(struct radeon_device *rdev,  		info->var.transp.offset = 0;  		info->var.transp.length = 0;  		break; +#ifdef __LITTLE_ENDIAN  	case 15:  		info->var.red.offset = 10;  		info->var.green.offset = 5; @@ -639,7 +677,29 @@ int radeonfb_create(struct radeon_device *rdev,  		info->var.transp.offset = 24;  		info->var.transp.length = 8;  		break; +#else +	case 24: +		info->var.red.offset = 8; +		info->var.green.offset = 16; +		info->var.blue.offset = 24; +		info->var.red.length = 8; +		info->var.green.length = 8; +		info->var.blue.length = 8; +		info->var.transp.offset = 0; +		info->var.transp.length = 0; +		break; +	case 32: +		info->var.red.offset = 8; +		info->var.green.offset = 16; +		info->var.blue.offset = 24; +		info->var.red.length = 8; +		info->var.green.length = 8; +		info->var.blue.length = 8; +		info->var.transp.offset = 0; +		info->var.transp.length = 8; +		break;  	default: +#endif  		break;  	} diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 96afbf5ae2a..b4e48dd2e85 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -195,7 +195,7 @@ retry:  		r = wait_event_interruptible_timeout(rdev->fence_drv.queue,  				radeon_fence_signaled(fence), timeout);  		if (unlikely(r == -ERESTARTSYS)) { -			return -ERESTART; +			return -EBUSY;  		}  	} else {  		r = wait_event_timeout(rdev->fence_drv.queue, diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index d343a15316e..2977539880f 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -177,7 +177,7 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,  			return -ENOMEM;  		}  		rdev->gart.pages[p] = pagelist[i]; -		page_base = (uint32_t)rdev->gart.pages_addr[p]; +		page_base = rdev->gart.pages_addr[p];  		for (j = 0; j < (PAGE_SIZE / 4096); j++, t++) {  			radeon_gart_set_page(rdev, t, page_base);  			page_base += 4096; diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index eb516034235..d4ceff13bbb 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -157,9 +157,9 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data,  	struct radeon_device *rdev = dev->dev_private;  	struct drm_radeon_gem_info *args = data; -	args->vram_size = rdev->mc.vram_size; +	args->vram_size = rdev->mc.real_vram_size;  	/* FIXME: report somethings that makes sense */ -	args->vram_visible = rdev->mc.vram_size - (4 * 1024 * 1024); +	args->vram_visible = rdev->mc.real_vram_size - (4 * 1024 * 1024);  	args->gart_size = rdev->mc.gtt_size;  	return 0;  } @@ -262,7 +262,27 @@ int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data,  int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,  			  struct drm_file *filp)  { -	/* FIXME: implement */ +	struct drm_radeon_gem_busy *args = data; +	struct drm_gem_object *gobj; +	struct radeon_object *robj; +	int r; +	uint32_t cur_placement; + +	gobj = drm_gem_object_lookup(dev, filp, args->handle); +	if (gobj == NULL) { +		return -EINVAL; +	} +	robj = gobj->driver_private; +	r = radeon_object_busy_domain(robj, &cur_placement); +	if (cur_placement == TTM_PL_VRAM) +		args->domain = RADEON_GEM_DOMAIN_VRAM; +	if (cur_placement == TTM_PL_FLAG_TT) +		args->domain = RADEON_GEM_DOMAIN_GTT; +	if (cur_placement == TTM_PL_FLAG_SYSTEM) +		args->domain = RADEON_GEM_DOMAIN_CPU; +	mutex_lock(&dev->struct_mutex); +	drm_gem_object_unreference(gobj); +	mutex_unlock(&dev->struct_mutex);  	return 0;  } @@ -285,3 +305,44 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,  	mutex_unlock(&dev->struct_mutex);  	return r;  } + +int radeon_gem_set_tiling_ioctl(struct drm_device *dev, void *data, +				struct drm_file *filp) +{ +	struct drm_radeon_gem_set_tiling *args = data; +	struct drm_gem_object *gobj; +	struct radeon_object *robj; +	int r = 0; + +	DRM_DEBUG("%d \n", args->handle); +	gobj = drm_gem_object_lookup(dev, filp, args->handle); +	if (gobj == NULL) +		return -EINVAL; +	robj = gobj->driver_private; +	radeon_object_set_tiling_flags(robj, args->tiling_flags, args->pitch); +	mutex_lock(&dev->struct_mutex); +	drm_gem_object_unreference(gobj); +	mutex_unlock(&dev->struct_mutex); +	return r; +} + +int radeon_gem_get_tiling_ioctl(struct drm_device *dev, void *data, +				struct drm_file *filp) +{ +	struct drm_radeon_gem_get_tiling *args = data; +	struct drm_gem_object *gobj; +	struct radeon_object *robj; +	int r = 0; + +	DRM_DEBUG("\n"); +	gobj = drm_gem_object_lookup(dev, filp, args->handle); +	if (gobj == NULL) +		return -EINVAL; +	robj = gobj->driver_private; +	radeon_object_get_tiling_flags(robj, &args->tiling_flags, +				       &args->pitch); +	mutex_lock(&dev->struct_mutex); +	drm_gem_object_unreference(gobj); +	mutex_unlock(&dev->struct_mutex); +	return r; +} diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 491d569deb0..9805e4b6ca1 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -32,60 +32,6 @@  #include "radeon.h"  #include "atom.h" -static inline uint32_t r100_irq_ack(struct radeon_device *rdev) -{ -	uint32_t irqs = RREG32(RADEON_GEN_INT_STATUS); -	uint32_t irq_mask = RADEON_SW_INT_TEST; - -	if (irqs) { -		WREG32(RADEON_GEN_INT_STATUS, irqs); -	} -	return irqs & irq_mask; -} - -int r100_irq_set(struct radeon_device *rdev) -{ -	uint32_t tmp = 0; - -	if (rdev->irq.sw_int) { -		tmp |= RADEON_SW_INT_ENABLE; -	} -	/* Todo go through CRTC and enable vblank int or not */ -	WREG32(RADEON_GEN_INT_CNTL, tmp); -	return 0; -} - -int r100_irq_process(struct radeon_device *rdev) -{ -	uint32_t status; - -	status = r100_irq_ack(rdev); -	if (!status) { -		return IRQ_NONE; -	} -	while (status) { -		/* SW interrupt */ -		if (status & RADEON_SW_INT_TEST) { -			radeon_fence_process(rdev); -		} -		status = r100_irq_ack(rdev); -	} -	return IRQ_HANDLED; -} - -int rs600_irq_set(struct radeon_device *rdev) -{ -	uint32_t tmp = 0; - -	if (rdev->irq.sw_int) { -		tmp |= RADEON_SW_INT_ENABLE; -	} -	WREG32(RADEON_GEN_INT_CNTL, tmp); -	/* Todo go through CRTC and enable vblank int or not */ -	WREG32(R500_DxMODE_INT_MASK, 0); -	return 0; -} -  irqreturn_t radeon_driver_irq_handler_kms(DRM_IRQ_ARGS)  {  	struct drm_device *dev = (struct drm_device *) arg; diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 4612a7c146d..d2764bf6b2a 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -58,6 +58,8 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)  	if (r) {  		DRM_ERROR("Failed to initialize radeon, disabling IOCTL\n");  		radeon_device_fini(rdev); +		kfree(rdev); +		dev->dev_private = NULL;  		return r;  	}  	return 0; @@ -139,19 +141,42 @@ void radeon_driver_preclose_kms(struct drm_device *dev,   */  u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc)  { -	/* FIXME: implement */ -	return 0; +	struct radeon_device *rdev = dev->dev_private; + +	if (crtc < 0 || crtc > 1) { +		DRM_ERROR("Invalid crtc %d\n", crtc); +		return -EINVAL; +	} + +	return radeon_get_vblank_counter(rdev, crtc);  }  int radeon_enable_vblank_kms(struct drm_device *dev, int crtc)  { -	/* FIXME: implement */ -	return 0; +	struct radeon_device *rdev = dev->dev_private; + +	if (crtc < 0 || crtc > 1) { +		DRM_ERROR("Invalid crtc %d\n", crtc); +		return -EINVAL; +	} + +	rdev->irq.crtc_vblank_int[crtc] = true; + +	return radeon_irq_set(rdev);  }  void radeon_disable_vblank_kms(struct drm_device *dev, int crtc)  { -	/* FIXME: implement */ +	struct radeon_device *rdev = dev->dev_private; + +	if (crtc < 0 || crtc > 1) { +		DRM_ERROR("Invalid crtc %d\n", crtc); +		return; +	} + +	rdev->irq.crtc_vblank_int[crtc] = false; + +	radeon_irq_set(rdev);  } @@ -291,5 +316,7 @@ struct drm_ioctl_desc radeon_ioctls_kms[] = {  	DRM_IOCTL_DEF(DRM_RADEON_GEM_WAIT_IDLE, radeon_gem_wait_idle_ioctl, DRM_AUTH),  	DRM_IOCTL_DEF(DRM_RADEON_CS, radeon_cs_ioctl, DRM_AUTH),  	DRM_IOCTL_DEF(DRM_RADEON_INFO, radeon_info_ioctl, DRM_AUTH), +	DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_TILING, radeon_gem_set_tiling_ioctl, DRM_AUTH), +	DRM_IOCTL_DEF(DRM_RADEON_GEM_GET_TILING, radeon_gem_get_tiling_ioctl, DRM_AUTH),  };  int radeon_max_kms_ioctl = DRM_ARRAY_SIZE(radeon_ioctls_kms); diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 8086ecf7f03..0da72f18fd3 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -29,6 +29,171 @@  #include "radeon_fixed.h"  #include "radeon.h" +static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc, +				       struct drm_display_mode *mode, +				       struct drm_display_mode *adjusted_mode) +{ +	struct drm_device *dev = crtc->dev; +	struct radeon_device *rdev = dev->dev_private; +	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); +	int xres = mode->hdisplay; +	int yres = mode->vdisplay; +	bool hscale = true, vscale = true; +	int hsync_wid; +	int vsync_wid; +	int hsync_start; +	int blank_width; +	u32 scale, inc, crtc_more_cntl; +	u32 fp_horz_stretch, fp_vert_stretch, fp_horz_vert_active; +	u32 fp_h_sync_strt_wid, fp_crtc_h_total_disp; +	u32 fp_v_sync_strt_wid, fp_crtc_v_total_disp; +	struct radeon_native_mode *native_mode = &radeon_crtc->native_mode; + +	fp_vert_stretch = RREG32(RADEON_FP_VERT_STRETCH) & +		(RADEON_VERT_STRETCH_RESERVED | +		 RADEON_VERT_AUTO_RATIO_INC); +	fp_horz_stretch = RREG32(RADEON_FP_HORZ_STRETCH) & +		(RADEON_HORZ_FP_LOOP_STRETCH | +		 RADEON_HORZ_AUTO_RATIO_INC); + +	crtc_more_cntl = 0; +	if ((rdev->family == CHIP_RS100) || +	    (rdev->family == CHIP_RS200)) { +		/* This is to workaround the asic bug for RMX, some versions +		   of BIOS dosen't have this register initialized correctly. */ +		crtc_more_cntl |= RADEON_CRTC_H_CUTOFF_ACTIVE_EN; +	} + + +	fp_crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff) +				| ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16)); + +	hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8; +	if (!hsync_wid) +		hsync_wid = 1; +	hsync_start = mode->crtc_hsync_start - 8; + +	fp_h_sync_strt_wid = ((hsync_start & 0x1fff) +			      | ((hsync_wid & 0x3f) << 16) +			      | ((mode->flags & DRM_MODE_FLAG_NHSYNC) +				 ? RADEON_CRTC_H_SYNC_POL +				 : 0)); + +	fp_crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff) +				| ((mode->crtc_vdisplay - 1) << 16)); + +	vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start; +	if (!vsync_wid) +		vsync_wid = 1; + +	fp_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff) +			      | ((vsync_wid & 0x1f) << 16) +			      | ((mode->flags & DRM_MODE_FLAG_NVSYNC) +				 ? RADEON_CRTC_V_SYNC_POL +				 : 0)); + +	fp_horz_vert_active = 0; + +	if (native_mode->panel_xres == 0 || +	    native_mode->panel_yres == 0) { +		hscale = false; +		vscale = false; +	} else { +		if (xres > native_mode->panel_xres) +			xres = native_mode->panel_xres; +		if (yres > native_mode->panel_yres) +			yres = native_mode->panel_yres; + +		if (xres == native_mode->panel_xres) +			hscale = false; +		if (yres == native_mode->panel_yres) +			vscale = false; +	} + +	switch (radeon_crtc->rmx_type) { +	case RMX_FULL: +	case RMX_ASPECT: +		if (!hscale) +			fp_horz_stretch |= ((xres/8-1) << 16); +		else { +			inc = (fp_horz_stretch & RADEON_HORZ_AUTO_RATIO_INC) ? 1 : 0; +			scale = ((xres + inc) * RADEON_HORZ_STRETCH_RATIO_MAX) +				/ native_mode->panel_xres + 1; +			fp_horz_stretch |= (((scale) & RADEON_HORZ_STRETCH_RATIO_MASK) | +					RADEON_HORZ_STRETCH_BLEND | +					RADEON_HORZ_STRETCH_ENABLE | +					((native_mode->panel_xres/8-1) << 16)); +		} + +		if (!vscale) +			fp_vert_stretch |= ((yres-1) << 12); +		else { +			inc = (fp_vert_stretch & RADEON_VERT_AUTO_RATIO_INC) ? 1 : 0; +			scale = ((yres + inc) * RADEON_VERT_STRETCH_RATIO_MAX) +				/ native_mode->panel_yres + 1; +			fp_vert_stretch |= (((scale) & RADEON_VERT_STRETCH_RATIO_MASK) | +					RADEON_VERT_STRETCH_ENABLE | +					RADEON_VERT_STRETCH_BLEND | +					((native_mode->panel_yres-1) << 12)); +		} +		break; +	case RMX_CENTER: +		fp_horz_stretch |= ((xres/8-1) << 16); +		fp_vert_stretch |= ((yres-1) << 12); + +		crtc_more_cntl |= (RADEON_CRTC_AUTO_HORZ_CENTER_EN | +				RADEON_CRTC_AUTO_VERT_CENTER_EN); + +		blank_width = (mode->crtc_hblank_end - mode->crtc_hblank_start) / 8; +		if (blank_width > 110) +			blank_width = 110; + +		fp_crtc_h_total_disp = (((blank_width) & 0x3ff) +				| ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16)); + +		hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8; +		if (!hsync_wid) +			hsync_wid = 1; + +		fp_h_sync_strt_wid = ((((mode->crtc_hsync_start - mode->crtc_hblank_start) / 8) & 0x1fff) +				| ((hsync_wid & 0x3f) << 16) +				| ((mode->flags & DRM_MODE_FLAG_NHSYNC) +					? RADEON_CRTC_H_SYNC_POL +					: 0)); + +		fp_crtc_v_total_disp = (((mode->crtc_vblank_end - mode->crtc_vblank_start) & 0xffff) +				| ((mode->crtc_vdisplay - 1) << 16)); + +		vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start; +		if (!vsync_wid) +			vsync_wid = 1; + +		fp_v_sync_strt_wid = ((((mode->crtc_vsync_start - mode->crtc_vblank_start) & 0xfff) +					| ((vsync_wid & 0x1f) << 16) +					| ((mode->flags & DRM_MODE_FLAG_NVSYNC) +						? RADEON_CRTC_V_SYNC_POL +						: 0))); + +		fp_horz_vert_active = (((native_mode->panel_yres) & 0xfff) | +				(((native_mode->panel_xres / 8) & 0x1ff) << 16)); +		break; +	case RMX_OFF: +	default: +		fp_horz_stretch |= ((xres/8-1) << 16); +		fp_vert_stretch |= ((yres-1) << 12); +		break; +	} + +	WREG32(RADEON_FP_HORZ_STRETCH,      fp_horz_stretch); +	WREG32(RADEON_FP_VERT_STRETCH,      fp_vert_stretch); +	WREG32(RADEON_CRTC_MORE_CNTL,       crtc_more_cntl); +	WREG32(RADEON_FP_HORZ_VERT_ACTIVE,  fp_horz_vert_active); +	WREG32(RADEON_FP_H_SYNC_STRT_WID,   fp_h_sync_strt_wid); +	WREG32(RADEON_FP_V_SYNC_STRT_WID,   fp_v_sync_strt_wid); +	WREG32(RADEON_FP_CRTC_H_TOTAL_DISP, fp_crtc_h_total_disp); +	WREG32(RADEON_FP_CRTC_V_TOTAL_DISP, fp_crtc_v_total_disp); +} +  void radeon_restore_common_regs(struct drm_device *dev)  {  	/* don't need this yet */ @@ -145,10 +310,13 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)  									 RADEON_CRTC_DISP_REQ_EN_B));  			WREG32_P(RADEON_CRTC_EXT_CNTL, 0, ~mask);  		} +		drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); +		radeon_crtc_load_lut(crtc);  		break;  	case DRM_MODE_DPMS_STANDBY:  	case DRM_MODE_DPMS_SUSPEND:  	case DRM_MODE_DPMS_OFF: +		drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id);  		if (radeon_crtc->crtc_id)  			WREG32_P(RADEON_CRTC2_GEN_CNTL, mask, ~mask);  		else { @@ -158,10 +326,6 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)  		}  		break;  	} - -	if (mode != DRM_MODE_DPMS_OFF) { -		radeon_crtc_load_lut(crtc); -	}  }  /* properly set crtc bpp when using atombios */ @@ -235,6 +399,7 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,  	uint64_t base;  	uint32_t crtc_offset, crtc_offset_cntl, crtc_tile_x0_y0 = 0;  	uint32_t crtc_pitch, pitch_pixels; +	uint32_t tiling_flags;  	DRM_DEBUG("\n"); @@ -244,7 +409,12 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,  	if (radeon_gem_object_pin(obj, RADEON_GEM_DOMAIN_VRAM, &base)) {  		return -EINVAL;  	} -	crtc_offset = (u32)base; +	/* if scanout was in GTT this really wouldn't work */ +	/* crtc offset is from display base addr not FB location */ +	radeon_crtc->legacy_display_base_addr = rdev->mc.vram_location; + +	base -= radeon_crtc->legacy_display_base_addr; +  	crtc_offset_cntl = 0;  	pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8); @@ -253,8 +423,12 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,  		       (crtc->fb->bits_per_pixel * 8));  	crtc_pitch |= crtc_pitch << 16; -	/* TODO tiling */ -	if (0) { +	radeon_object_get_tiling_flags(obj->driver_private, +				       &tiling_flags, NULL); +	if (tiling_flags & RADEON_TILING_MICRO) +		DRM_ERROR("trying to scanout microtiled buffer\n"); + +	if (tiling_flags & RADEON_TILING_MACRO) {  		if (ASIC_IS_R300(rdev))  			crtc_offset_cntl |= (R300_CRTC_X_Y_MODE_EN |  					     R300_CRTC_MICRO_TILE_BUFFER_DIS | @@ -270,15 +444,13 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,  			crtc_offset_cntl &= ~RADEON_CRTC_TILE_EN;  	} - -	/* TODO more tiling */ -	if (0) { +	if (tiling_flags & RADEON_TILING_MACRO) {  		if (ASIC_IS_R300(rdev)) {  			crtc_tile_x0_y0 = x | (y << 16);  			base &= ~0x7ff;  		} else {  			int byteshift = crtc->fb->bits_per_pixel >> 4; -			int tile_addr = (((y >> 3) * crtc->fb->width + x) >> (8 - byteshift)) << 11; +			int tile_addr = (((y >> 3) * pitch_pixels +  x) >> (8 - byteshift)) << 11;  			base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8);  			crtc_offset_cntl |= (y % 16);  		} @@ -303,11 +475,9 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,  	base &= ~7; -	/* update sarea TODO */ -  	crtc_offset = (u32)base; -	WREG32(RADEON_DISPLAY_BASE_ADDR + radeon_crtc->crtc_offset, rdev->mc.vram_location); +	WREG32(RADEON_DISPLAY_BASE_ADDR + radeon_crtc->crtc_offset, radeon_crtc->legacy_display_base_addr);  	if (ASIC_IS_R300(rdev)) {  		if (radeon_crtc->crtc_id) @@ -751,6 +921,8 @@ static bool radeon_crtc_mode_fixup(struct drm_crtc *crtc,  				   struct drm_display_mode *mode,  				   struct drm_display_mode *adjusted_mode)  { +	if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) +		return false;  	return true;  } @@ -759,16 +931,25 @@ static int radeon_crtc_mode_set(struct drm_crtc *crtc,  				 struct drm_display_mode *adjusted_mode,  				 int x, int y, struct drm_framebuffer *old_fb)  { - -	DRM_DEBUG("\n"); +	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); +	struct drm_device *dev = crtc->dev; +	struct radeon_device *rdev = dev->dev_private;  	/* TODO TV */ -  	radeon_crtc_set_base(crtc, x, y, old_fb);  	radeon_set_crtc_timing(crtc, adjusted_mode);  	radeon_set_pll(crtc, adjusted_mode); -	radeon_init_disp_bandwidth(crtc->dev); - +	radeon_bandwidth_update(rdev); +	if (radeon_crtc->crtc_id == 0) { +		radeon_legacy_rmx_mode_set(crtc, mode, adjusted_mode); +	} else { +		if (radeon_crtc->rmx_type != RMX_OFF) { +			/* FIXME: only first crtc has rmx what should we +			 * do ? +			 */ +			DRM_ERROR("Mode need scaling but only first crtc can do that.\n"); +		} +	}  	return 0;  } @@ -799,478 +980,3 @@ void radeon_legacy_init_crtc(struct drm_device *dev,  		radeon_crtc->crtc_offset = RADEON_CRTC2_H_TOTAL_DISP - RADEON_CRTC_H_TOTAL_DISP;  	drm_crtc_helper_add(&radeon_crtc->base, &legacy_helper_funcs);  } - -void radeon_init_disp_bw_legacy(struct drm_device *dev, -				struct drm_display_mode *mode1, -				uint32_t pixel_bytes1, -				struct drm_display_mode *mode2, -				uint32_t pixel_bytes2) -{ -	struct radeon_device *rdev = dev->dev_private; -	fixed20_12 trcd_ff, trp_ff, tras_ff, trbs_ff, tcas_ff; -	fixed20_12 sclk_ff, mclk_ff, sclk_eff_ff, sclk_delay_ff; -	fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff, crit_point_ff; -	uint32_t temp, data, mem_trcd, mem_trp, mem_tras; -	fixed20_12 memtcas_ff[8] = { -		fixed_init(1), -		fixed_init(2), -		fixed_init(3), -		fixed_init(0), -		fixed_init_half(1), -		fixed_init_half(2), -		fixed_init(0), -	}; -	fixed20_12 memtcas_rs480_ff[8] = { -		fixed_init(0), -		fixed_init(1), -		fixed_init(2), -		fixed_init(3), -		fixed_init(0), -		fixed_init_half(1), -		fixed_init_half(2), -		fixed_init_half(3), -	}; -	fixed20_12 memtcas2_ff[8] = { -		fixed_init(0), -		fixed_init(1), -		fixed_init(2), -		fixed_init(3), -		fixed_init(4), -		fixed_init(5), -		fixed_init(6), -		fixed_init(7), -	}; -	fixed20_12 memtrbs[8] = { -		fixed_init(1), -		fixed_init_half(1), -		fixed_init(2), -		fixed_init_half(2), -		fixed_init(3), -		fixed_init_half(3), -		fixed_init(4), -		fixed_init_half(4) -	}; -	fixed20_12 memtrbs_r4xx[8] = { -		fixed_init(4), -		fixed_init(5), -		fixed_init(6), -		fixed_init(7), -		fixed_init(8), -		fixed_init(9), -		fixed_init(10), -		fixed_init(11) -	}; -	fixed20_12 min_mem_eff; -	fixed20_12 mc_latency_sclk, mc_latency_mclk, k1; -	fixed20_12 cur_latency_mclk, cur_latency_sclk; -	fixed20_12 disp_latency, disp_latency_overhead, disp_drain_rate, -		disp_drain_rate2, read_return_rate; -	fixed20_12 time_disp1_drop_priority; -	int c; -	int cur_size = 16;       /* in octawords */ -	int critical_point = 0, critical_point2; -/* 	uint32_t read_return_rate, time_disp1_drop_priority; */ -	int stop_req, max_stop_req; - -	min_mem_eff.full = rfixed_const_8(0); -	/* get modes */ -	if ((rdev->disp_priority == 2) && ASIC_IS_R300(rdev)) { -		uint32_t mc_init_misc_lat_timer = RREG32(R300_MC_INIT_MISC_LAT_TIMER); -		mc_init_misc_lat_timer &= ~(R300_MC_DISP1R_INIT_LAT_MASK << R300_MC_DISP1R_INIT_LAT_SHIFT); -		mc_init_misc_lat_timer &= ~(R300_MC_DISP0R_INIT_LAT_MASK << R300_MC_DISP0R_INIT_LAT_SHIFT); -		/* check crtc enables */ -		if (mode2) -			mc_init_misc_lat_timer |= (1 << R300_MC_DISP1R_INIT_LAT_SHIFT); -		if (mode1) -			mc_init_misc_lat_timer |= (1 << R300_MC_DISP0R_INIT_LAT_SHIFT); -		WREG32(R300_MC_INIT_MISC_LAT_TIMER, mc_init_misc_lat_timer); -	} - -	/* -	 * determine is there is enough bw for current mode -	 */ -	mclk_ff.full = rfixed_const(rdev->clock.default_mclk); -	temp_ff.full = rfixed_const(100); -	mclk_ff.full = rfixed_div(mclk_ff, temp_ff); -	sclk_ff.full = rfixed_const(rdev->clock.default_sclk); -	sclk_ff.full = rfixed_div(sclk_ff, temp_ff); - -	temp = (rdev->mc.vram_width / 8) * (rdev->mc.vram_is_ddr ? 2 : 1); -	temp_ff.full = rfixed_const(temp); -	mem_bw.full = rfixed_mul(mclk_ff, temp_ff); - -	pix_clk.full = 0; -	pix_clk2.full = 0; -	peak_disp_bw.full = 0; -	if (mode1) { -		temp_ff.full = rfixed_const(1000); -		pix_clk.full = rfixed_const(mode1->clock); /* convert to fixed point */ -		pix_clk.full = rfixed_div(pix_clk, temp_ff); -		temp_ff.full = rfixed_const(pixel_bytes1); -		peak_disp_bw.full += rfixed_mul(pix_clk, temp_ff); -	} -	if (mode2) { -		temp_ff.full = rfixed_const(1000); -		pix_clk2.full = rfixed_const(mode2->clock); /* convert to fixed point */ -		pix_clk2.full = rfixed_div(pix_clk2, temp_ff); -		temp_ff.full = rfixed_const(pixel_bytes2); -		peak_disp_bw.full += rfixed_mul(pix_clk2, temp_ff); -	} - -	mem_bw.full = rfixed_mul(mem_bw, min_mem_eff); -	if (peak_disp_bw.full >= mem_bw.full) { -		DRM_ERROR("You may not have enough display bandwidth for current mode\n" -			  "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n"); -	} - -	/*  Get values from the EXT_MEM_CNTL register...converting its contents. */ -	temp = RREG32(RADEON_MEM_TIMING_CNTL); -	if ((rdev->family == CHIP_RV100) || (rdev->flags & RADEON_IS_IGP)) { /* RV100, M6, IGPs */ -		mem_trcd = ((temp >> 2) & 0x3) + 1; -		mem_trp  = ((temp & 0x3)) + 1; -		mem_tras = ((temp & 0x70) >> 4) + 1; -	} else if (rdev->family == CHIP_R300 || -		   rdev->family == CHIP_R350) { /* r300, r350 */ -		mem_trcd = (temp & 0x7) + 1; -		mem_trp = ((temp >> 8) & 0x7) + 1; -		mem_tras = ((temp >> 11) & 0xf) + 4; -	} else if (rdev->family == CHIP_RV350 || -		   rdev->family <= CHIP_RV380) { -		/* rv3x0 */ -		mem_trcd = (temp & 0x7) + 3; -		mem_trp = ((temp >> 8) & 0x7) + 3; -		mem_tras = ((temp >> 11) & 0xf) + 6; -	} else if (rdev->family == CHIP_R420 || -		   rdev->family == CHIP_R423 || -		   rdev->family == CHIP_RV410) { -		/* r4xx */ -		mem_trcd = (temp & 0xf) + 3; -		if (mem_trcd > 15) -			mem_trcd = 15; -		mem_trp = ((temp >> 8) & 0xf) + 3; -		if (mem_trp > 15) -			mem_trp = 15; -		mem_tras = ((temp >> 12) & 0x1f) + 6; -		if (mem_tras > 31) -			mem_tras = 31; -	} else { /* RV200, R200 */ -		mem_trcd = (temp & 0x7) + 1; -		mem_trp = ((temp >> 8) & 0x7) + 1; -		mem_tras = ((temp >> 12) & 0xf) + 4; -	} -	/* convert to FF */ -	trcd_ff.full = rfixed_const(mem_trcd); -	trp_ff.full = rfixed_const(mem_trp); -	tras_ff.full = rfixed_const(mem_tras); - -	/* Get values from the MEM_SDRAM_MODE_REG register...converting its */ -	temp = RREG32(RADEON_MEM_SDRAM_MODE_REG); -	data = (temp & (7 << 20)) >> 20; -	if ((rdev->family == CHIP_RV100) || rdev->flags & RADEON_IS_IGP) { -		if (rdev->family == CHIP_RS480) /* don't think rs400 */ -			tcas_ff = memtcas_rs480_ff[data]; -		else -			tcas_ff = memtcas_ff[data]; -	} else -		tcas_ff = memtcas2_ff[data]; - -	if (rdev->family == CHIP_RS400 || -	    rdev->family == CHIP_RS480) { -		/* extra cas latency stored in bits 23-25 0-4 clocks */ -		data = (temp >> 23) & 0x7; -		if (data < 5) -			tcas_ff.full += rfixed_const(data); -	} - -	if (ASIC_IS_R300(rdev) && !(rdev->flags & RADEON_IS_IGP)) { -		/* on the R300, Tcas is included in Trbs. -		 */ -		temp = RREG32(RADEON_MEM_CNTL); -		data = (R300_MEM_NUM_CHANNELS_MASK & temp); -		if (data == 1) { -			if (R300_MEM_USE_CD_CH_ONLY & temp) { -				temp = RREG32(R300_MC_IND_INDEX); -				temp &= ~R300_MC_IND_ADDR_MASK; -				temp |= R300_MC_READ_CNTL_CD_mcind; -				WREG32(R300_MC_IND_INDEX, temp); -				temp = RREG32(R300_MC_IND_DATA); -				data = (R300_MEM_RBS_POSITION_C_MASK & temp); -			} else { -				temp = RREG32(R300_MC_READ_CNTL_AB); -				data = (R300_MEM_RBS_POSITION_A_MASK & temp); -			} -		} else { -			temp = RREG32(R300_MC_READ_CNTL_AB); -			data = (R300_MEM_RBS_POSITION_A_MASK & temp); -		} -		if (rdev->family == CHIP_RV410 || -		    rdev->family == CHIP_R420 || -		    rdev->family == CHIP_R423) -			trbs_ff = memtrbs_r4xx[data]; -		else -			trbs_ff = memtrbs[data]; -		tcas_ff.full += trbs_ff.full; -	} - -	sclk_eff_ff.full = sclk_ff.full; - -	if (rdev->flags & RADEON_IS_AGP) { -		fixed20_12 agpmode_ff; -		agpmode_ff.full = rfixed_const(radeon_agpmode); -		temp_ff.full = rfixed_const_666(16); -		sclk_eff_ff.full -= rfixed_mul(agpmode_ff, temp_ff); -	} -	/* TODO PCIE lanes may affect this - agpmode == 16?? */ - -	if (ASIC_IS_R300(rdev)) { -		sclk_delay_ff.full = rfixed_const(250); -	} else { -		if ((rdev->family == CHIP_RV100) || -		    rdev->flags & RADEON_IS_IGP) { -			if (rdev->mc.vram_is_ddr) -				sclk_delay_ff.full = rfixed_const(41); -			else -				sclk_delay_ff.full = rfixed_const(33); -		} else { -			if (rdev->mc.vram_width == 128) -				sclk_delay_ff.full = rfixed_const(57); -			else -				sclk_delay_ff.full = rfixed_const(41); -		} -	} - -	mc_latency_sclk.full = rfixed_div(sclk_delay_ff, sclk_eff_ff); - -	if (rdev->mc.vram_is_ddr) { -		if (rdev->mc.vram_width == 32) { -			k1.full = rfixed_const(40); -			c  = 3; -		} else { -			k1.full = rfixed_const(20); -			c  = 1; -		} -	} else { -		k1.full = rfixed_const(40); -		c  = 3; -	} - -	temp_ff.full = rfixed_const(2); -	mc_latency_mclk.full = rfixed_mul(trcd_ff, temp_ff); -	temp_ff.full = rfixed_const(c); -	mc_latency_mclk.full += rfixed_mul(tcas_ff, temp_ff); -	temp_ff.full = rfixed_const(4); -	mc_latency_mclk.full += rfixed_mul(tras_ff, temp_ff); -	mc_latency_mclk.full += rfixed_mul(trp_ff, temp_ff); -	mc_latency_mclk.full += k1.full; - -	mc_latency_mclk.full = rfixed_div(mc_latency_mclk, mclk_ff); -	mc_latency_mclk.full += rfixed_div(temp_ff, sclk_eff_ff); - -	/* -	  HW cursor time assuming worst case of full size colour cursor. -	*/ -	temp_ff.full = rfixed_const((2 * (cur_size - (rdev->mc.vram_is_ddr + 1)))); -	temp_ff.full += trcd_ff.full; -	if (temp_ff.full < tras_ff.full) -		temp_ff.full = tras_ff.full; -	cur_latency_mclk.full = rfixed_div(temp_ff, mclk_ff); - -	temp_ff.full = rfixed_const(cur_size); -	cur_latency_sclk.full = rfixed_div(temp_ff, sclk_eff_ff); -	/* -	  Find the total latency for the display data. -	*/ -	disp_latency_overhead.full = rfixed_const(80); -	disp_latency_overhead.full = rfixed_div(disp_latency_overhead, sclk_ff); -	mc_latency_mclk.full += disp_latency_overhead.full + cur_latency_mclk.full; -	mc_latency_sclk.full += disp_latency_overhead.full + cur_latency_sclk.full; - -	if (mc_latency_mclk.full > mc_latency_sclk.full) -		disp_latency.full = mc_latency_mclk.full; -	else -		disp_latency.full = mc_latency_sclk.full; - -	/* setup Max GRPH_STOP_REQ default value */ -	if (ASIC_IS_RV100(rdev)) -		max_stop_req = 0x5c; -	else -		max_stop_req = 0x7c; - -	if (mode1) { -		/*  CRTC1 -		    Set GRPH_BUFFER_CNTL register using h/w defined optimal values. -		    GRPH_STOP_REQ <= MIN[ 0x7C, (CRTC_H_DISP + 1) * (bit depth) / 0x10 ] -		*/ -		stop_req = mode1->hdisplay * pixel_bytes1 / 16; - -		if (stop_req > max_stop_req) -			stop_req = max_stop_req; - -		/* -		  Find the drain rate of the display buffer. -		*/ -		temp_ff.full = rfixed_const((16/pixel_bytes1)); -		disp_drain_rate.full = rfixed_div(pix_clk, temp_ff); - -		/* -		  Find the critical point of the display buffer. -		*/ -		crit_point_ff.full = rfixed_mul(disp_drain_rate, disp_latency); -		crit_point_ff.full += rfixed_const_half(0); - -		critical_point = rfixed_trunc(crit_point_ff); - -		if (rdev->disp_priority == 2) { -			critical_point = 0; -		} - -		/* -		  The critical point should never be above max_stop_req-4.  Setting -		  GRPH_CRITICAL_CNTL = 0 will thus force high priority all the time. -		*/ -		if (max_stop_req - critical_point < 4) -			critical_point = 0; - -		if (critical_point == 0 && mode2 && rdev->family == CHIP_R300) { -			/* some R300 cards have problem with this set to 0, when CRTC2 is enabled.*/ -			critical_point = 0x10; -		} - -		temp = RREG32(RADEON_GRPH_BUFFER_CNTL); -		temp &= ~(RADEON_GRPH_STOP_REQ_MASK); -		temp |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT); -		temp &= ~(RADEON_GRPH_START_REQ_MASK); -		if ((rdev->family == CHIP_R350) && -		    (stop_req > 0x15)) { -			stop_req -= 0x10; -		} -		temp |= (stop_req << RADEON_GRPH_START_REQ_SHIFT); -		temp |= RADEON_GRPH_BUFFER_SIZE; -		temp &= ~(RADEON_GRPH_CRITICAL_CNTL   | -			  RADEON_GRPH_CRITICAL_AT_SOF | -			  RADEON_GRPH_STOP_CNTL); -		/* -		  Write the result into the register. -		*/ -		WREG32(RADEON_GRPH_BUFFER_CNTL, ((temp & ~RADEON_GRPH_CRITICAL_POINT_MASK) | -						       (critical_point << RADEON_GRPH_CRITICAL_POINT_SHIFT))); - -#if 0 -		if ((rdev->family == CHIP_RS400) || -		    (rdev->family == CHIP_RS480)) { -			/* attempt to program RS400 disp regs correctly ??? */ -			temp = RREG32(RS400_DISP1_REG_CNTL); -			temp &= ~(RS400_DISP1_START_REQ_LEVEL_MASK | -				  RS400_DISP1_STOP_REQ_LEVEL_MASK); -			WREG32(RS400_DISP1_REQ_CNTL1, (temp | -						       (critical_point << RS400_DISP1_START_REQ_LEVEL_SHIFT) | -						       (critical_point << RS400_DISP1_STOP_REQ_LEVEL_SHIFT))); -			temp = RREG32(RS400_DMIF_MEM_CNTL1); -			temp &= ~(RS400_DISP1_CRITICAL_POINT_START_MASK | -				  RS400_DISP1_CRITICAL_POINT_STOP_MASK); -			WREG32(RS400_DMIF_MEM_CNTL1, (temp | -						      (critical_point << RS400_DISP1_CRITICAL_POINT_START_SHIFT) | -						      (critical_point << RS400_DISP1_CRITICAL_POINT_STOP_SHIFT))); -		} -#endif - -		DRM_DEBUG("GRPH_BUFFER_CNTL from to %x\n", -			  /* 	  (unsigned int)info->SavedReg->grph_buffer_cntl, */ -			  (unsigned int)RREG32(RADEON_GRPH_BUFFER_CNTL)); -	} - -	if (mode2) { -		u32 grph2_cntl; -		stop_req = mode2->hdisplay * pixel_bytes2 / 16; - -		if (stop_req > max_stop_req) -			stop_req = max_stop_req; - -		/* -		  Find the drain rate of the display buffer. -		*/ -		temp_ff.full = rfixed_const((16/pixel_bytes2)); -		disp_drain_rate2.full = rfixed_div(pix_clk2, temp_ff); - -		grph2_cntl = RREG32(RADEON_GRPH2_BUFFER_CNTL); -		grph2_cntl &= ~(RADEON_GRPH_STOP_REQ_MASK); -		grph2_cntl |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT); -		grph2_cntl &= ~(RADEON_GRPH_START_REQ_MASK); -		if ((rdev->family == CHIP_R350) && -		    (stop_req > 0x15)) { -			stop_req -= 0x10; -		} -		grph2_cntl |= (stop_req << RADEON_GRPH_START_REQ_SHIFT); -		grph2_cntl |= RADEON_GRPH_BUFFER_SIZE; -		grph2_cntl &= ~(RADEON_GRPH_CRITICAL_CNTL   | -			  RADEON_GRPH_CRITICAL_AT_SOF | -			  RADEON_GRPH_STOP_CNTL); - -		if ((rdev->family == CHIP_RS100) || -		    (rdev->family == CHIP_RS200)) -			critical_point2 = 0; -		else { -			temp = (rdev->mc.vram_width * rdev->mc.vram_is_ddr + 1)/128; -			temp_ff.full = rfixed_const(temp); -			temp_ff.full = rfixed_mul(mclk_ff, temp_ff); -			if (sclk_ff.full < temp_ff.full) -				temp_ff.full = sclk_ff.full; - -			read_return_rate.full = temp_ff.full; - -			if (mode1) { -				temp_ff.full = read_return_rate.full - disp_drain_rate.full; -				time_disp1_drop_priority.full = rfixed_div(crit_point_ff, temp_ff); -			} else { -				time_disp1_drop_priority.full = 0; -			} -			crit_point_ff.full = disp_latency.full + time_disp1_drop_priority.full + disp_latency.full; -			crit_point_ff.full = rfixed_mul(crit_point_ff, disp_drain_rate2); -			crit_point_ff.full += rfixed_const_half(0); - -			critical_point2 = rfixed_trunc(crit_point_ff); - -			if (rdev->disp_priority == 2) { -				critical_point2 = 0; -			} - -			if (max_stop_req - critical_point2 < 4) -				critical_point2 = 0; - -		} - -		if (critical_point2 == 0 && rdev->family == CHIP_R300) { -			/* some R300 cards have problem with this set to 0 */ -			critical_point2 = 0x10; -		} - -		WREG32(RADEON_GRPH2_BUFFER_CNTL, ((grph2_cntl & ~RADEON_GRPH_CRITICAL_POINT_MASK) | -						  (critical_point2 << RADEON_GRPH_CRITICAL_POINT_SHIFT))); - -		if ((rdev->family == CHIP_RS400) || -		    (rdev->family == CHIP_RS480)) { -#if 0 -			/* attempt to program RS400 disp2 regs correctly ??? */ -			temp = RREG32(RS400_DISP2_REQ_CNTL1); -			temp &= ~(RS400_DISP2_START_REQ_LEVEL_MASK | -				  RS400_DISP2_STOP_REQ_LEVEL_MASK); -			WREG32(RS400_DISP2_REQ_CNTL1, (temp | -						       (critical_point2 << RS400_DISP1_START_REQ_LEVEL_SHIFT) | -						       (critical_point2 << RS400_DISP1_STOP_REQ_LEVEL_SHIFT))); -			temp = RREG32(RS400_DISP2_REQ_CNTL2); -			temp &= ~(RS400_DISP2_CRITICAL_POINT_START_MASK | -				  RS400_DISP2_CRITICAL_POINT_STOP_MASK); -			WREG32(RS400_DISP2_REQ_CNTL2, (temp | -						       (critical_point2 << RS400_DISP2_CRITICAL_POINT_START_SHIFT) | -						       (critical_point2 << RS400_DISP2_CRITICAL_POINT_STOP_SHIFT))); -#endif -			WREG32(RS400_DISP2_REQ_CNTL1, 0x105DC1CC); -			WREG32(RS400_DISP2_REQ_CNTL2, 0x2749D000); -			WREG32(RS400_DMIF_MEM_CNTL1,  0x29CA71DC); -			WREG32(RS400_DISP1_REQ_CNTL1, 0x28FBC3AC); -		} - -		DRM_DEBUG("GRPH2_BUFFER_CNTL from to %x\n", -			  (unsigned int)RREG32(RADEON_GRPH2_BUFFER_CNTL)); -	} -} diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 2c2f42de1d4..9322675ef6d 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -30,170 +30,6 @@  #include "atom.h" -static void radeon_legacy_rmx_mode_set(struct drm_encoder *encoder, -				       struct drm_display_mode *mode, -				       struct drm_display_mode *adjusted_mode) -{ -	struct drm_device *dev = encoder->dev; -	struct radeon_device *rdev = dev->dev_private; -	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); -	int    xres = mode->hdisplay; -	int    yres = mode->vdisplay; -	bool   hscale = true, vscale = true; -	int    hsync_wid; -	int    vsync_wid; -	int    hsync_start; -	uint32_t scale, inc; -	uint32_t fp_horz_stretch, fp_vert_stretch, crtc_more_cntl, fp_horz_vert_active; -	uint32_t fp_h_sync_strt_wid, fp_v_sync_strt_wid, fp_crtc_h_total_disp, fp_crtc_v_total_disp; -	struct radeon_native_mode *native_mode = &radeon_encoder->native_mode; - -	DRM_DEBUG("\n"); - -	fp_vert_stretch = RREG32(RADEON_FP_VERT_STRETCH) & -		(RADEON_VERT_STRETCH_RESERVED | -		 RADEON_VERT_AUTO_RATIO_INC); -	fp_horz_stretch = RREG32(RADEON_FP_HORZ_STRETCH) & -		(RADEON_HORZ_FP_LOOP_STRETCH | -		 RADEON_HORZ_AUTO_RATIO_INC); - -	crtc_more_cntl = 0; -	if ((rdev->family == CHIP_RS100) || -	    (rdev->family == CHIP_RS200)) { -		/* This is to workaround the asic bug for RMX, some versions -		   of BIOS dosen't have this register initialized correctly. */ -		crtc_more_cntl |= RADEON_CRTC_H_CUTOFF_ACTIVE_EN; -	} - - -	fp_crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff) -				| ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16)); - -	hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8; -	if (!hsync_wid) -		hsync_wid = 1; -	hsync_start = mode->crtc_hsync_start - 8; - -	fp_h_sync_strt_wid = ((hsync_start & 0x1fff) -			      | ((hsync_wid & 0x3f) << 16) -			      | ((mode->flags & DRM_MODE_FLAG_NHSYNC) -				 ? RADEON_CRTC_H_SYNC_POL -				 : 0)); - -	fp_crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff) -				| ((mode->crtc_vdisplay - 1) << 16)); - -	vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start; -	if (!vsync_wid) -		vsync_wid = 1; - -	fp_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff) -			      | ((vsync_wid & 0x1f) << 16) -			      | ((mode->flags & DRM_MODE_FLAG_NVSYNC) -				 ? RADEON_CRTC_V_SYNC_POL -				 : 0)); - -	fp_horz_vert_active = 0; - -	if (native_mode->panel_xres == 0 || -	    native_mode->panel_yres == 0) { -		hscale = false; -		vscale = false; -	} else { -		if (xres > native_mode->panel_xres) -			xres = native_mode->panel_xres; -		if (yres > native_mode->panel_yres) -			yres = native_mode->panel_yres; - -		if (xres == native_mode->panel_xres) -			hscale = false; -		if (yres == native_mode->panel_yres) -			vscale = false; -	} - -	if (radeon_encoder->flags & RADEON_USE_RMX) { -		if (radeon_encoder->rmx_type != RMX_CENTER) { -			if (!hscale) -				fp_horz_stretch |= ((xres/8-1) << 16); -			else { -				inc = (fp_horz_stretch & RADEON_HORZ_AUTO_RATIO_INC) ? 1 : 0; -				scale = ((xres + inc) * RADEON_HORZ_STRETCH_RATIO_MAX) -					/ native_mode->panel_xres + 1; -				fp_horz_stretch |= (((scale) & RADEON_HORZ_STRETCH_RATIO_MASK) | -						    RADEON_HORZ_STRETCH_BLEND | -						    RADEON_HORZ_STRETCH_ENABLE | -						    ((native_mode->panel_xres/8-1) << 16)); -			} - -			if (!vscale) -				fp_vert_stretch |= ((yres-1) << 12); -			else { -				inc = (fp_vert_stretch & RADEON_VERT_AUTO_RATIO_INC) ? 1 : 0; -				scale = ((yres + inc) * RADEON_VERT_STRETCH_RATIO_MAX) -					/ native_mode->panel_yres + 1; -				fp_vert_stretch |= (((scale) & RADEON_VERT_STRETCH_RATIO_MASK) | -						    RADEON_VERT_STRETCH_ENABLE | -						    RADEON_VERT_STRETCH_BLEND | -						    ((native_mode->panel_yres-1) << 12)); -			} -		} else if (radeon_encoder->rmx_type == RMX_CENTER) { -			int    blank_width; - -			fp_horz_stretch |= ((xres/8-1) << 16); -			fp_vert_stretch |= ((yres-1) << 12); - -			crtc_more_cntl |= (RADEON_CRTC_AUTO_HORZ_CENTER_EN | -					   RADEON_CRTC_AUTO_VERT_CENTER_EN); - -			blank_width = (mode->crtc_hblank_end - mode->crtc_hblank_start) / 8; -			if (blank_width > 110) -				blank_width = 110; - -			fp_crtc_h_total_disp = (((blank_width) & 0x3ff) -						| ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16)); - -			hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8; -			if (!hsync_wid) -				hsync_wid = 1; - -			fp_h_sync_strt_wid = ((((mode->crtc_hsync_start - mode->crtc_hblank_start) / 8) & 0x1fff) -					      | ((hsync_wid & 0x3f) << 16) -					      | ((mode->flags & DRM_MODE_FLAG_NHSYNC) -						 ? RADEON_CRTC_H_SYNC_POL -						 : 0)); - -			fp_crtc_v_total_disp = (((mode->crtc_vblank_end - mode->crtc_vblank_start) & 0xffff) -						| ((mode->crtc_vdisplay - 1) << 16)); - -			vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start; -			if (!vsync_wid) -				vsync_wid = 1; - -			fp_v_sync_strt_wid = ((((mode->crtc_vsync_start - mode->crtc_vblank_start) & 0xfff) -					       | ((vsync_wid & 0x1f) << 16) -					       | ((mode->flags & DRM_MODE_FLAG_NVSYNC) -						  ? RADEON_CRTC_V_SYNC_POL -						  : 0))); - -			fp_horz_vert_active = (((native_mode->panel_yres) & 0xfff) | -					       (((native_mode->panel_xres / 8) & 0x1ff) << 16)); -		} -	} else { -		fp_horz_stretch |= ((xres/8-1) << 16); -		fp_vert_stretch |= ((yres-1) << 12); -	} - -	WREG32(RADEON_FP_HORZ_STRETCH,      fp_horz_stretch); -	WREG32(RADEON_FP_VERT_STRETCH,      fp_vert_stretch); -	WREG32(RADEON_CRTC_MORE_CNTL,       crtc_more_cntl); -	WREG32(RADEON_FP_HORZ_VERT_ACTIVE,  fp_horz_vert_active); -	WREG32(RADEON_FP_H_SYNC_STRT_WID,   fp_h_sync_strt_wid); -	WREG32(RADEON_FP_V_SYNC_STRT_WID,   fp_v_sync_strt_wid); -	WREG32(RADEON_FP_CRTC_H_TOTAL_DISP, fp_crtc_h_total_disp); -	WREG32(RADEON_FP_CRTC_V_TOTAL_DISP, fp_crtc_v_total_disp); - -} -  static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)  {  	struct drm_device *dev = encoder->dev; @@ -287,9 +123,6 @@ static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder,  	DRM_DEBUG("\n"); -	if (radeon_crtc->crtc_id == 0) -		radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); -  	lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL);  	lvds_pll_cntl &= ~RADEON_LVDS_PLL_EN; @@ -318,7 +151,7 @@ static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder,  	if (radeon_crtc->crtc_id == 0) {  		if (ASIC_IS_R300(rdev)) { -			if (radeon_encoder->flags & RADEON_USE_RMX) +			if (radeon_encoder->rmx_type != RMX_OFF)  				lvds_pll_cntl |= R300_LVDS_SRC_SEL_RMX;  		} else  			lvds_gen_cntl &= ~RADEON_LVDS_SEL_CRTC2; @@ -350,8 +183,6 @@ static bool radeon_legacy_lvds_mode_fixup(struct drm_encoder *encoder,  	drm_mode_set_crtcinfo(adjusted_mode, 0); -	radeon_encoder->flags &= ~RADEON_USE_RMX; -  	if (radeon_encoder->rmx_type != RMX_OFF)  		radeon_rmx_mode_fixup(encoder, mode, adjusted_mode); @@ -455,9 +286,6 @@ static void radeon_legacy_primary_dac_mode_set(struct drm_encoder *encoder,  	DRM_DEBUG("\n"); -	if (radeon_crtc->crtc_id == 0) -		radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); -  	if (radeon_crtc->crtc_id == 0) {  		if (rdev->family == CHIP_R200 || ASIC_IS_R300(rdev)) {  			disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL) & @@ -653,9 +481,6 @@ static void radeon_legacy_tmds_int_mode_set(struct drm_encoder *encoder,  	DRM_DEBUG("\n"); -	if (radeon_crtc->crtc_id == 0) -		radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); -  	tmp = tmds_pll_cntl = RREG32(RADEON_TMDS_PLL_CNTL);  	tmp &= 0xfffff;  	if (rdev->family == CHIP_RV280) { @@ -711,7 +536,7 @@ static void radeon_legacy_tmds_int_mode_set(struct drm_encoder *encoder,      if (radeon_crtc->crtc_id == 0) {  	    if (ASIC_IS_R300(rdev) || rdev->family == CHIP_R200) {  		    fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK; -		    if (radeon_encoder->flags & RADEON_USE_RMX) +		    if (radeon_encoder->rmx_type != RMX_OFF)  			    fp_gen_cntl |= R200_FP_SOURCE_SEL_RMX;  		    else  			    fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC1; @@ -820,9 +645,6 @@ static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder,  	DRM_DEBUG("\n"); -	if (radeon_crtc->crtc_id == 0) -		radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); -  	if (rdev->is_atom_bios) {  		radeon_encoder->pixel_clock = adjusted_mode->clock;  		atombios_external_tmds_setup(encoder, ATOM_ENABLE); @@ -856,7 +678,7 @@ static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder,  	if (radeon_crtc->crtc_id == 0) {  		if ((rdev->family == CHIP_R200) || ASIC_IS_R300(rdev)) {  			fp2_gen_cntl &= ~R200_FP2_SOURCE_SEL_MASK; -			if (radeon_encoder->flags & RADEON_USE_RMX) +			if (radeon_encoder->rmx_type != RMX_OFF)  				fp2_gen_cntl |= R200_FP2_SOURCE_SEL_RMX;  			else  				fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC1; @@ -1014,9 +836,6 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder,  	DRM_DEBUG("\n"); -	if (radeon_crtc->crtc_id == 0) -		radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); -  	if (rdev->family != CHIP_R200) {  		tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);  		if (rdev->family == CHIP_R420 || @@ -1243,9 +1062,11 @@ radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t  	radeon_encoder->encoder_id = encoder_id;  	radeon_encoder->devices = supported_device; +	radeon_encoder->rmx_type = RMX_OFF;  	switch (radeon_encoder->encoder_id) {  	case ENCODER_OBJECT_ID_INTERNAL_LVDS: +		encoder->possible_crtcs = 0x1;  		drm_encoder_init(dev, encoder, &radeon_legacy_lvds_enc_funcs, DRM_MODE_ENCODER_LVDS);  		drm_encoder_helper_add(encoder, &radeon_legacy_lvds_helper_funcs);  		if (rdev->is_atom_bios) diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 9173b687462..3b09a1f2d8f 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -36,6 +36,9 @@  #include <linux/i2c.h>  #include <linux/i2c-id.h>  #include <linux/i2c-algo-bit.h> +#include "radeon_fixed.h" + +struct radeon_device;  #define to_radeon_crtc(x) container_of(x, struct radeon_crtc, base)  #define to_radeon_connector(x) container_of(x, struct radeon_connector, base) @@ -124,6 +127,7 @@ struct radeon_tmds_pll {  #define RADEON_PLL_PREFER_LOW_POST_DIV  (1 << 8)  #define RADEON_PLL_PREFER_HIGH_POST_DIV (1 << 9)  #define RADEON_PLL_USE_FRAC_FB_DIV      (1 << 10) +#define RADEON_PLL_PREFER_CLOSEST_LOWER (1 << 11)  struct radeon_pll {  	uint16_t reference_freq; @@ -170,6 +174,18 @@ struct radeon_mode_info {  	struct atom_context *atom_context;  	enum radeon_connector_table connector_table;  	bool mode_config_initialized; +	struct radeon_crtc *crtcs[2]; +}; + +struct radeon_native_mode { +	/* preferred mode */ +	uint32_t panel_xres, panel_yres; +	uint32_t hoverplus, hsync_width; +	uint32_t hblank; +	uint32_t voverplus, vsync_width; +	uint32_t vblank; +	uint32_t dotclock; +	uint32_t flags;  };  struct radeon_crtc { @@ -185,19 +201,13 @@ struct radeon_crtc {  	uint64_t cursor_addr;  	int cursor_width;  	int cursor_height; -}; - -#define RADEON_USE_RMX 1 - -struct radeon_native_mode { -	/* preferred mode */ -	uint32_t panel_xres, panel_yres; -	uint32_t hoverplus, hsync_width; -	uint32_t hblank; -	uint32_t voverplus, vsync_width; -	uint32_t vblank; -	uint32_t dotclock; -	uint32_t flags; +	uint32_t legacy_display_base_addr; +	uint32_t legacy_cursor_offset; +	enum radeon_rmx_type rmx_type; +	uint32_t devices; +	fixed20_12 vsc; +	fixed20_12 hsc; +	struct radeon_native_mode native_mode;  };  struct radeon_encoder_primary_dac { @@ -383,16 +393,9 @@ void radeon_enc_destroy(struct drm_encoder *encoder);  void radeon_copy_fb(struct drm_device *dev, struct drm_gem_object *dst_obj);  void radeon_combios_asic_init(struct drm_device *dev);  extern int radeon_static_clocks_init(struct drm_device *dev); -void radeon_init_disp_bw_legacy(struct drm_device *dev, -				struct drm_display_mode *mode1, -				uint32_t pixel_bytes1, -				struct drm_display_mode *mode2, -				uint32_t pixel_bytes2); -void radeon_init_disp_bw_avivo(struct drm_device *dev, -			       struct drm_display_mode *mode1, -			       uint32_t pixel_bytes1, -			       struct drm_display_mode *mode2, -			       uint32_t pixel_bytes2); -void radeon_init_disp_bandwidth(struct drm_device *dev); +bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, +					struct drm_display_mode *mode, +					struct drm_display_mode *adjusted_mode); +void atom_rv515_force_tv_scaler(struct radeon_device *rdev);  #endif diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index bac0d06c52a..b85fb83d7ae 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -44,6 +44,9 @@ struct radeon_object {  	uint64_t			gpu_addr;  	void				*kptr;  	bool				is_iomem; +	uint32_t			tiling_flags; +	uint32_t			pitch; +	int				surface_reg;  };  int radeon_ttm_init(struct radeon_device *rdev); @@ -70,6 +73,7 @@ static void radeon_ttm_object_object_destroy(struct ttm_buffer_object *tobj)  	robj = container_of(tobj, struct radeon_object, tobj);  	list_del_init(&robj->list); +	radeon_object_clear_surface_reg(robj);  	kfree(robj);  } @@ -99,16 +103,16 @@ static inline uint32_t radeon_object_flags_from_domain(uint32_t domain)  {  	uint32_t flags = 0;  	if (domain & RADEON_GEM_DOMAIN_VRAM) { -		flags |= TTM_PL_FLAG_VRAM; +		flags |= TTM_PL_FLAG_VRAM | TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED;  	}  	if (domain & RADEON_GEM_DOMAIN_GTT) { -		flags |= TTM_PL_FLAG_TT; +		flags |= TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING;  	}  	if (domain & RADEON_GEM_DOMAIN_CPU) { -		flags |= TTM_PL_FLAG_SYSTEM; +		flags |= TTM_PL_FLAG_SYSTEM | TTM_PL_MASK_CACHING;  	}  	if (!flags) { -		flags |= TTM_PL_FLAG_SYSTEM; +		flags |= TTM_PL_FLAG_SYSTEM | TTM_PL_MASK_CACHING;  	}  	return flags;  } @@ -141,6 +145,7 @@ int radeon_object_create(struct radeon_device *rdev,  	}  	robj->rdev = rdev;  	robj->gobj = gobj; +	robj->surface_reg = -1;  	INIT_LIST_HEAD(&robj->list);  	flags = radeon_object_flags_from_domain(domain); @@ -304,7 +309,26 @@ int radeon_object_wait(struct radeon_object *robj)  	}  	spin_lock(&robj->tobj.lock);  	if (robj->tobj.sync_obj) { -		r = ttm_bo_wait(&robj->tobj, true, false, false); +		r = ttm_bo_wait(&robj->tobj, true, true, false); +	} +	spin_unlock(&robj->tobj.lock); +	radeon_object_unreserve(robj); +	return r; +} + +int radeon_object_busy_domain(struct radeon_object *robj, uint32_t *cur_placement) +{ +	int r = 0; + +	r = radeon_object_reserve(robj, true); +	if (unlikely(r != 0)) { +		DRM_ERROR("radeon: failed to reserve object for waiting.\n"); +		return r; +	} +	spin_lock(&robj->tobj.lock); +	*cur_placement = robj->tobj.mem.mem_type; +	if (robj->tobj.sync_obj) { +		r = ttm_bo_wait(&robj->tobj, true, true, true);  	}  	spin_unlock(&robj->tobj.lock);  	radeon_object_unreserve(robj); @@ -403,7 +427,6 @@ int radeon_object_list_validate(struct list_head *head, void *fence)  	struct radeon_object *robj;  	struct radeon_fence *old_fence = NULL;  	struct list_head *i; -	uint32_t flags;  	int r;  	r = radeon_object_list_reserve(head); @@ -414,27 +437,25 @@ int radeon_object_list_validate(struct list_head *head, void *fence)  	list_for_each(i, head) {  		lobj = list_entry(i, struct radeon_object_list, list);  		robj = lobj->robj; -		if (lobj->wdomain) { -			flags = radeon_object_flags_from_domain(lobj->wdomain); -			flags |= TTM_PL_FLAG_TT; -		} else { -			flags = radeon_object_flags_from_domain(lobj->rdomain); -			flags |= TTM_PL_FLAG_TT; -			flags |= TTM_PL_FLAG_VRAM; -		}  		if (!robj->pin_count) { -			robj->tobj.proposed_placement = flags | TTM_PL_MASK_CACHING; +			if (lobj->wdomain) { +				robj->tobj.proposed_placement = +					radeon_object_flags_from_domain(lobj->wdomain); +			} else { +				robj->tobj.proposed_placement = +					radeon_object_flags_from_domain(lobj->rdomain); +			}  			r = ttm_buffer_object_validate(&robj->tobj,  						       robj->tobj.proposed_placement,  						       true, false);  			if (unlikely(r)) { -				radeon_object_list_unreserve(head);  				DRM_ERROR("radeon: failed to validate.\n");  				return r;  			}  			radeon_object_gpu_addr(robj);  		}  		lobj->gpu_offset = robj->gpu_addr; +		lobj->tiling_flags = robj->tiling_flags;  		if (fence) {  			old_fence = (struct radeon_fence *)robj->tobj.sync_obj;  			robj->tobj.sync_obj = radeon_fence_ref(fence); @@ -479,3 +500,127 @@ unsigned long radeon_object_size(struct radeon_object *robj)  {  	return robj->tobj.num_pages << PAGE_SHIFT;  } + +int radeon_object_get_surface_reg(struct radeon_object *robj) +{ +	struct radeon_device *rdev = robj->rdev; +	struct radeon_surface_reg *reg; +	struct radeon_object *old_object; +	int steal; +	int i; + +	if (!robj->tiling_flags) +		return 0; + +	if (robj->surface_reg >= 0) { +		reg = &rdev->surface_regs[robj->surface_reg]; +		i = robj->surface_reg; +		goto out; +	} + +	steal = -1; +	for (i = 0; i < RADEON_GEM_MAX_SURFACES; i++) { + +		reg = &rdev->surface_regs[i]; +		if (!reg->robj) +			break; + +		old_object = reg->robj; +		if (old_object->pin_count == 0) +			steal = i; +	} + +	/* if we are all out */ +	if (i == RADEON_GEM_MAX_SURFACES) { +		if (steal == -1) +			return -ENOMEM; +		/* find someone with a surface reg and nuke their BO */ +		reg = &rdev->surface_regs[steal]; +		old_object = reg->robj; +		/* blow away the mapping */ +		DRM_DEBUG("stealing surface reg %d from %p\n", steal, old_object); +		ttm_bo_unmap_virtual(&old_object->tobj); +		old_object->surface_reg = -1; +		i = steal; +	} + +	robj->surface_reg = i; +	reg->robj = robj; + +out: +	radeon_set_surface_reg(rdev, i, robj->tiling_flags, robj->pitch, +			       robj->tobj.mem.mm_node->start << PAGE_SHIFT, +			       robj->tobj.num_pages << PAGE_SHIFT); +	return 0; +} + +void radeon_object_clear_surface_reg(struct radeon_object *robj) +{ +	struct radeon_device *rdev = robj->rdev; +	struct radeon_surface_reg *reg; + +	if (robj->surface_reg == -1) +		return; + +	reg = &rdev->surface_regs[robj->surface_reg]; +	radeon_clear_surface_reg(rdev, robj->surface_reg); + +	reg->robj = NULL; +	robj->surface_reg = -1; +} + +void radeon_object_set_tiling_flags(struct radeon_object *robj, +				    uint32_t tiling_flags, uint32_t pitch) +{ +	robj->tiling_flags = tiling_flags; +	robj->pitch = pitch; +} + +void radeon_object_get_tiling_flags(struct radeon_object *robj, +				    uint32_t *tiling_flags, +				    uint32_t *pitch) +{ +	if (tiling_flags) +		*tiling_flags = robj->tiling_flags; +	if (pitch) +		*pitch = robj->pitch; +} + +int radeon_object_check_tiling(struct radeon_object *robj, bool has_moved, +			       bool force_drop) +{ +	if (!(robj->tiling_flags & RADEON_TILING_SURFACE)) +		return 0; + +	if (force_drop) { +		radeon_object_clear_surface_reg(robj); +		return 0; +	} + +	if (robj->tobj.mem.mem_type != TTM_PL_VRAM) { +		if (!has_moved) +			return 0; + +		if (robj->surface_reg >= 0) +			radeon_object_clear_surface_reg(robj); +		return 0; +	} + +	if ((robj->surface_reg >= 0) && !has_moved) +		return 0; + +	return radeon_object_get_surface_reg(robj); +} + +void radeon_bo_move_notify(struct ttm_buffer_object *bo, +			  struct ttm_mem_reg *mem) +{ +	struct radeon_object *robj = container_of(bo, struct radeon_object, tobj); +	radeon_object_check_tiling(robj, 0, 1); +} + +void radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo) +{ +	struct radeon_object *robj = container_of(bo, struct radeon_object, tobj); +	radeon_object_check_tiling(robj, 0, 0); +} diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index e1b61857446..5a098f304ed 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -982,12 +982,15 @@  #       define RS400_TMDS2_PLLRST           (1 << 1)  #define RADEON_GEN_INT_CNTL                 0x0040 +#	define RADEON_CRTC_VBLANK_MASK		(1 << 0) +#	define RADEON_CRTC2_VBLANK_MASK		(1 << 9)  #	define RADEON_SW_INT_ENABLE		(1 << 25)  #define RADEON_GEN_INT_STATUS               0x0044 -#       define RADEON_VSYNC_INT_AK          (1 <<  2) -#       define RADEON_VSYNC_INT             (1 <<  2) -#       define RADEON_VSYNC2_INT_AK         (1 <<  6) -#       define RADEON_VSYNC2_INT            (1 <<  6) +#	define AVIVO_DISPLAY_INT_STATUS		(1 << 0) +#	define RADEON_CRTC_VBLANK_STAT		(1 << 0) +#	define RADEON_CRTC_VBLANK_STAT_ACK	(1 << 0) +#	define RADEON_CRTC2_VBLANK_STAT		(1 << 9) +#	define RADEON_CRTC2_VBLANK_STAT_ACK	(1 << 9)  #	define RADEON_SW_INT_FIRE		(1 << 26)  #	define RADEON_SW_INT_TEST		(1 << 25)  #	define RADEON_SW_INT_TEST_ACK		(1 << 25) diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index a853261d188..60d159308b8 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -126,32 +126,19 @@ static void radeon_ib_align(struct radeon_device *rdev, struct radeon_ib *ib)  	}  } -static void radeon_ib_cpu_flush(struct radeon_device *rdev, -				struct radeon_ib *ib) -{ -	unsigned long tmp; -	unsigned i; - -	/* To force CPU cache flush ugly but seems reliable */ -	for (i = 0; i < ib->length_dw; i += (rdev->cp.align_mask + 1)) { -		tmp = readl(&ib->ptr[i]); -	} -} -  int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib)  {  	int r = 0;  	mutex_lock(&rdev->ib_pool.mutex);  	radeon_ib_align(rdev, ib); -	radeon_ib_cpu_flush(rdev, ib);  	if (!ib->length_dw || !rdev->cp.ready) {  		/* TODO: Nothings in the ib we should report. */  		mutex_unlock(&rdev->ib_pool.mutex);  		DRM_ERROR("radeon: couldn't schedule IB(%lu).\n", ib->idx);  		return -EINVAL;  	} -	/* 64 dwords should be enought for fence too */ +	/* 64 dwords should be enough for fence too */  	r = radeon_ring_lock(rdev, 64);  	if (r) {  		DRM_ERROR("radeon: scheduling IB failled (%d).\n", r); diff --git a/drivers/gpu/drm/radeon/radeon_share.h b/drivers/gpu/drm/radeon/radeon_share.h new file mode 100644 index 00000000000..63a773578f1 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_share.h @@ -0,0 +1,39 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + *          Alex Deucher + *          Jerome Glisse + */ +#ifndef __RADEON_SHARE_H__ +#define __RADEON_SHARE_H__ + +void r100_vram_init_sizes(struct radeon_device *rdev); + +void rs690_line_buffer_adjust(struct radeon_device *rdev, +			      struct drm_display_mode *mode1, +			      struct drm_display_mode *mode2); + +void rv515_bandwidth_avivo_update(struct radeon_device *rdev); + +#endif diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c new file mode 100644 index 00000000000..03c33cf4e14 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_test.c @@ -0,0 +1,209 @@ +/* + * Copyright 2009 VMware, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Michel Dänzer + */ +#include <drm/drmP.h> +#include <drm/radeon_drm.h> +#include "radeon_reg.h" +#include "radeon.h" + + +/* Test BO GTT->VRAM and VRAM->GTT GPU copies across the whole GTT aperture */ +void radeon_test_moves(struct radeon_device *rdev) +{ +	struct radeon_object *vram_obj = NULL; +	struct radeon_object **gtt_obj = NULL; +	struct radeon_fence *fence = NULL; +	uint64_t gtt_addr, vram_addr; +	unsigned i, n, size; +	int r; + +	size = 1024 * 1024; + +	/* Number of tests = +	 * (Total GTT - IB pool - writeback page - ring buffer) / test size +	 */ +	n = (rdev->mc.gtt_size - RADEON_IB_POOL_SIZE*64*1024 - 4096 - +	     rdev->cp.ring_size) / size; + +	gtt_obj = kzalloc(n * sizeof(*gtt_obj), GFP_KERNEL); +	if (!gtt_obj) { +		DRM_ERROR("Failed to allocate %d pointers\n", n); +		r = 1; +		goto out_cleanup; +	} + +	r = radeon_object_create(rdev, NULL, size, true, RADEON_GEM_DOMAIN_VRAM, +				 false, &vram_obj); +	if (r) { +		DRM_ERROR("Failed to create VRAM object\n"); +		goto out_cleanup; +	} + +	r = radeon_object_pin(vram_obj, RADEON_GEM_DOMAIN_VRAM, &vram_addr); +	if (r) { +		DRM_ERROR("Failed to pin VRAM object\n"); +		goto out_cleanup; +	} + +	for (i = 0; i < n; i++) { +		void *gtt_map, *vram_map; +		void **gtt_start, **gtt_end; +		void **vram_start, **vram_end; + +		r = radeon_object_create(rdev, NULL, size, true, +					 RADEON_GEM_DOMAIN_GTT, false, gtt_obj + i); +		if (r) { +			DRM_ERROR("Failed to create GTT object %d\n", i); +			goto out_cleanup; +		} + +		r = radeon_object_pin(gtt_obj[i], RADEON_GEM_DOMAIN_GTT, >t_addr); +		if (r) { +			DRM_ERROR("Failed to pin GTT object %d\n", i); +			goto out_cleanup; +		} + +		r = radeon_object_kmap(gtt_obj[i], >t_map); +		if (r) { +			DRM_ERROR("Failed to map GTT object %d\n", i); +			goto out_cleanup; +		} + +		for (gtt_start = gtt_map, gtt_end = gtt_map + size; +		     gtt_start < gtt_end; +		     gtt_start++) +			*gtt_start = gtt_start; + +		radeon_object_kunmap(gtt_obj[i]); + +		r = radeon_fence_create(rdev, &fence); +		if (r) { +			DRM_ERROR("Failed to create GTT->VRAM fence %d\n", i); +			goto out_cleanup; +		} + +		r = radeon_copy(rdev, gtt_addr, vram_addr, size / 4096, fence); +		if (r) { +			DRM_ERROR("Failed GTT->VRAM copy %d\n", i); +			goto out_cleanup; +		} + +		r = radeon_fence_wait(fence, false); +		if (r) { +			DRM_ERROR("Failed to wait for GTT->VRAM fence %d\n", i); +			goto out_cleanup; +		} + +		radeon_fence_unref(&fence); + +		r = radeon_object_kmap(vram_obj, &vram_map); +		if (r) { +			DRM_ERROR("Failed to map VRAM object after copy %d\n", i); +			goto out_cleanup; +		} + +		for (gtt_start = gtt_map, gtt_end = gtt_map + size, +		     vram_start = vram_map, vram_end = vram_map + size; +		     vram_start < vram_end; +		     gtt_start++, vram_start++) { +			if (*vram_start != gtt_start) { +				DRM_ERROR("Incorrect GTT->VRAM copy %d: Got 0x%p, " +					  "expected 0x%p (GTT map 0x%p-0x%p)\n", +					  i, *vram_start, gtt_start, gtt_map, +					  gtt_end); +				radeon_object_kunmap(vram_obj); +				goto out_cleanup; +			} +			*vram_start = vram_start; +		} + +		radeon_object_kunmap(vram_obj); + +		r = radeon_fence_create(rdev, &fence); +		if (r) { +			DRM_ERROR("Failed to create VRAM->GTT fence %d\n", i); +			goto out_cleanup; +		} + +		r = radeon_copy(rdev, vram_addr, gtt_addr, size / 4096, fence); +		if (r) { +			DRM_ERROR("Failed VRAM->GTT copy %d\n", i); +			goto out_cleanup; +		} + +		r = radeon_fence_wait(fence, false); +		if (r) { +			DRM_ERROR("Failed to wait for VRAM->GTT fence %d\n", i); +			goto out_cleanup; +		} + +		radeon_fence_unref(&fence); + +		r = radeon_object_kmap(gtt_obj[i], >t_map); +		if (r) { +			DRM_ERROR("Failed to map GTT object after copy %d\n", i); +			goto out_cleanup; +		} + +		for (gtt_start = gtt_map, gtt_end = gtt_map + size, +		     vram_start = vram_map, vram_end = vram_map + size; +		     gtt_start < gtt_end; +		     gtt_start++, vram_start++) { +			if (*gtt_start != vram_start) { +				DRM_ERROR("Incorrect VRAM->GTT copy %d: Got 0x%p, " +					  "expected 0x%p (VRAM map 0x%p-0x%p)\n", +					  i, *gtt_start, vram_start, vram_map, +					  vram_end); +				radeon_object_kunmap(gtt_obj[i]); +				goto out_cleanup; +			} +		} + +		radeon_object_kunmap(gtt_obj[i]); + +		DRM_INFO("Tested GTT->VRAM and VRAM->GTT copy for GTT offset 0x%llx\n", +			 gtt_addr - rdev->mc.gtt_location); +	} + +out_cleanup: +	if (vram_obj) { +		radeon_object_unpin(vram_obj); +		radeon_object_unref(&vram_obj); +	} +	if (gtt_obj) { +		for (i = 0; i < n; i++) { +			if (gtt_obj[i]) { +				radeon_object_unpin(gtt_obj[i]); +				radeon_object_unref(>t_obj[i]); +			} +		} +		kfree(gtt_obj); +	} +	if (fence) { +		radeon_fence_unref(&fence); +	} +	if (r) { +		printk(KERN_WARNING "Error while testing BO move.\n"); +	} +} + diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 343b6d6b99c..6f5ad0802fc 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -376,23 +376,26 @@ static int radeon_bo_move(struct ttm_buffer_object *bo,  	if (!rdev->cp.ready) {  		/* use memcpy */  		DRM_ERROR("CP is not ready use memcpy.\n"); -		return ttm_bo_move_memcpy(bo, evict, no_wait, new_mem); +		goto memcpy;  	}  	if (old_mem->mem_type == TTM_PL_VRAM &&  	    new_mem->mem_type == TTM_PL_SYSTEM) { -		return radeon_move_vram_ram(bo, evict, interruptible, +		r = radeon_move_vram_ram(bo, evict, interruptible,  					    no_wait, new_mem);  	} else if (old_mem->mem_type == TTM_PL_SYSTEM &&  		   new_mem->mem_type == TTM_PL_VRAM) { -		return radeon_move_ram_vram(bo, evict, interruptible, +		r = radeon_move_ram_vram(bo, evict, interruptible,  					    no_wait, new_mem);  	} else {  		r = radeon_move_blit(bo, evict, no_wait, new_mem, old_mem); -		if (unlikely(r)) { -			return r; -		}  	} + +	if (r) { +memcpy: +		r = ttm_bo_move_memcpy(bo, evict, no_wait, new_mem); +	} +  	return r;  } @@ -450,6 +453,8 @@ static struct ttm_bo_driver radeon_bo_driver = {  	.sync_obj_flush = &radeon_sync_obj_flush,  	.sync_obj_unref = &radeon_sync_obj_unref,  	.sync_obj_ref = &radeon_sync_obj_ref, +	.move_notify = &radeon_bo_move_notify, +	.fault_reserve_notify = &radeon_bo_fault_reserve_notify,  };  int radeon_ttm_init(struct radeon_device *rdev) @@ -463,13 +468,14 @@ int radeon_ttm_init(struct radeon_device *rdev)  	/* No others user of address space so set it to 0 */  	r = ttm_bo_device_init(&rdev->mman.bdev,  			       rdev->mman.bo_global_ref.ref.object, -			       &radeon_bo_driver, DRM_FILE_PAGE_OFFSET); +			       &radeon_bo_driver, DRM_FILE_PAGE_OFFSET, +			       rdev->need_dma32);  	if (r) {  		DRM_ERROR("failed initializing buffer object driver(%d).\n", r);  		return r;  	}  	r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_VRAM, 0, -			   ((rdev->mc.aper_size) >> PAGE_SHIFT)); +			   ((rdev->mc.real_vram_size) >> PAGE_SHIFT));  	if (r) {  		DRM_ERROR("Failed initializing VRAM heap.\n");  		return r; @@ -486,7 +492,7 @@ int radeon_ttm_init(struct radeon_device *rdev)  		return r;  	}  	DRM_INFO("radeon: %uM of VRAM memory ready\n", -		 rdev->mc.vram_size / (1024 * 1024)); +		 rdev->mc.real_vram_size / (1024 * 1024));  	r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_TT, 0,  			   ((rdev->mc.gtt_size) >> PAGE_SHIFT));  	if (r) { diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index cc074b5a8f7..b29affd9c5d 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -29,6 +29,7 @@  #include <drm/drmP.h>  #include "radeon_reg.h"  #include "radeon.h" +#include "radeon_share.h"  /* rs400,rs480 depends on : */  void r100_hdp_reset(struct radeon_device *rdev); @@ -164,7 +165,9 @@ int rs400_gart_enable(struct radeon_device *rdev)  		WREG32(RADEON_BUS_CNTL, tmp);  	}  	/* Table should be in 32bits address space so ignore bits above. */ -	tmp = rdev->gart.table_addr & 0xfffff000; +	tmp = (u32)rdev->gart.table_addr & 0xfffff000; +	tmp |= (upper_32_bits(rdev->gart.table_addr) & 0xff) << 4; +  	WREG32_MC(RS480_GART_BASE, tmp);  	/* TODO: more tweaking here */  	WREG32_MC(RS480_GART_FEATURE_ID, @@ -201,10 +204,17 @@ void rs400_gart_disable(struct radeon_device *rdev)  int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)  { +	uint32_t entry; +  	if (i < 0 || i > rdev->gart.num_gpu_pages) {  		return -EINVAL;  	} -	rdev->gart.table.ram.ptr[i] = cpu_to_le32(((uint32_t)addr) | 0xC); + +	entry = (lower_32_bits(addr) & PAGE_MASK) | +		((upper_32_bits(addr) & 0xff) << 4) | +		0xc; +	entry = cpu_to_le32(entry); +	rdev->gart.table.ram.ptr[i] = entry;  	return 0;  } @@ -223,10 +233,9 @@ int rs400_mc_init(struct radeon_device *rdev)  	rs400_gpu_init(rdev);  	rs400_gart_disable(rdev); -	rdev->mc.gtt_location = rdev->mc.vram_size; +	rdev->mc.gtt_location = rdev->mc.mc_vram_size;  	rdev->mc.gtt_location += (rdev->mc.gtt_size - 1);  	rdev->mc.gtt_location &= ~(rdev->mc.gtt_size - 1); -	rdev->mc.vram_location = 0xFFFFFFFFUL;  	r = radeon_mc_setup(rdev);  	if (r) {  		return r; @@ -238,7 +247,7 @@ int rs400_mc_init(struct radeon_device *rdev)  		       "programming pipes. Bad things might happen.\n");  	} -	tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1; +	tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;  	tmp = REG_SET(RADEON_MC_FB_TOP, tmp >> 16);  	tmp |= REG_SET(RADEON_MC_FB_START, rdev->mc.vram_location >> 16);  	WREG32(RADEON_MC_FB_LOCATION, tmp); @@ -284,21 +293,12 @@ void rs400_gpu_init(struct radeon_device *rdev)   */  void rs400_vram_info(struct radeon_device *rdev)  { -	uint32_t tom; -  	rs400_gart_adjust_size(rdev);  	/* DDR for all card after R300 & IGP */  	rdev->mc.vram_is_ddr = true;  	rdev->mc.vram_width = 128; -	/* read NB_TOM to get the amount of ram stolen for the GPU */ -	tom = RREG32(RADEON_NB_TOM); -	rdev->mc.vram_size = (((tom >> 16) - (tom & 0xffff) + 1) << 16); -	WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size); - -	/* Could aper size report 0 ? */ -	rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); -	rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); +	r100_vram_init_sizes(rdev);  } diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index ab0c967553e..7e8ce983a90 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -223,7 +223,7 @@ int rs600_mc_init(struct radeon_device *rdev)  		printk(KERN_WARNING "Failed to wait MC idle while "  		       "programming pipes. Bad things might happen.\n");  	} -	tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1; +	tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;  	tmp = REG_SET(RS600_MC_FB_TOP, tmp >> 16);  	tmp |= REG_SET(RS600_MC_FB_START, rdev->mc.vram_location >> 16);  	WREG32_MC(RS600_MC_FB_LOCATION, tmp); @@ -240,6 +240,88 @@ void rs600_mc_fini(struct radeon_device *rdev)  /* + * Interrupts + */ +int rs600_irq_set(struct radeon_device *rdev) +{ +	uint32_t tmp = 0; +	uint32_t mode_int = 0; + +	if (rdev->irq.sw_int) { +		tmp |= RADEON_SW_INT_ENABLE; +	} +	if (rdev->irq.crtc_vblank_int[0]) { +		tmp |= AVIVO_DISPLAY_INT_STATUS; +		mode_int |= AVIVO_D1MODE_INT_MASK; +	} +	if (rdev->irq.crtc_vblank_int[1]) { +		tmp |= AVIVO_DISPLAY_INT_STATUS; +		mode_int |= AVIVO_D2MODE_INT_MASK; +	} +	WREG32(RADEON_GEN_INT_CNTL, tmp); +	WREG32(AVIVO_DxMODE_INT_MASK, mode_int); +	return 0; +} + +static inline uint32_t rs600_irq_ack(struct radeon_device *rdev, u32 *r500_disp_int) +{ +	uint32_t irqs = RREG32(RADEON_GEN_INT_STATUS); +	uint32_t irq_mask = RADEON_SW_INT_TEST; + +	if (irqs & AVIVO_DISPLAY_INT_STATUS) { +		*r500_disp_int = RREG32(AVIVO_DISP_INTERRUPT_STATUS); +		if (*r500_disp_int & AVIVO_D1_VBLANK_INTERRUPT) { +			WREG32(AVIVO_D1MODE_VBLANK_STATUS, AVIVO_VBLANK_ACK); +		} +		if (*r500_disp_int & AVIVO_D2_VBLANK_INTERRUPT) { +			WREG32(AVIVO_D2MODE_VBLANK_STATUS, AVIVO_VBLANK_ACK); +		} +	} else { +		*r500_disp_int = 0; +	} + +	if (irqs) { +		WREG32(RADEON_GEN_INT_STATUS, irqs); +	} +	return irqs & irq_mask; +} + +int rs600_irq_process(struct radeon_device *rdev) +{ +	uint32_t status; +	uint32_t r500_disp_int; + +	status = rs600_irq_ack(rdev, &r500_disp_int); +	if (!status && !r500_disp_int) { +		return IRQ_NONE; +	} +	while (status || r500_disp_int) { +		/* SW interrupt */ +		if (status & RADEON_SW_INT_TEST) { +			radeon_fence_process(rdev); +		} +		/* Vertical blank interrupts */ +		if (r500_disp_int & AVIVO_D1_VBLANK_INTERRUPT) { +			drm_handle_vblank(rdev->ddev, 0); +		} +		if (r500_disp_int & AVIVO_D2_VBLANK_INTERRUPT) { +			drm_handle_vblank(rdev->ddev, 1); +		} +		status = rs600_irq_ack(rdev, &r500_disp_int); +	} +	return IRQ_HANDLED; +} + +u32 rs600_get_vblank_counter(struct radeon_device *rdev, int crtc) +{ +	if (crtc == 0) +		return RREG32(AVIVO_D1CRTC_FRAME_COUNT); +	else +		return RREG32(AVIVO_D2CRTC_FRAME_COUNT); +} + + +/*   * Global GPU functions   */  void rs600_disable_vga(struct radeon_device *rdev) @@ -301,6 +383,11 @@ void rs600_vram_info(struct radeon_device *rdev)  	rdev->mc.vram_width = 128;  } +void rs600_bandwidth_update(struct radeon_device *rdev) +{ +	/* FIXME: implement, should this be like rs690 ? */ +} +  /*   * Indirect registers accessor diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index 79ba85042b5..bc6b7c5339b 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -28,6 +28,9 @@  #include "drmP.h"  #include "radeon_reg.h"  #include "radeon.h" +#include "rs690r.h" +#include "atom.h" +#include "atom-bits.h"  /* rs690,rs740 depends on : */  void r100_hdp_reset(struct radeon_device *rdev); @@ -64,7 +67,7 @@ int rs690_mc_init(struct radeon_device *rdev)  	rs400_gart_disable(rdev);  	/* Setup GPU memory space */ -	rdev->mc.gtt_location = rdev->mc.vram_size; +	rdev->mc.gtt_location = rdev->mc.mc_vram_size;  	rdev->mc.gtt_location += (rdev->mc.gtt_size - 1);  	rdev->mc.gtt_location &= ~(rdev->mc.gtt_size - 1);  	rdev->mc.vram_location = 0xFFFFFFFFUL; @@ -79,7 +82,7 @@ int rs690_mc_init(struct radeon_device *rdev)  		printk(KERN_WARNING "Failed to wait MC idle while "  		       "programming pipes. Bad things might happen.\n");  	} -	tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1; +	tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;  	tmp = REG_SET(RS690_MC_FB_TOP, tmp >> 16);  	tmp |= REG_SET(RS690_MC_FB_START, rdev->mc.vram_location >> 16);  	WREG32_MC(RS690_MCCFG_FB_LOCATION, tmp); @@ -138,9 +141,82 @@ void rs690_gpu_init(struct radeon_device *rdev)  /*   * VRAM info.   */ +void rs690_pm_info(struct radeon_device *rdev) +{ +	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); +	struct _ATOM_INTEGRATED_SYSTEM_INFO *info; +	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 *info_v2; +	void *ptr; +	uint16_t data_offset; +	uint8_t frev, crev; +	fixed20_12 tmp; + +	atom_parse_data_header(rdev->mode_info.atom_context, index, NULL, +			       &frev, &crev, &data_offset); +	ptr = rdev->mode_info.atom_context->bios + data_offset; +	info = (struct _ATOM_INTEGRATED_SYSTEM_INFO *)ptr; +	info_v2 = (struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 *)ptr; +	/* Get various system informations from bios */ +	switch (crev) { +	case 1: +		tmp.full = rfixed_const(100); +		rdev->pm.igp_sideport_mclk.full = rfixed_const(info->ulBootUpMemoryClock); +		rdev->pm.igp_sideport_mclk.full = rfixed_div(rdev->pm.igp_sideport_mclk, tmp); +		rdev->pm.igp_system_mclk.full = rfixed_const(le16_to_cpu(info->usK8MemoryClock)); +		rdev->pm.igp_ht_link_clk.full = rfixed_const(le16_to_cpu(info->usFSBClock)); +		rdev->pm.igp_ht_link_width.full = rfixed_const(info->ucHTLinkWidth); +		break; +	case 2: +		tmp.full = rfixed_const(100); +		rdev->pm.igp_sideport_mclk.full = rfixed_const(info_v2->ulBootUpSidePortClock); +		rdev->pm.igp_sideport_mclk.full = rfixed_div(rdev->pm.igp_sideport_mclk, tmp); +		rdev->pm.igp_system_mclk.full = rfixed_const(info_v2->ulBootUpUMAClock); +		rdev->pm.igp_system_mclk.full = rfixed_div(rdev->pm.igp_system_mclk, tmp); +		rdev->pm.igp_ht_link_clk.full = rfixed_const(info_v2->ulHTLinkFreq); +		rdev->pm.igp_ht_link_clk.full = rfixed_div(rdev->pm.igp_ht_link_clk, tmp); +		rdev->pm.igp_ht_link_width.full = rfixed_const(le16_to_cpu(info_v2->usMinHTLinkWidth)); +		break; +	default: +		tmp.full = rfixed_const(100); +		/* We assume the slower possible clock ie worst case */ +		/* DDR 333Mhz */ +		rdev->pm.igp_sideport_mclk.full = rfixed_const(333); +		/* FIXME: system clock ? */ +		rdev->pm.igp_system_mclk.full = rfixed_const(100); +		rdev->pm.igp_system_mclk.full = rfixed_div(rdev->pm.igp_system_mclk, tmp); +		rdev->pm.igp_ht_link_clk.full = rfixed_const(200); +		rdev->pm.igp_ht_link_width.full = rfixed_const(8); +		DRM_ERROR("No integrated system info for your GPU, using safe default\n"); +		break; +	} +	/* Compute various bandwidth */ +	/* k8_bandwidth = (memory_clk / 2) * 2 * 8 * 0.5 = memory_clk * 4  */ +	tmp.full = rfixed_const(4); +	rdev->pm.k8_bandwidth.full = rfixed_mul(rdev->pm.igp_system_mclk, tmp); +	/* ht_bandwidth = ht_clk * 2 * ht_width / 8 * 0.8 +	 *              = ht_clk * ht_width / 5 +	 */ +	tmp.full = rfixed_const(5); +	rdev->pm.ht_bandwidth.full = rfixed_mul(rdev->pm.igp_ht_link_clk, +						rdev->pm.igp_ht_link_width); +	rdev->pm.ht_bandwidth.full = rfixed_div(rdev->pm.ht_bandwidth, tmp); +	if (tmp.full < rdev->pm.max_bandwidth.full) { +		/* HT link is a limiting factor */ +		rdev->pm.max_bandwidth.full = tmp.full; +	} +	/* sideport_bandwidth = (sideport_clk / 2) * 2 * 2 * 0.7 +	 *                    = (sideport_clk * 14) / 10 +	 */ +	tmp.full = rfixed_const(14); +	rdev->pm.sideport_bandwidth.full = rfixed_mul(rdev->pm.igp_sideport_mclk, tmp); +	tmp.full = rfixed_const(10); +	rdev->pm.sideport_bandwidth.full = rfixed_div(rdev->pm.sideport_bandwidth, tmp); +} +  void rs690_vram_info(struct radeon_device *rdev)  {  	uint32_t tmp; +	fixed20_12 a;  	rs400_gart_adjust_size(rdev);  	/* DDR for all card after R300 & IGP */ @@ -152,12 +228,409 @@ void rs690_vram_info(struct radeon_device *rdev)  	} else {  		rdev->mc.vram_width = 64;  	} -	rdev->mc.vram_size = RREG32(RADEON_CONFIG_MEMSIZE); +	rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE); +	rdev->mc.mc_vram_size = rdev->mc.real_vram_size;  	rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);  	rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); +	rs690_pm_info(rdev); +	/* FIXME: we should enforce default clock in case GPU is not in +	 * default setup +	 */ +	a.full = rfixed_const(100); +	rdev->pm.sclk.full = rfixed_const(rdev->clock.default_sclk); +	rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a); +	a.full = rfixed_const(16); +	/* core_bandwidth = sclk(Mhz) * 16 */ +	rdev->pm.core_bandwidth.full = rfixed_div(rdev->pm.sclk, a); +} + +void rs690_line_buffer_adjust(struct radeon_device *rdev, +			      struct drm_display_mode *mode1, +			      struct drm_display_mode *mode2) +{ +	u32 tmp; + +	/* +	 * Line Buffer Setup +	 * There is a single line buffer shared by both display controllers. +	 * DC_LB_MEMORY_SPLIT controls how that line buffer is shared between +	 * the display controllers.  The paritioning can either be done +	 * manually or via one of four preset allocations specified in bits 1:0: +	 *  0 - line buffer is divided in half and shared between crtc +	 *  1 - D1 gets 3/4 of the line buffer, D2 gets 1/4 +	 *  2 - D1 gets the whole buffer +	 *  3 - D1 gets 1/4 of the line buffer, D2 gets 3/4 +	 * Setting bit 2 of DC_LB_MEMORY_SPLIT controls switches to manual +	 * allocation mode. In manual allocation mode, D1 always starts at 0, +	 * D1 end/2 is specified in bits 14:4; D2 allocation follows D1. +	 */ +	tmp = RREG32(DC_LB_MEMORY_SPLIT) & ~DC_LB_MEMORY_SPLIT_MASK; +	tmp &= ~DC_LB_MEMORY_SPLIT_SHIFT_MODE; +	/* auto */ +	if (mode1 && mode2) { +		if (mode1->hdisplay > mode2->hdisplay) { +			if (mode1->hdisplay > 2560) +				tmp |= DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q; +			else +				tmp |= DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; +		} else if (mode2->hdisplay > mode1->hdisplay) { +			if (mode2->hdisplay > 2560) +				tmp |= DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q; +			else +				tmp |= DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; +		} else +			tmp |= AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; +	} else if (mode1) { +		tmp |= DC_LB_MEMORY_SPLIT_D1_ONLY; +	} else if (mode2) { +		tmp |= DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q; +	} +	WREG32(DC_LB_MEMORY_SPLIT, tmp); +} + +struct rs690_watermark { +	u32        lb_request_fifo_depth; +	fixed20_12 num_line_pair; +	fixed20_12 estimated_width; +	fixed20_12 worst_case_latency; +	fixed20_12 consumption_rate; +	fixed20_12 active_time; +	fixed20_12 dbpp; +	fixed20_12 priority_mark_max; +	fixed20_12 priority_mark; +	fixed20_12 sclk; +}; + +void rs690_crtc_bandwidth_compute(struct radeon_device *rdev, +				  struct radeon_crtc *crtc, +				  struct rs690_watermark *wm) +{ +	struct drm_display_mode *mode = &crtc->base.mode; +	fixed20_12 a, b, c; +	fixed20_12 pclk, request_fifo_depth, tolerable_latency, estimated_width; +	fixed20_12 consumption_time, line_time, chunk_time, read_delay_latency; +	/* FIXME: detect IGP with sideport memory, i don't think there is any +	 * such product available +	 */ +	bool sideport = false; + +	if (!crtc->base.enabled) { +		/* FIXME: wouldn't it better to set priority mark to maximum */ +		wm->lb_request_fifo_depth = 4; +		return; +	} + +	if (crtc->vsc.full > rfixed_const(2)) +		wm->num_line_pair.full = rfixed_const(2); +	else +		wm->num_line_pair.full = rfixed_const(1); + +	b.full = rfixed_const(mode->crtc_hdisplay); +	c.full = rfixed_const(256); +	a.full = rfixed_mul(wm->num_line_pair, b); +	request_fifo_depth.full = rfixed_div(a, c); +	if (a.full < rfixed_const(4)) { +		wm->lb_request_fifo_depth = 4; +	} else { +		wm->lb_request_fifo_depth = rfixed_trunc(request_fifo_depth); +	} + +	/* Determine consumption rate +	 *  pclk = pixel clock period(ns) = 1000 / (mode.clock / 1000) +	 *  vtaps = number of vertical taps, +	 *  vsc = vertical scaling ratio, defined as source/destination +	 *  hsc = horizontal scaling ration, defined as source/destination +	 */ +	a.full = rfixed_const(mode->clock); +	b.full = rfixed_const(1000); +	a.full = rfixed_div(a, b); +	pclk.full = rfixed_div(b, a); +	if (crtc->rmx_type != RMX_OFF) { +		b.full = rfixed_const(2); +		if (crtc->vsc.full > b.full) +			b.full = crtc->vsc.full; +		b.full = rfixed_mul(b, crtc->hsc); +		c.full = rfixed_const(2); +		b.full = rfixed_div(b, c); +		consumption_time.full = rfixed_div(pclk, b); +	} else { +		consumption_time.full = pclk.full; +	} +	a.full = rfixed_const(1); +	wm->consumption_rate.full = rfixed_div(a, consumption_time); + + +	/* Determine line time +	 *  LineTime = total time for one line of displayhtotal +	 *  LineTime = total number of horizontal pixels +	 *  pclk = pixel clock period(ns) +	 */ +	a.full = rfixed_const(crtc->base.mode.crtc_htotal); +	line_time.full = rfixed_mul(a, pclk); + +	/* Determine active time +	 *  ActiveTime = time of active region of display within one line, +	 *  hactive = total number of horizontal active pixels +	 *  htotal = total number of horizontal pixels +	 */ +	a.full = rfixed_const(crtc->base.mode.crtc_htotal); +	b.full = rfixed_const(crtc->base.mode.crtc_hdisplay); +	wm->active_time.full = rfixed_mul(line_time, b); +	wm->active_time.full = rfixed_div(wm->active_time, a); + +	/* Maximun bandwidth is the minimun bandwidth of all component */ +	rdev->pm.max_bandwidth = rdev->pm.core_bandwidth; +	if (sideport) { +		if (rdev->pm.max_bandwidth.full > rdev->pm.sideport_bandwidth.full && +			rdev->pm.sideport_bandwidth.full) +			rdev->pm.max_bandwidth = rdev->pm.sideport_bandwidth; +		read_delay_latency.full = rfixed_const(370 * 800 * 1000); +		read_delay_latency.full = rfixed_div(read_delay_latency, +			rdev->pm.igp_sideport_mclk); +	} else { +		if (rdev->pm.max_bandwidth.full > rdev->pm.k8_bandwidth.full && +			rdev->pm.k8_bandwidth.full) +			rdev->pm.max_bandwidth = rdev->pm.k8_bandwidth; +		if (rdev->pm.max_bandwidth.full > rdev->pm.ht_bandwidth.full && +			rdev->pm.ht_bandwidth.full) +			rdev->pm.max_bandwidth = rdev->pm.ht_bandwidth; +		read_delay_latency.full = rfixed_const(5000); +	} + +	/* sclk = system clocks(ns) = 1000 / max_bandwidth / 16 */ +	a.full = rfixed_const(16); +	rdev->pm.sclk.full = rfixed_mul(rdev->pm.max_bandwidth, a); +	a.full = rfixed_const(1000); +	rdev->pm.sclk.full = rfixed_div(a, rdev->pm.sclk); +	/* Determine chunk time +	 * ChunkTime = the time it takes the DCP to send one chunk of data +	 * to the LB which consists of pipeline delay and inter chunk gap +	 * sclk = system clock(ns) +	 */ +	a.full = rfixed_const(256 * 13); +	chunk_time.full = rfixed_mul(rdev->pm.sclk, a); +	a.full = rfixed_const(10); +	chunk_time.full = rfixed_div(chunk_time, a); + +	/* Determine the worst case latency +	 * NumLinePair = Number of line pairs to request(1=2 lines, 2=4 lines) +	 * WorstCaseLatency = worst case time from urgent to when the MC starts +	 *                    to return data +	 * READ_DELAY_IDLE_MAX = constant of 1us +	 * ChunkTime = time it takes the DCP to send one chunk of data to the LB +	 *             which consists of pipeline delay and inter chunk gap +	 */ +	if (rfixed_trunc(wm->num_line_pair) > 1) { +		a.full = rfixed_const(3); +		wm->worst_case_latency.full = rfixed_mul(a, chunk_time); +		wm->worst_case_latency.full += read_delay_latency.full; +	} else { +		a.full = rfixed_const(2); +		wm->worst_case_latency.full = rfixed_mul(a, chunk_time); +		wm->worst_case_latency.full += read_delay_latency.full; +	} + +	/* Determine the tolerable latency +	 * TolerableLatency = Any given request has only 1 line time +	 *                    for the data to be returned +	 * LBRequestFifoDepth = Number of chunk requests the LB can +	 *                      put into the request FIFO for a display +	 *  LineTime = total time for one line of display +	 *  ChunkTime = the time it takes the DCP to send one chunk +	 *              of data to the LB which consists of +	 *  pipeline delay and inter chunk gap +	 */ +	if ((2+wm->lb_request_fifo_depth) >= rfixed_trunc(request_fifo_depth)) { +		tolerable_latency.full = line_time.full; +	} else { +		tolerable_latency.full = rfixed_const(wm->lb_request_fifo_depth - 2); +		tolerable_latency.full = request_fifo_depth.full - tolerable_latency.full; +		tolerable_latency.full = rfixed_mul(tolerable_latency, chunk_time); +		tolerable_latency.full = line_time.full - tolerable_latency.full; +	} +	/* We assume worst case 32bits (4 bytes) */ +	wm->dbpp.full = rfixed_const(4 * 8); + +	/* Determine the maximum priority mark +	 *  width = viewport width in pixels +	 */ +	a.full = rfixed_const(16); +	wm->priority_mark_max.full = rfixed_const(crtc->base.mode.crtc_hdisplay); +	wm->priority_mark_max.full = rfixed_div(wm->priority_mark_max, a); + +	/* Determine estimated width */ +	estimated_width.full = tolerable_latency.full - wm->worst_case_latency.full; +	estimated_width.full = rfixed_div(estimated_width, consumption_time); +	if (rfixed_trunc(estimated_width) > crtc->base.mode.crtc_hdisplay) { +		wm->priority_mark.full = rfixed_const(10); +	} else { +		a.full = rfixed_const(16); +		wm->priority_mark.full = rfixed_div(estimated_width, a); +		wm->priority_mark.full = wm->priority_mark_max.full - wm->priority_mark.full; +	}  } +void rs690_bandwidth_update(struct radeon_device *rdev) +{ +	struct drm_display_mode *mode0 = NULL; +	struct drm_display_mode *mode1 = NULL; +	struct rs690_watermark wm0; +	struct rs690_watermark wm1; +	u32 tmp; +	fixed20_12 priority_mark02, priority_mark12, fill_rate; +	fixed20_12 a, b; + +	if (rdev->mode_info.crtcs[0]->base.enabled) +		mode0 = &rdev->mode_info.crtcs[0]->base.mode; +	if (rdev->mode_info.crtcs[1]->base.enabled) +		mode1 = &rdev->mode_info.crtcs[1]->base.mode; +	/* +	 * Set display0/1 priority up in the memory controller for +	 * modes if the user specifies HIGH for displaypriority +	 * option. +	 */ +	if (rdev->disp_priority == 2) { +		tmp = RREG32_MC(MC_INIT_MISC_LAT_TIMER); +		tmp &= ~MC_DISP1R_INIT_LAT_MASK; +		tmp &= ~MC_DISP0R_INIT_LAT_MASK; +		if (mode1) +			tmp |= (1 << MC_DISP1R_INIT_LAT_SHIFT); +		if (mode0) +			tmp |= (1 << MC_DISP0R_INIT_LAT_SHIFT); +		WREG32_MC(MC_INIT_MISC_LAT_TIMER, tmp); +	} +	rs690_line_buffer_adjust(rdev, mode0, mode1); + +	if ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740)) +		WREG32(DCP_CONTROL, 0); +	if ((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880)) +		WREG32(DCP_CONTROL, 2); + +	rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0); +	rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1); + +	tmp = (wm0.lb_request_fifo_depth - 1); +	tmp |= (wm1.lb_request_fifo_depth - 1) << 16; +	WREG32(LB_MAX_REQ_OUTSTANDING, tmp); + +	if (mode0 && mode1) { +		if (rfixed_trunc(wm0.dbpp) > 64) +			a.full = rfixed_mul(wm0.dbpp, wm0.num_line_pair); +		else +			a.full = wm0.num_line_pair.full; +		if (rfixed_trunc(wm1.dbpp) > 64) +			b.full = rfixed_mul(wm1.dbpp, wm1.num_line_pair); +		else +			b.full = wm1.num_line_pair.full; +		a.full += b.full; +		fill_rate.full = rfixed_div(wm0.sclk, a); +		if (wm0.consumption_rate.full > fill_rate.full) { +			b.full = wm0.consumption_rate.full - fill_rate.full; +			b.full = rfixed_mul(b, wm0.active_time); +			a.full = rfixed_mul(wm0.worst_case_latency, +						wm0.consumption_rate); +			a.full = a.full + b.full; +			b.full = rfixed_const(16 * 1000); +			priority_mark02.full = rfixed_div(a, b); +		} else { +			a.full = rfixed_mul(wm0.worst_case_latency, +						wm0.consumption_rate); +			b.full = rfixed_const(16 * 1000); +			priority_mark02.full = rfixed_div(a, b); +		} +		if (wm1.consumption_rate.full > fill_rate.full) { +			b.full = wm1.consumption_rate.full - fill_rate.full; +			b.full = rfixed_mul(b, wm1.active_time); +			a.full = rfixed_mul(wm1.worst_case_latency, +						wm1.consumption_rate); +			a.full = a.full + b.full; +			b.full = rfixed_const(16 * 1000); +			priority_mark12.full = rfixed_div(a, b); +		} else { +			a.full = rfixed_mul(wm1.worst_case_latency, +						wm1.consumption_rate); +			b.full = rfixed_const(16 * 1000); +			priority_mark12.full = rfixed_div(a, b); +		} +		if (wm0.priority_mark.full > priority_mark02.full) +			priority_mark02.full = wm0.priority_mark.full; +		if (rfixed_trunc(priority_mark02) < 0) +			priority_mark02.full = 0; +		if (wm0.priority_mark_max.full > priority_mark02.full) +			priority_mark02.full = wm0.priority_mark_max.full; +		if (wm1.priority_mark.full > priority_mark12.full) +			priority_mark12.full = wm1.priority_mark.full; +		if (rfixed_trunc(priority_mark12) < 0) +			priority_mark12.full = 0; +		if (wm1.priority_mark_max.full > priority_mark12.full) +			priority_mark12.full = wm1.priority_mark_max.full; +		WREG32(D1MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark02)); +		WREG32(D1MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark02)); +		WREG32(D2MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark12)); +		WREG32(D2MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark12)); +	} else if (mode0) { +		if (rfixed_trunc(wm0.dbpp) > 64) +			a.full = rfixed_mul(wm0.dbpp, wm0.num_line_pair); +		else +			a.full = wm0.num_line_pair.full; +		fill_rate.full = rfixed_div(wm0.sclk, a); +		if (wm0.consumption_rate.full > fill_rate.full) { +			b.full = wm0.consumption_rate.full - fill_rate.full; +			b.full = rfixed_mul(b, wm0.active_time); +			a.full = rfixed_mul(wm0.worst_case_latency, +						wm0.consumption_rate); +			a.full = a.full + b.full; +			b.full = rfixed_const(16 * 1000); +			priority_mark02.full = rfixed_div(a, b); +		} else { +			a.full = rfixed_mul(wm0.worst_case_latency, +						wm0.consumption_rate); +			b.full = rfixed_const(16 * 1000); +			priority_mark02.full = rfixed_div(a, b); +		} +		if (wm0.priority_mark.full > priority_mark02.full) +			priority_mark02.full = wm0.priority_mark.full; +		if (rfixed_trunc(priority_mark02) < 0) +			priority_mark02.full = 0; +		if (wm0.priority_mark_max.full > priority_mark02.full) +			priority_mark02.full = wm0.priority_mark_max.full; +		WREG32(D1MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark02)); +		WREG32(D1MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark02)); +		WREG32(D2MODE_PRIORITY_A_CNT, MODE_PRIORITY_OFF); +		WREG32(D2MODE_PRIORITY_B_CNT, MODE_PRIORITY_OFF); +	} else { +		if (rfixed_trunc(wm1.dbpp) > 64) +			a.full = rfixed_mul(wm1.dbpp, wm1.num_line_pair); +		else +			a.full = wm1.num_line_pair.full; +		fill_rate.full = rfixed_div(wm1.sclk, a); +		if (wm1.consumption_rate.full > fill_rate.full) { +			b.full = wm1.consumption_rate.full - fill_rate.full; +			b.full = rfixed_mul(b, wm1.active_time); +			a.full = rfixed_mul(wm1.worst_case_latency, +						wm1.consumption_rate); +			a.full = a.full + b.full; +			b.full = rfixed_const(16 * 1000); +			priority_mark12.full = rfixed_div(a, b); +		} else { +			a.full = rfixed_mul(wm1.worst_case_latency, +						wm1.consumption_rate); +			b.full = rfixed_const(16 * 1000); +			priority_mark12.full = rfixed_div(a, b); +		} +		if (wm1.priority_mark.full > priority_mark12.full) +			priority_mark12.full = wm1.priority_mark.full; +		if (rfixed_trunc(priority_mark12) < 0) +			priority_mark12.full = 0; +		if (wm1.priority_mark_max.full > priority_mark12.full) +			priority_mark12.full = wm1.priority_mark_max.full; +		WREG32(D1MODE_PRIORITY_A_CNT, MODE_PRIORITY_OFF); +		WREG32(D1MODE_PRIORITY_B_CNT, MODE_PRIORITY_OFF); +		WREG32(D2MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark12)); +		WREG32(D2MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark12)); +	} +}  /*   * Indirect registers accessor @@ -179,3 +652,68 @@ void rs690_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)  	WREG32(RS690_MC_DATA, v);  	WREG32(RS690_MC_INDEX, RS690_MC_INDEX_WR_ACK);  } + +static const unsigned rs690_reg_safe_bm[219] = { +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0x17FF1FFF,0xFFFFFFFC,0xFFFFFFFF,0xFF30FFBF, +	0xFFFFFFF8,0xC3E6FFFF,0xFFFFF6DF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFF03F, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFEFCE,0xF00EBFFF,0x007C0000, +	0xF0000078,0xFF000009,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFF7FF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFC78,0xFFFFFFFF,0xFFFFFFFE,0xFFFFFFFF, +	0x38FF8F50,0xFFF88082,0xF000000C,0xFAE009FF, +	0x0000FFFF,0xFFFFFFFF,0xFFFFFFFF,0x00000000, +	0x00000000,0x0000C100,0x00000000,0x00000000, +	0x00000000,0x00000000,0x00000000,0x00000000, +	0x00000000,0xFFFF0000,0xFFFFFFFF,0xFF80FFFF, +	0x00000000,0x00000000,0x00000000,0x00000000, +	0x0003FC01,0xFFFFFFF8,0xFE800B19,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +	0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +}; + +int rs690_init(struct radeon_device *rdev) +{ +	rdev->config.r300.reg_safe_bm = rs690_reg_safe_bm; +	rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(rs690_reg_safe_bm); +	return 0; +} diff --git a/drivers/gpu/drm/radeon/rs690r.h b/drivers/gpu/drm/radeon/rs690r.h new file mode 100644 index 00000000000..c0d9faa2175 --- /dev/null +++ b/drivers/gpu/drm/radeon/rs690r.h @@ -0,0 +1,99 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + *          Alex Deucher + *          Jerome Glisse + */ +#ifndef RS690R_H +#define RS690R_H + +/* RS690/RS740 registers */ +#define MC_INDEX			0x0078 +#	define MC_INDEX_MASK			0x1FF +#	define MC_INDEX_WR_EN			(1 << 9) +#	define MC_INDEX_WR_ACK			0x7F +#define MC_DATA				0x007C +#define HDP_FB_LOCATION			0x0134 +#define DC_LB_MEMORY_SPLIT		0x6520 +#define		DC_LB_MEMORY_SPLIT_MASK			0x00000003 +#define		DC_LB_MEMORY_SPLIT_SHIFT		0 +#define		DC_LB_MEMORY_SPLIT_D1HALF_D2HALF	0 +#define		DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q		1 +#define		DC_LB_MEMORY_SPLIT_D1_ONLY		2 +#define		DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q		3 +#define		DC_LB_MEMORY_SPLIT_SHIFT_MODE		(1 << 2) +#define		DC_LB_DISP1_END_ADR_SHIFT		4 +#define		DC_LB_DISP1_END_ADR_MASK		0x00007FF0 +#define D1MODE_PRIORITY_A_CNT		0x6548 +#define		MODE_PRIORITY_MARK_MASK			0x00007FFF +#define		MODE_PRIORITY_OFF			(1 << 16) +#define		MODE_PRIORITY_ALWAYS_ON			(1 << 20) +#define		MODE_PRIORITY_FORCE_MASK		(1 << 24) +#define D1MODE_PRIORITY_B_CNT		0x654C +#define LB_MAX_REQ_OUTSTANDING		0x6D58 +#define		LB_D1_MAX_REQ_OUTSTANDING_MASK		0x0000000F +#define		LB_D1_MAX_REQ_OUTSTANDING_SHIFT		0 +#define		LB_D2_MAX_REQ_OUTSTANDING_MASK		0x000F0000 +#define		LB_D2_MAX_REQ_OUTSTANDING_SHIFT		16 +#define DCP_CONTROL			0x6C9C +#define D2MODE_PRIORITY_A_CNT		0x6D48 +#define D2MODE_PRIORITY_B_CNT		0x6D4C + +/* MC indirect registers */ +#define MC_STATUS_IDLE				(1 << 0) +#define MC_MISC_CNTL			0x18 +#define		DISABLE_GTW			(1 << 1) +#define		GART_INDEX_REG_EN		(1 << 12) +#define		BLOCK_GFX_D3_EN			(1 << 14) +#define GART_FEATURE_ID			0x2B +#define		HANG_EN				(1 << 11) +#define		TLB_ENABLE			(1 << 18) +#define		P2P_ENABLE			(1 << 19) +#define		GTW_LAC_EN			(1 << 25) +#define		LEVEL2_GART			(0 << 30) +#define		LEVEL1_GART			(1 << 30) +#define		PDC_EN				(1 << 31) +#define GART_BASE			0x2C +#define GART_CACHE_CNTRL		0x2E +#	define GART_CACHE_INVALIDATE		(1 << 0) +#define MC_STATUS			0x90 +#define MCCFG_FB_LOCATION		0x100 +#define		MC_FB_START_MASK		0x0000FFFF +#define		MC_FB_START_SHIFT		0 +#define		MC_FB_TOP_MASK			0xFFFF0000 +#define		MC_FB_TOP_SHIFT			16 +#define MCCFG_AGP_LOCATION		0x101 +#define		MC_AGP_START_MASK		0x0000FFFF +#define		MC_AGP_START_SHIFT		0 +#define		MC_AGP_TOP_MASK			0xFFFF0000 +#define		MC_AGP_TOP_SHIFT		16 +#define MCCFG_AGP_BASE			0x102 +#define MCCFG_AGP_BASE_2		0x103 +#define MC_INIT_MISC_LAT_TIMER		0x104 +#define		MC_DISP0R_INIT_LAT_SHIFT	8 +#define		MC_DISP0R_INIT_LAT_MASK		0x00000F00 +#define		MC_DISP1R_INIT_LAT_SHIFT	12 +#define		MC_DISP1R_INIT_LAT_MASK		0x0000F000 + +#endif diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index ffea37b1b3e..31a7f668ae5 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -27,8 +27,9 @@   */  #include <linux/seq_file.h>  #include "drmP.h" -#include "radeon_reg.h" +#include "rv515r.h"  #include "radeon.h" +#include "radeon_share.h"  /* rv515 depends on : */  void r100_hdp_reset(struct radeon_device *rdev); @@ -99,26 +100,26 @@ int rv515_mc_init(struct radeon_device *rdev)  		       "programming pipes. Bad things might happen.\n");  	}  	/* Write VRAM size in case we are limiting it */ -	WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size); -	tmp = REG_SET(RV515_MC_FB_START, rdev->mc.vram_location >> 16); +	WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.real_vram_size); +	tmp = REG_SET(MC_FB_START, rdev->mc.vram_location >> 16);  	WREG32(0x134, tmp); -	tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1; -	tmp = REG_SET(RV515_MC_FB_TOP, tmp >> 16); -	tmp |= REG_SET(RV515_MC_FB_START, rdev->mc.vram_location >> 16); -	WREG32_MC(RV515_MC_FB_LOCATION, tmp); -	WREG32(RS690_HDP_FB_LOCATION, rdev->mc.vram_location >> 16); +	tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1; +	tmp = REG_SET(MC_FB_TOP, tmp >> 16); +	tmp |= REG_SET(MC_FB_START, rdev->mc.vram_location >> 16); +	WREG32_MC(MC_FB_LOCATION, tmp); +	WREG32(HDP_FB_LOCATION, rdev->mc.vram_location >> 16);  	WREG32(0x310, rdev->mc.vram_location);  	if (rdev->flags & RADEON_IS_AGP) {  		tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1; -		tmp = REG_SET(RV515_MC_AGP_TOP, tmp >> 16); -		tmp |= REG_SET(RV515_MC_AGP_START, rdev->mc.gtt_location >> 16); -		WREG32_MC(RV515_MC_AGP_LOCATION, tmp); -		WREG32_MC(RV515_MC_AGP_BASE, rdev->mc.agp_base); -		WREG32_MC(RV515_MC_AGP_BASE_2, 0); +		tmp = REG_SET(MC_AGP_TOP, tmp >> 16); +		tmp |= REG_SET(MC_AGP_START, rdev->mc.gtt_location >> 16); +		WREG32_MC(MC_AGP_LOCATION, tmp); +		WREG32_MC(MC_AGP_BASE, rdev->mc.agp_base); +		WREG32_MC(MC_AGP_BASE_2, 0);  	} else { -		WREG32_MC(RV515_MC_AGP_LOCATION, 0x0FFFFFFF); -		WREG32_MC(RV515_MC_AGP_BASE, 0); -		WREG32_MC(RV515_MC_AGP_BASE_2, 0); +		WREG32_MC(MC_AGP_LOCATION, 0x0FFFFFFF); +		WREG32_MC(MC_AGP_BASE, 0); +		WREG32_MC(MC_AGP_BASE_2, 0);  	}  	return 0;  } @@ -136,95 +137,67 @@ void rv515_mc_fini(struct radeon_device *rdev)   */  void rv515_ring_start(struct radeon_device *rdev)  { -	unsigned gb_tile_config;  	int r; -	/* Sub pixel 1/12 so we can have 4K rendering according to doc */ -	gb_tile_config = R300_ENABLE_TILING | R300_TILE_SIZE_16; -	switch (rdev->num_gb_pipes) { -	case 2: -		gb_tile_config |= R300_PIPE_COUNT_R300; -		break; -	case 3: -		gb_tile_config |= R300_PIPE_COUNT_R420_3P; -		break; -	case 4: -		gb_tile_config |= R300_PIPE_COUNT_R420; -		break; -	case 1: -	default: -		gb_tile_config |= R300_PIPE_COUNT_RV350; -		break; -	} -  	r = radeon_ring_lock(rdev, 64);  	if (r) {  		return;  	} -	radeon_ring_write(rdev, PACKET0(RADEON_ISYNC_CNTL, 0)); -	radeon_ring_write(rdev, -			  RADEON_ISYNC_ANY2D_IDLE3D | -			  RADEON_ISYNC_ANY3D_IDLE2D | -			  RADEON_ISYNC_WAIT_IDLEGUI | -			  RADEON_ISYNC_CPSCRATCH_IDLEGUI); -	radeon_ring_write(rdev, PACKET0(R300_GB_TILE_CONFIG, 0)); -	radeon_ring_write(rdev, gb_tile_config); -	radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0)); +	radeon_ring_write(rdev, PACKET0(ISYNC_CNTL, 0));  	radeon_ring_write(rdev, -			  RADEON_WAIT_2D_IDLECLEAN | -			  RADEON_WAIT_3D_IDLECLEAN); +			  ISYNC_ANY2D_IDLE3D | +			  ISYNC_ANY3D_IDLE2D | +			  ISYNC_WAIT_IDLEGUI | +			  ISYNC_CPSCRATCH_IDLEGUI); +	radeon_ring_write(rdev, PACKET0(WAIT_UNTIL, 0)); +	radeon_ring_write(rdev, WAIT_2D_IDLECLEAN | WAIT_3D_IDLECLEAN);  	radeon_ring_write(rdev, PACKET0(0x170C, 0));  	radeon_ring_write(rdev, 1 << 31); -	radeon_ring_write(rdev, PACKET0(R300_GB_SELECT, 0)); +	radeon_ring_write(rdev, PACKET0(GB_SELECT, 0));  	radeon_ring_write(rdev, 0); -	radeon_ring_write(rdev, PACKET0(R300_GB_ENABLE, 0)); +	radeon_ring_write(rdev, PACKET0(GB_ENABLE, 0));  	radeon_ring_write(rdev, 0);  	radeon_ring_write(rdev, PACKET0(0x42C8, 0));  	radeon_ring_write(rdev, (1 << rdev->num_gb_pipes) - 1); -	radeon_ring_write(rdev, PACKET0(R500_VAP_INDEX_OFFSET, 0)); +	radeon_ring_write(rdev, PACKET0(VAP_INDEX_OFFSET, 0));  	radeon_ring_write(rdev, 0); -	radeon_ring_write(rdev, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); -	radeon_ring_write(rdev, R300_RB3D_DC_FLUSH | R300_RB3D_DC_FREE); -	radeon_ring_write(rdev, PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0)); -	radeon_ring_write(rdev, R300_ZC_FLUSH | R300_ZC_FREE); -	radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0)); -	radeon_ring_write(rdev, -			  RADEON_WAIT_2D_IDLECLEAN | -			  RADEON_WAIT_3D_IDLECLEAN); -	radeon_ring_write(rdev, PACKET0(R300_GB_AA_CONFIG, 0)); +	radeon_ring_write(rdev, PACKET0(RB3D_DSTCACHE_CTLSTAT, 0)); +	radeon_ring_write(rdev, RB3D_DC_FLUSH | RB3D_DC_FREE); +	radeon_ring_write(rdev, PACKET0(ZB_ZCACHE_CTLSTAT, 0)); +	radeon_ring_write(rdev, ZC_FLUSH | ZC_FREE); +	radeon_ring_write(rdev, PACKET0(WAIT_UNTIL, 0)); +	radeon_ring_write(rdev, WAIT_2D_IDLECLEAN | WAIT_3D_IDLECLEAN); +	radeon_ring_write(rdev, PACKET0(GB_AA_CONFIG, 0));  	radeon_ring_write(rdev, 0); -	radeon_ring_write(rdev, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); -	radeon_ring_write(rdev, R300_RB3D_DC_FLUSH | R300_RB3D_DC_FREE); -	radeon_ring_write(rdev, PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0)); -	radeon_ring_write(rdev, R300_ZC_FLUSH | R300_ZC_FREE); -	radeon_ring_write(rdev, PACKET0(R300_GB_MSPOS0, 0)); -	radeon_ring_write(rdev, -			  ((6 << R300_MS_X0_SHIFT) | -			   (6 << R300_MS_Y0_SHIFT) | -			   (6 << R300_MS_X1_SHIFT) | -			   (6 << R300_MS_Y1_SHIFT) | -			   (6 << R300_MS_X2_SHIFT) | -			   (6 << R300_MS_Y2_SHIFT) | -			   (6 << R300_MSBD0_Y_SHIFT) | -			   (6 << R300_MSBD0_X_SHIFT))); -	radeon_ring_write(rdev, PACKET0(R300_GB_MSPOS1, 0)); -	radeon_ring_write(rdev, -			  ((6 << R300_MS_X3_SHIFT) | -			   (6 << R300_MS_Y3_SHIFT) | -			   (6 << R300_MS_X4_SHIFT) | -			   (6 << R300_MS_Y4_SHIFT) | -			   (6 << R300_MS_X5_SHIFT) | -			   (6 << R300_MS_Y5_SHIFT) | -			   (6 << R300_MSBD1_SHIFT))); -	radeon_ring_write(rdev, PACKET0(R300_GA_ENHANCE, 0)); -	radeon_ring_write(rdev, R300_GA_DEADLOCK_CNTL | R300_GA_FASTSYNC_CNTL); -	radeon_ring_write(rdev, PACKET0(R300_GA_POLY_MODE, 0)); +	radeon_ring_write(rdev, PACKET0(RB3D_DSTCACHE_CTLSTAT, 0)); +	radeon_ring_write(rdev, RB3D_DC_FLUSH | RB3D_DC_FREE); +	radeon_ring_write(rdev, PACKET0(ZB_ZCACHE_CTLSTAT, 0)); +	radeon_ring_write(rdev, ZC_FLUSH | ZC_FREE); +	radeon_ring_write(rdev, PACKET0(GB_MSPOS0, 0));  	radeon_ring_write(rdev, -			  R300_FRONT_PTYPE_TRIANGE | R300_BACK_PTYPE_TRIANGE); -	radeon_ring_write(rdev, PACKET0(R300_GA_ROUND_MODE, 0)); +			  ((6 << MS_X0_SHIFT) | +			   (6 << MS_Y0_SHIFT) | +			   (6 << MS_X1_SHIFT) | +			   (6 << MS_Y1_SHIFT) | +			   (6 << MS_X2_SHIFT) | +			   (6 << MS_Y2_SHIFT) | +			   (6 << MSBD0_Y_SHIFT) | +			   (6 << MSBD0_X_SHIFT))); +	radeon_ring_write(rdev, PACKET0(GB_MSPOS1, 0));  	radeon_ring_write(rdev, -			  R300_GEOMETRY_ROUND_NEAREST | -			  R300_COLOR_ROUND_NEAREST); +			  ((6 << MS_X3_SHIFT) | +			   (6 << MS_Y3_SHIFT) | +			   (6 << MS_X4_SHIFT) | +			   (6 << MS_Y4_SHIFT) | +			   (6 << MS_X5_SHIFT) | +			   (6 << MS_Y5_SHIFT) | +			   (6 << MSBD1_SHIFT))); +	radeon_ring_write(rdev, PACKET0(GA_ENHANCE, 0)); +	radeon_ring_write(rdev, GA_DEADLOCK_CNTL | GA_FASTSYNC_CNTL); +	radeon_ring_write(rdev, PACKET0(GA_POLY_MODE, 0)); +	radeon_ring_write(rdev, FRONT_PTYPE_TRIANGE | BACK_PTYPE_TRIANGE); +	radeon_ring_write(rdev, PACKET0(GA_ROUND_MODE, 0)); +	radeon_ring_write(rdev, GEOMETRY_ROUND_NEAREST | COLOR_ROUND_NEAREST);  	radeon_ring_write(rdev, PACKET0(0x20C8, 0));  	radeon_ring_write(rdev, 0);  	radeon_ring_unlock_commit(rdev); @@ -242,8 +215,8 @@ int rv515_mc_wait_for_idle(struct radeon_device *rdev)  	for (i = 0; i < rdev->usec_timeout; i++) {  		/* read MC_STATUS */ -		tmp = RREG32_MC(RV515_MC_STATUS); -		if (tmp & RV515_MC_STATUS_IDLE) { +		tmp = RREG32_MC(MC_STATUS); +		if (tmp & MC_STATUS_IDLE) {  			return 0;  		}  		DRM_UDELAY(1); @@ -291,33 +264,33 @@ int rv515_ga_reset(struct radeon_device *rdev)  	reinit_cp = rdev->cp.ready;  	rdev->cp.ready = false;  	for (i = 0; i < rdev->usec_timeout; i++) { -		WREG32(RADEON_CP_CSQ_MODE, 0); -		WREG32(RADEON_CP_CSQ_CNTL, 0); -		WREG32(RADEON_RBBM_SOFT_RESET, 0x32005); -		(void)RREG32(RADEON_RBBM_SOFT_RESET); +		WREG32(CP_CSQ_MODE, 0); +		WREG32(CP_CSQ_CNTL, 0); +		WREG32(RBBM_SOFT_RESET, 0x32005); +		(void)RREG32(RBBM_SOFT_RESET);  		udelay(200); -		WREG32(RADEON_RBBM_SOFT_RESET, 0); +		WREG32(RBBM_SOFT_RESET, 0);  		/* Wait to prevent race in RBBM_STATUS */  		mdelay(1); -		tmp = RREG32(RADEON_RBBM_STATUS); +		tmp = RREG32(RBBM_STATUS);  		if (tmp & ((1 << 20) | (1 << 26))) {  			DRM_ERROR("VAP & CP still busy (RBBM_STATUS=0x%08X)\n", tmp);  			/* GA still busy soft reset it */  			WREG32(0x429C, 0x200); -			WREG32(R300_VAP_PVS_STATE_FLUSH_REG, 0); +			WREG32(VAP_PVS_STATE_FLUSH_REG, 0);  			WREG32(0x43E0, 0);  			WREG32(0x43E4, 0);  			WREG32(0x24AC, 0);  		}  		/* Wait to prevent race in RBBM_STATUS */  		mdelay(1); -		tmp = RREG32(RADEON_RBBM_STATUS); +		tmp = RREG32(RBBM_STATUS);  		if (!(tmp & ((1 << 20) | (1 << 26)))) {  			break;  		}  	}  	for (i = 0; i < rdev->usec_timeout; i++) { -		tmp = RREG32(RADEON_RBBM_STATUS); +		tmp = RREG32(RBBM_STATUS);  		if (!(tmp & ((1 << 20) | (1 << 26)))) {  			DRM_INFO("GA reset succeed (RBBM_STATUS=0x%08X)\n",  				 tmp); @@ -331,7 +304,7 @@ int rv515_ga_reset(struct radeon_device *rdev)  		}  		DRM_UDELAY(1);  	} -	tmp = RREG32(RADEON_RBBM_STATUS); +	tmp = RREG32(RBBM_STATUS);  	DRM_ERROR("Failed to reset GA ! (RBBM_STATUS=0x%08X)\n", tmp);  	return -1;  } @@ -341,7 +314,7 @@ int rv515_gpu_reset(struct radeon_device *rdev)  	uint32_t status;  	/* reset order likely matter */ -	status = RREG32(RADEON_RBBM_STATUS); +	status = RREG32(RBBM_STATUS);  	/* reset HDP */  	r100_hdp_reset(rdev);  	/* reset rb2d */ @@ -353,12 +326,12 @@ int rv515_gpu_reset(struct radeon_device *rdev)  		rv515_ga_reset(rdev);  	}  	/* reset CP */ -	status = RREG32(RADEON_RBBM_STATUS); +	status = RREG32(RBBM_STATUS);  	if (status & (1 << 16)) {  		r100_cp_reset(rdev);  	}  	/* Check if GPU is idle */ -	status = RREG32(RADEON_RBBM_STATUS); +	status = RREG32(RBBM_STATUS);  	if (status & (1 << 31)) {  		DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status);  		return -1; @@ -377,8 +350,7 @@ static void rv515_vram_get_type(struct radeon_device *rdev)  	rdev->mc.vram_width = 128;  	rdev->mc.vram_is_ddr = true; -	tmp = RREG32_MC(RV515_MC_CNTL); -	tmp &= RV515_MEM_NUM_CHANNELS_MASK; +	tmp = RREG32_MC(RV515_MC_CNTL) & MEM_NUM_CHANNELS_MASK;  	switch (tmp) {  	case 0:  		rdev->mc.vram_width = 64; @@ -394,11 +366,17 @@ static void rv515_vram_get_type(struct radeon_device *rdev)  void rv515_vram_info(struct radeon_device *rdev)  { +	fixed20_12 a; +  	rv515_vram_get_type(rdev); -	rdev->mc.vram_size = RREG32(RADEON_CONFIG_MEMSIZE); -	rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); -	rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); +	r100_vram_init_sizes(rdev); +	/* FIXME: we should enforce default clock in case GPU is not in +	 * default setup +	 */ +	a.full = rfixed_const(100); +	rdev->pm.sclk.full = rfixed_const(rdev->clock.default_sclk); +	rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a);  } @@ -409,38 +387,19 @@ uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg)  {  	uint32_t r; -	WREG32(R520_MC_IND_INDEX, 0x7f0000 | (reg & 0xffff)); -	r = RREG32(R520_MC_IND_DATA); -	WREG32(R520_MC_IND_INDEX, 0); +	WREG32(MC_IND_INDEX, 0x7f0000 | (reg & 0xffff)); +	r = RREG32(MC_IND_DATA); +	WREG32(MC_IND_INDEX, 0);  	return r;  }  void rv515_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)  { -	WREG32(R520_MC_IND_INDEX, 0xff0000 | ((reg) & 0xffff)); -	WREG32(R520_MC_IND_DATA, (v)); -	WREG32(R520_MC_IND_INDEX, 0); -} - -uint32_t rv515_pcie_rreg(struct radeon_device *rdev, uint32_t reg) -{ -	uint32_t r; - -	WREG32(RADEON_PCIE_INDEX, ((reg) & 0x7ff)); -	(void)RREG32(RADEON_PCIE_INDEX); -	r = RREG32(RADEON_PCIE_DATA); -	return r; -} - -void rv515_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) -{ -	WREG32(RADEON_PCIE_INDEX, ((reg) & 0x7ff)); -	(void)RREG32(RADEON_PCIE_INDEX); -	WREG32(RADEON_PCIE_DATA, (v)); -	(void)RREG32(RADEON_PCIE_DATA); +	WREG32(MC_IND_INDEX, 0xff0000 | ((reg) & 0xffff)); +	WREG32(MC_IND_DATA, (v)); +	WREG32(MC_IND_INDEX, 0);  } -  /*   * Debugfs info   */ @@ -452,13 +411,13 @@ static int rv515_debugfs_pipes_info(struct seq_file *m, void *data)  	struct radeon_device *rdev = dev->dev_private;  	uint32_t tmp; -	tmp = RREG32(R400_GB_PIPE_SELECT); +	tmp = RREG32(GB_PIPE_SELECT);  	seq_printf(m, "GB_PIPE_SELECT 0x%08x\n", tmp); -	tmp = RREG32(R500_SU_REG_DEST); +	tmp = RREG32(SU_REG_DEST);  	seq_printf(m, "SU_REG_DEST 0x%08x\n", tmp); -	tmp = RREG32(R300_GB_TILE_CONFIG); +	tmp = RREG32(GB_TILE_CONFIG);  	seq_printf(m, "GB_TILE_CONFIG 0x%08x\n", tmp); -	tmp = RREG32(R300_DST_PIPE_CONFIG); +	tmp = RREG32(DST_PIPE_CONFIG);  	seq_printf(m, "DST_PIPE_CONFIG 0x%08x\n", tmp);  	return 0;  } @@ -509,9 +468,9 @@ int rv515_debugfs_ga_info_init(struct radeon_device *rdev)  /*   * Asic initialization   */ -static const unsigned r500_reg_safe_bm[159] = { +static const unsigned r500_reg_safe_bm[219] = { +	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,  	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, -	0xFFFFFFBF, 0xFFFFFFFF, 0xFFFFFFBF, 0xFFFFFFFF,  	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,  	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,  	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, @@ -549,14 +508,575 @@ static const unsigned r500_reg_safe_bm[159] = {  	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,  	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF80FFFF,  	0x00000000, 0x00000000, 0x00000000, 0x00000000, -	0x0003FC01, 0x3FFFFCF8, 0xFE800B19, +	0x0003FC01, 0x3FFFFCF8, 0xFE800B19, 0xFFFFFFFF, +	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,  }; - -  int rv515_init(struct radeon_device *rdev)  {  	rdev->config.r300.reg_safe_bm = r500_reg_safe_bm;  	rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(r500_reg_safe_bm);  	return 0;  } + +void atom_rv515_force_tv_scaler(struct radeon_device *rdev) +{ + +	WREG32(0x659C, 0x0); +	WREG32(0x6594, 0x705); +	WREG32(0x65A4, 0x10001); +	WREG32(0x65D8, 0x0); +	WREG32(0x65B0, 0x0); +	WREG32(0x65C0, 0x0); +	WREG32(0x65D4, 0x0); +	WREG32(0x6578, 0x0); +	WREG32(0x657C, 0x841880A8); +	WREG32(0x6578, 0x1); +	WREG32(0x657C, 0x84208680); +	WREG32(0x6578, 0x2); +	WREG32(0x657C, 0xBFF880B0); +	WREG32(0x6578, 0x100); +	WREG32(0x657C, 0x83D88088); +	WREG32(0x6578, 0x101); +	WREG32(0x657C, 0x84608680); +	WREG32(0x6578, 0x102); +	WREG32(0x657C, 0xBFF080D0); +	WREG32(0x6578, 0x200); +	WREG32(0x657C, 0x83988068); +	WREG32(0x6578, 0x201); +	WREG32(0x657C, 0x84A08680); +	WREG32(0x6578, 0x202); +	WREG32(0x657C, 0xBFF080F8); +	WREG32(0x6578, 0x300); +	WREG32(0x657C, 0x83588058); +	WREG32(0x6578, 0x301); +	WREG32(0x657C, 0x84E08660); +	WREG32(0x6578, 0x302); +	WREG32(0x657C, 0xBFF88120); +	WREG32(0x6578, 0x400); +	WREG32(0x657C, 0x83188040); +	WREG32(0x6578, 0x401); +	WREG32(0x657C, 0x85008660); +	WREG32(0x6578, 0x402); +	WREG32(0x657C, 0xBFF88150); +	WREG32(0x6578, 0x500); +	WREG32(0x657C, 0x82D88030); +	WREG32(0x6578, 0x501); +	WREG32(0x657C, 0x85408640); +	WREG32(0x6578, 0x502); +	WREG32(0x657C, 0xBFF88180); +	WREG32(0x6578, 0x600); +	WREG32(0x657C, 0x82A08018); +	WREG32(0x6578, 0x601); +	WREG32(0x657C, 0x85808620); +	WREG32(0x6578, 0x602); +	WREG32(0x657C, 0xBFF081B8); +	WREG32(0x6578, 0x700); +	WREG32(0x657C, 0x82608010); +	WREG32(0x6578, 0x701); +	WREG32(0x657C, 0x85A08600); +	WREG32(0x6578, 0x702); +	WREG32(0x657C, 0x800081F0); +	WREG32(0x6578, 0x800); +	WREG32(0x657C, 0x8228BFF8); +	WREG32(0x6578, 0x801); +	WREG32(0x657C, 0x85E085E0); +	WREG32(0x6578, 0x802); +	WREG32(0x657C, 0xBFF88228); +	WREG32(0x6578, 0x10000); +	WREG32(0x657C, 0x82A8BF00); +	WREG32(0x6578, 0x10001); +	WREG32(0x657C, 0x82A08CC0); +	WREG32(0x6578, 0x10002); +	WREG32(0x657C, 0x8008BEF8); +	WREG32(0x6578, 0x10100); +	WREG32(0x657C, 0x81F0BF28); +	WREG32(0x6578, 0x10101); +	WREG32(0x657C, 0x83608CA0); +	WREG32(0x6578, 0x10102); +	WREG32(0x657C, 0x8018BED0); +	WREG32(0x6578, 0x10200); +	WREG32(0x657C, 0x8148BF38); +	WREG32(0x6578, 0x10201); +	WREG32(0x657C, 0x84408C80); +	WREG32(0x6578, 0x10202); +	WREG32(0x657C, 0x8008BEB8); +	WREG32(0x6578, 0x10300); +	WREG32(0x657C, 0x80B0BF78); +	WREG32(0x6578, 0x10301); +	WREG32(0x657C, 0x85008C20); +	WREG32(0x6578, 0x10302); +	WREG32(0x657C, 0x8020BEA0); +	WREG32(0x6578, 0x10400); +	WREG32(0x657C, 0x8028BF90); +	WREG32(0x6578, 0x10401); +	WREG32(0x657C, 0x85E08BC0); +	WREG32(0x6578, 0x10402); +	WREG32(0x657C, 0x8018BE90); +	WREG32(0x6578, 0x10500); +	WREG32(0x657C, 0xBFB8BFB0); +	WREG32(0x6578, 0x10501); +	WREG32(0x657C, 0x86C08B40); +	WREG32(0x6578, 0x10502); +	WREG32(0x657C, 0x8010BE90); +	WREG32(0x6578, 0x10600); +	WREG32(0x657C, 0xBF58BFC8); +	WREG32(0x6578, 0x10601); +	WREG32(0x657C, 0x87A08AA0); +	WREG32(0x6578, 0x10602); +	WREG32(0x657C, 0x8010BE98); +	WREG32(0x6578, 0x10700); +	WREG32(0x657C, 0xBF10BFF0); +	WREG32(0x6578, 0x10701); +	WREG32(0x657C, 0x886089E0); +	WREG32(0x6578, 0x10702); +	WREG32(0x657C, 0x8018BEB0); +	WREG32(0x6578, 0x10800); +	WREG32(0x657C, 0xBED8BFE8); +	WREG32(0x6578, 0x10801); +	WREG32(0x657C, 0x89408940); +	WREG32(0x6578, 0x10802); +	WREG32(0x657C, 0xBFE8BED8); +	WREG32(0x6578, 0x20000); +	WREG32(0x657C, 0x80008000); +	WREG32(0x6578, 0x20001); +	WREG32(0x657C, 0x90008000); +	WREG32(0x6578, 0x20002); +	WREG32(0x657C, 0x80008000); +	WREG32(0x6578, 0x20003); +	WREG32(0x657C, 0x80008000); +	WREG32(0x6578, 0x20100); +	WREG32(0x657C, 0x80108000); +	WREG32(0x6578, 0x20101); +	WREG32(0x657C, 0x8FE0BF70); +	WREG32(0x6578, 0x20102); +	WREG32(0x657C, 0xBFE880C0); +	WREG32(0x6578, 0x20103); +	WREG32(0x657C, 0x80008000); +	WREG32(0x6578, 0x20200); +	WREG32(0x657C, 0x8018BFF8); +	WREG32(0x6578, 0x20201); +	WREG32(0x657C, 0x8F80BF08); +	WREG32(0x6578, 0x20202); +	WREG32(0x657C, 0xBFD081A0); +	WREG32(0x6578, 0x20203); +	WREG32(0x657C, 0xBFF88000); +	WREG32(0x6578, 0x20300); +	WREG32(0x657C, 0x80188000); +	WREG32(0x6578, 0x20301); +	WREG32(0x657C, 0x8EE0BEC0); +	WREG32(0x6578, 0x20302); +	WREG32(0x657C, 0xBFB082A0); +	WREG32(0x6578, 0x20303); +	WREG32(0x657C, 0x80008000); +	WREG32(0x6578, 0x20400); +	WREG32(0x657C, 0x80188000); +	WREG32(0x6578, 0x20401); +	WREG32(0x657C, 0x8E00BEA0); +	WREG32(0x6578, 0x20402); +	WREG32(0x657C, 0xBF8883C0); +	WREG32(0x6578, 0x20403); +	WREG32(0x657C, 0x80008000); +	WREG32(0x6578, 0x20500); +	WREG32(0x657C, 0x80188000); +	WREG32(0x6578, 0x20501); +	WREG32(0x657C, 0x8D00BE90); +	WREG32(0x6578, 0x20502); +	WREG32(0x657C, 0xBF588500); +	WREG32(0x6578, 0x20503); +	WREG32(0x657C, 0x80008008); +	WREG32(0x6578, 0x20600); +	WREG32(0x657C, 0x80188000); +	WREG32(0x6578, 0x20601); +	WREG32(0x657C, 0x8BC0BE98); +	WREG32(0x6578, 0x20602); +	WREG32(0x657C, 0xBF308660); +	WREG32(0x6578, 0x20603); +	WREG32(0x657C, 0x80008008); +	WREG32(0x6578, 0x20700); +	WREG32(0x657C, 0x80108000); +	WREG32(0x6578, 0x20701); +	WREG32(0x657C, 0x8A80BEB0); +	WREG32(0x6578, 0x20702); +	WREG32(0x657C, 0xBF0087C0); +	WREG32(0x6578, 0x20703); +	WREG32(0x657C, 0x80008008); +	WREG32(0x6578, 0x20800); +	WREG32(0x657C, 0x80108000); +	WREG32(0x6578, 0x20801); +	WREG32(0x657C, 0x8920BED0); +	WREG32(0x6578, 0x20802); +	WREG32(0x657C, 0xBED08920); +	WREG32(0x6578, 0x20803); +	WREG32(0x657C, 0x80008010); +	WREG32(0x6578, 0x30000); +	WREG32(0x657C, 0x90008000); +	WREG32(0x6578, 0x30001); +	WREG32(0x657C, 0x80008000); +	WREG32(0x6578, 0x30100); +	WREG32(0x657C, 0x8FE0BF90); +	WREG32(0x6578, 0x30101); +	WREG32(0x657C, 0xBFF880A0); +	WREG32(0x6578, 0x30200); +	WREG32(0x657C, 0x8F60BF40); +	WREG32(0x6578, 0x30201); +	WREG32(0x657C, 0xBFE88180); +	WREG32(0x6578, 0x30300); +	WREG32(0x657C, 0x8EC0BF00); +	WREG32(0x6578, 0x30301); +	WREG32(0x657C, 0xBFC88280); +	WREG32(0x6578, 0x30400); +	WREG32(0x657C, 0x8DE0BEE0); +	WREG32(0x6578, 0x30401); +	WREG32(0x657C, 0xBFA083A0); +	WREG32(0x6578, 0x30500); +	WREG32(0x657C, 0x8CE0BED0); +	WREG32(0x6578, 0x30501); +	WREG32(0x657C, 0xBF7884E0); +	WREG32(0x6578, 0x30600); +	WREG32(0x657C, 0x8BA0BED8); +	WREG32(0x6578, 0x30601); +	WREG32(0x657C, 0xBF508640); +	WREG32(0x6578, 0x30700); +	WREG32(0x657C, 0x8A60BEE8); +	WREG32(0x6578, 0x30701); +	WREG32(0x657C, 0xBF2087A0); +	WREG32(0x6578, 0x30800); +	WREG32(0x657C, 0x8900BF00); +	WREG32(0x6578, 0x30801); +	WREG32(0x657C, 0xBF008900); +} + +struct rv515_watermark { +	u32        lb_request_fifo_depth; +	fixed20_12 num_line_pair; +	fixed20_12 estimated_width; +	fixed20_12 worst_case_latency; +	fixed20_12 consumption_rate; +	fixed20_12 active_time; +	fixed20_12 dbpp; +	fixed20_12 priority_mark_max; +	fixed20_12 priority_mark; +	fixed20_12 sclk; +}; + +void rv515_crtc_bandwidth_compute(struct radeon_device *rdev, +				  struct radeon_crtc *crtc, +				  struct rv515_watermark *wm) +{ +	struct drm_display_mode *mode = &crtc->base.mode; +	fixed20_12 a, b, c; +	fixed20_12 pclk, request_fifo_depth, tolerable_latency, estimated_width; +	fixed20_12 consumption_time, line_time, chunk_time, read_delay_latency; + +	if (!crtc->base.enabled) { +		/* FIXME: wouldn't it better to set priority mark to maximum */ +		wm->lb_request_fifo_depth = 4; +		return; +	} + +	if (crtc->vsc.full > rfixed_const(2)) +		wm->num_line_pair.full = rfixed_const(2); +	else +		wm->num_line_pair.full = rfixed_const(1); + +	b.full = rfixed_const(mode->crtc_hdisplay); +	c.full = rfixed_const(256); +	a.full = rfixed_mul(wm->num_line_pair, b); +	request_fifo_depth.full = rfixed_div(a, c); +	if (a.full < rfixed_const(4)) { +		wm->lb_request_fifo_depth = 4; +	} else { +		wm->lb_request_fifo_depth = rfixed_trunc(request_fifo_depth); +	} + +	/* Determine consumption rate +	 *  pclk = pixel clock period(ns) = 1000 / (mode.clock / 1000) +	 *  vtaps = number of vertical taps, +	 *  vsc = vertical scaling ratio, defined as source/destination +	 *  hsc = horizontal scaling ration, defined as source/destination +	 */ +	a.full = rfixed_const(mode->clock); +	b.full = rfixed_const(1000); +	a.full = rfixed_div(a, b); +	pclk.full = rfixed_div(b, a); +	if (crtc->rmx_type != RMX_OFF) { +		b.full = rfixed_const(2); +		if (crtc->vsc.full > b.full) +			b.full = crtc->vsc.full; +		b.full = rfixed_mul(b, crtc->hsc); +		c.full = rfixed_const(2); +		b.full = rfixed_div(b, c); +		consumption_time.full = rfixed_div(pclk, b); +	} else { +		consumption_time.full = pclk.full; +	} +	a.full = rfixed_const(1); +	wm->consumption_rate.full = rfixed_div(a, consumption_time); + + +	/* Determine line time +	 *  LineTime = total time for one line of displayhtotal +	 *  LineTime = total number of horizontal pixels +	 *  pclk = pixel clock period(ns) +	 */ +	a.full = rfixed_const(crtc->base.mode.crtc_htotal); +	line_time.full = rfixed_mul(a, pclk); + +	/* Determine active time +	 *  ActiveTime = time of active region of display within one line, +	 *  hactive = total number of horizontal active pixels +	 *  htotal = total number of horizontal pixels +	 */ +	a.full = rfixed_const(crtc->base.mode.crtc_htotal); +	b.full = rfixed_const(crtc->base.mode.crtc_hdisplay); +	wm->active_time.full = rfixed_mul(line_time, b); +	wm->active_time.full = rfixed_div(wm->active_time, a); + +	/* Determine chunk time +	 * ChunkTime = the time it takes the DCP to send one chunk of data +	 * to the LB which consists of pipeline delay and inter chunk gap +	 * sclk = system clock(Mhz) +	 */ +	a.full = rfixed_const(600 * 1000); +	chunk_time.full = rfixed_div(a, rdev->pm.sclk); +	read_delay_latency.full = rfixed_const(1000); + +	/* Determine the worst case latency +	 * NumLinePair = Number of line pairs to request(1=2 lines, 2=4 lines) +	 * WorstCaseLatency = worst case time from urgent to when the MC starts +	 *                    to return data +	 * READ_DELAY_IDLE_MAX = constant of 1us +	 * ChunkTime = time it takes the DCP to send one chunk of data to the LB +	 *             which consists of pipeline delay and inter chunk gap +	 */ +	if (rfixed_trunc(wm->num_line_pair) > 1) { +		a.full = rfixed_const(3); +		wm->worst_case_latency.full = rfixed_mul(a, chunk_time); +		wm->worst_case_latency.full += read_delay_latency.full; +	} else { +		wm->worst_case_latency.full = chunk_time.full + read_delay_latency.full; +	} + +	/* Determine the tolerable latency +	 * TolerableLatency = Any given request has only 1 line time +	 *                    for the data to be returned +	 * LBRequestFifoDepth = Number of chunk requests the LB can +	 *                      put into the request FIFO for a display +	 *  LineTime = total time for one line of display +	 *  ChunkTime = the time it takes the DCP to send one chunk +	 *              of data to the LB which consists of +	 *  pipeline delay and inter chunk gap +	 */ +	if ((2+wm->lb_request_fifo_depth) >= rfixed_trunc(request_fifo_depth)) { +		tolerable_latency.full = line_time.full; +	} else { +		tolerable_latency.full = rfixed_const(wm->lb_request_fifo_depth - 2); +		tolerable_latency.full = request_fifo_depth.full - tolerable_latency.full; +		tolerable_latency.full = rfixed_mul(tolerable_latency, chunk_time); +		tolerable_latency.full = line_time.full - tolerable_latency.full; +	} +	/* We assume worst case 32bits (4 bytes) */ +	wm->dbpp.full = rfixed_const(2 * 16); + +	/* Determine the maximum priority mark +	 *  width = viewport width in pixels +	 */ +	a.full = rfixed_const(16); +	wm->priority_mark_max.full = rfixed_const(crtc->base.mode.crtc_hdisplay); +	wm->priority_mark_max.full = rfixed_div(wm->priority_mark_max, a); + +	/* Determine estimated width */ +	estimated_width.full = tolerable_latency.full - wm->worst_case_latency.full; +	estimated_width.full = rfixed_div(estimated_width, consumption_time); +	if (rfixed_trunc(estimated_width) > crtc->base.mode.crtc_hdisplay) { +		wm->priority_mark.full = rfixed_const(10); +	} else { +		a.full = rfixed_const(16); +		wm->priority_mark.full = rfixed_div(estimated_width, a); +		wm->priority_mark.full = wm->priority_mark_max.full - wm->priority_mark.full; +	} +} + +void rv515_bandwidth_avivo_update(struct radeon_device *rdev) +{ +	struct drm_display_mode *mode0 = NULL; +	struct drm_display_mode *mode1 = NULL; +	struct rv515_watermark wm0; +	struct rv515_watermark wm1; +	u32 tmp; +	fixed20_12 priority_mark02, priority_mark12, fill_rate; +	fixed20_12 a, b; + +	if (rdev->mode_info.crtcs[0]->base.enabled) +		mode0 = &rdev->mode_info.crtcs[0]->base.mode; +	if (rdev->mode_info.crtcs[1]->base.enabled) +		mode1 = &rdev->mode_info.crtcs[1]->base.mode; +	rs690_line_buffer_adjust(rdev, mode0, mode1); + +	rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0); +	rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1); + +	tmp = wm0.lb_request_fifo_depth; +	tmp |= wm1.lb_request_fifo_depth << 16; +	WREG32(LB_MAX_REQ_OUTSTANDING, tmp); + +	if (mode0 && mode1) { +		if (rfixed_trunc(wm0.dbpp) > 64) +			a.full = rfixed_div(wm0.dbpp, wm0.num_line_pair); +		else +			a.full = wm0.num_line_pair.full; +		if (rfixed_trunc(wm1.dbpp) > 64) +			b.full = rfixed_div(wm1.dbpp, wm1.num_line_pair); +		else +			b.full = wm1.num_line_pair.full; +		a.full += b.full; +		fill_rate.full = rfixed_div(wm0.sclk, a); +		if (wm0.consumption_rate.full > fill_rate.full) { +			b.full = wm0.consumption_rate.full - fill_rate.full; +			b.full = rfixed_mul(b, wm0.active_time); +			a.full = rfixed_const(16); +			b.full = rfixed_div(b, a); +			a.full = rfixed_mul(wm0.worst_case_latency, +						wm0.consumption_rate); +			priority_mark02.full = a.full + b.full; +		} else { +			a.full = rfixed_mul(wm0.worst_case_latency, +						wm0.consumption_rate); +			b.full = rfixed_const(16 * 1000); +			priority_mark02.full = rfixed_div(a, b); +		} +		if (wm1.consumption_rate.full > fill_rate.full) { +			b.full = wm1.consumption_rate.full - fill_rate.full; +			b.full = rfixed_mul(b, wm1.active_time); +			a.full = rfixed_const(16); +			b.full = rfixed_div(b, a); +			a.full = rfixed_mul(wm1.worst_case_latency, +						wm1.consumption_rate); +			priority_mark12.full = a.full + b.full; +		} else { +			a.full = rfixed_mul(wm1.worst_case_latency, +						wm1.consumption_rate); +			b.full = rfixed_const(16 * 1000); +			priority_mark12.full = rfixed_div(a, b); +		} +		if (wm0.priority_mark.full > priority_mark02.full) +			priority_mark02.full = wm0.priority_mark.full; +		if (rfixed_trunc(priority_mark02) < 0) +			priority_mark02.full = 0; +		if (wm0.priority_mark_max.full > priority_mark02.full) +			priority_mark02.full = wm0.priority_mark_max.full; +		if (wm1.priority_mark.full > priority_mark12.full) +			priority_mark12.full = wm1.priority_mark.full; +		if (rfixed_trunc(priority_mark12) < 0) +			priority_mark12.full = 0; +		if (wm1.priority_mark_max.full > priority_mark12.full) +			priority_mark12.full = wm1.priority_mark_max.full; +		WREG32(D1MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark02)); +		WREG32(D1MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark02)); +		WREG32(D2MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark12)); +		WREG32(D2MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark12)); +	} else if (mode0) { +		if (rfixed_trunc(wm0.dbpp) > 64) +			a.full = rfixed_div(wm0.dbpp, wm0.num_line_pair); +		else +			a.full = wm0.num_line_pair.full; +		fill_rate.full = rfixed_div(wm0.sclk, a); +		if (wm0.consumption_rate.full > fill_rate.full) { +			b.full = wm0.consumption_rate.full - fill_rate.full; +			b.full = rfixed_mul(b, wm0.active_time); +			a.full = rfixed_const(16); +			b.full = rfixed_div(b, a); +			a.full = rfixed_mul(wm0.worst_case_latency, +						wm0.consumption_rate); +			priority_mark02.full = a.full + b.full; +		} else { +			a.full = rfixed_mul(wm0.worst_case_latency, +						wm0.consumption_rate); +			b.full = rfixed_const(16); +			priority_mark02.full = rfixed_div(a, b); +		} +		if (wm0.priority_mark.full > priority_mark02.full) +			priority_mark02.full = wm0.priority_mark.full; +		if (rfixed_trunc(priority_mark02) < 0) +			priority_mark02.full = 0; +		if (wm0.priority_mark_max.full > priority_mark02.full) +			priority_mark02.full = wm0.priority_mark_max.full; +		WREG32(D1MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark02)); +		WREG32(D1MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark02)); +		WREG32(D2MODE_PRIORITY_A_CNT, MODE_PRIORITY_OFF); +		WREG32(D2MODE_PRIORITY_B_CNT, MODE_PRIORITY_OFF); +	} else { +		if (rfixed_trunc(wm1.dbpp) > 64) +			a.full = rfixed_div(wm1.dbpp, wm1.num_line_pair); +		else +			a.full = wm1.num_line_pair.full; +		fill_rate.full = rfixed_div(wm1.sclk, a); +		if (wm1.consumption_rate.full > fill_rate.full) { +			b.full = wm1.consumption_rate.full - fill_rate.full; +			b.full = rfixed_mul(b, wm1.active_time); +			a.full = rfixed_const(16); +			b.full = rfixed_div(b, a); +			a.full = rfixed_mul(wm1.worst_case_latency, +						wm1.consumption_rate); +			priority_mark12.full = a.full + b.full; +		} else { +			a.full = rfixed_mul(wm1.worst_case_latency, +						wm1.consumption_rate); +			b.full = rfixed_const(16 * 1000); +			priority_mark12.full = rfixed_div(a, b); +		} +		if (wm1.priority_mark.full > priority_mark12.full) +			priority_mark12.full = wm1.priority_mark.full; +		if (rfixed_trunc(priority_mark12) < 0) +			priority_mark12.full = 0; +		if (wm1.priority_mark_max.full > priority_mark12.full) +			priority_mark12.full = wm1.priority_mark_max.full; +		WREG32(D1MODE_PRIORITY_A_CNT, MODE_PRIORITY_OFF); +		WREG32(D1MODE_PRIORITY_B_CNT, MODE_PRIORITY_OFF); +		WREG32(D2MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark12)); +		WREG32(D2MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark12)); +	} +} + +void rv515_bandwidth_update(struct radeon_device *rdev) +{ +	uint32_t tmp; +	struct drm_display_mode *mode0 = NULL; +	struct drm_display_mode *mode1 = NULL; + +	if (rdev->mode_info.crtcs[0]->base.enabled) +		mode0 = &rdev->mode_info.crtcs[0]->base.mode; +	if (rdev->mode_info.crtcs[1]->base.enabled) +		mode1 = &rdev->mode_info.crtcs[1]->base.mode; +	/* +	 * Set display0/1 priority up in the memory controller for +	 * modes if the user specifies HIGH for displaypriority +	 * option. +	 */ +	if (rdev->disp_priority == 2) { +		tmp = RREG32_MC(MC_MISC_LAT_TIMER); +		tmp &= ~MC_DISP1R_INIT_LAT_MASK; +		tmp &= ~MC_DISP0R_INIT_LAT_MASK; +		if (mode1) +			tmp |= (1 << MC_DISP1R_INIT_LAT_SHIFT); +		if (mode0) +			tmp |= (1 << MC_DISP0R_INIT_LAT_SHIFT); +		WREG32_MC(MC_MISC_LAT_TIMER, tmp); +	} +	rv515_bandwidth_avivo_update(rdev); +} diff --git a/drivers/gpu/drm/radeon/rv515r.h b/drivers/gpu/drm/radeon/rv515r.h new file mode 100644 index 00000000000..f3cf8403990 --- /dev/null +++ b/drivers/gpu/drm/radeon/rv515r.h @@ -0,0 +1,170 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + *          Alex Deucher + *          Jerome Glisse + */ +#ifndef RV515R_H +#define RV515R_H + +/* RV515 registers */ +#define PCIE_INDEX			0x0030 +#define PCIE_DATA			0x0034 +#define	MC_IND_INDEX			0x0070 +#define		MC_IND_WR_EN				(1 << 24) +#define	MC_IND_DATA			0x0074 +#define	RBBM_SOFT_RESET			0x00F0 +#define	CONFIG_MEMSIZE			0x00F8 +#define HDP_FB_LOCATION			0x0134 +#define	CP_CSQ_CNTL			0x0740 +#define	CP_CSQ_MODE			0x0744 +#define	CP_CSQ_ADDR			0x07F0 +#define	CP_CSQ_DATA			0x07F4 +#define	CP_CSQ_STAT			0x07F8 +#define	CP_CSQ2_STAT			0x07FC +#define	RBBM_STATUS			0x0E40 +#define	DST_PIPE_CONFIG			0x170C +#define	WAIT_UNTIL			0x1720 +#define		WAIT_2D_IDLE				(1 << 14) +#define		WAIT_3D_IDLE				(1 << 15) +#define		WAIT_2D_IDLECLEAN			(1 << 16) +#define		WAIT_3D_IDLECLEAN			(1 << 17) +#define	ISYNC_CNTL			0x1724 +#define		ISYNC_ANY2D_IDLE3D			(1 << 0) +#define		ISYNC_ANY3D_IDLE2D			(1 << 1) +#define		ISYNC_TRIG2D_IDLE3D			(1 << 2) +#define		ISYNC_TRIG3D_IDLE2D			(1 << 3) +#define		ISYNC_WAIT_IDLEGUI			(1 << 4) +#define		ISYNC_CPSCRATCH_IDLEGUI			(1 << 5) +#define	VAP_INDEX_OFFSET		0x208C +#define	VAP_PVS_STATE_FLUSH_REG		0x2284 +#define	GB_ENABLE			0x4008 +#define	GB_MSPOS0			0x4010 +#define		MS_X0_SHIFT				0 +#define		MS_Y0_SHIFT				4 +#define		MS_X1_SHIFT				8 +#define		MS_Y1_SHIFT				12 +#define		MS_X2_SHIFT				16 +#define		MS_Y2_SHIFT				20 +#define		MSBD0_Y_SHIFT				24 +#define		MSBD0_X_SHIFT				28 +#define	GB_MSPOS1			0x4014 +#define		MS_X3_SHIFT				0 +#define		MS_Y3_SHIFT				4 +#define		MS_X4_SHIFT				8 +#define		MS_Y4_SHIFT				12 +#define		MS_X5_SHIFT				16 +#define		MS_Y5_SHIFT				20 +#define		MSBD1_SHIFT				24 +#define GB_TILE_CONFIG			0x4018 +#define		ENABLE_TILING				(1 << 0) +#define		PIPE_COUNT_MASK				0x0000000E +#define		PIPE_COUNT_SHIFT			1 +#define		TILE_SIZE_8				(0 << 4) +#define		TILE_SIZE_16				(1 << 4) +#define		TILE_SIZE_32				(2 << 4) +#define		SUBPIXEL_1_12				(0 << 16) +#define		SUBPIXEL_1_16				(1 << 16) +#define	GB_SELECT			0x401C +#define	GB_AA_CONFIG			0x4020 +#define	GB_PIPE_SELECT			0x402C +#define	GA_ENHANCE			0x4274 +#define		GA_DEADLOCK_CNTL			(1 << 0) +#define		GA_FASTSYNC_CNTL			(1 << 1) +#define	GA_POLY_MODE			0x4288 +#define		FRONT_PTYPE_POINT			(0 << 4) +#define		FRONT_PTYPE_LINE			(1 << 4) +#define		FRONT_PTYPE_TRIANGE			(2 << 4) +#define		BACK_PTYPE_POINT			(0 << 7) +#define		BACK_PTYPE_LINE				(1 << 7) +#define		BACK_PTYPE_TRIANGE			(2 << 7) +#define	GA_ROUND_MODE			0x428C +#define		GEOMETRY_ROUND_TRUNC			(0 << 0) +#define		GEOMETRY_ROUND_NEAREST			(1 << 0) +#define		COLOR_ROUND_TRUNC			(0 << 2) +#define		COLOR_ROUND_NEAREST			(1 << 2) +#define	SU_REG_DEST			0x42C8 +#define	RB3D_DSTCACHE_CTLSTAT		0x4E4C +#define		RB3D_DC_FLUSH				(2 << 0) +#define		RB3D_DC_FREE				(2 << 2) +#define		RB3D_DC_FINISH				(1 << 4) +#define ZB_ZCACHE_CTLSTAT		0x4F18 +#define		ZC_FLUSH				(1 << 0) +#define		ZC_FREE					(1 << 1) +#define DC_LB_MEMORY_SPLIT		0x6520 +#define		DC_LB_MEMORY_SPLIT_MASK			0x00000003 +#define		DC_LB_MEMORY_SPLIT_SHIFT		0 +#define		DC_LB_MEMORY_SPLIT_D1HALF_D2HALF	0 +#define		DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q		1 +#define		DC_LB_MEMORY_SPLIT_D1_ONLY		2 +#define		DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q		3 +#define		DC_LB_MEMORY_SPLIT_SHIFT_MODE		(1 << 2) +#define		DC_LB_DISP1_END_ADR_SHIFT		4 +#define		DC_LB_DISP1_END_ADR_MASK		0x00007FF0 +#define D1MODE_PRIORITY_A_CNT		0x6548 +#define		MODE_PRIORITY_MARK_MASK			0x00007FFF +#define		MODE_PRIORITY_OFF			(1 << 16) +#define		MODE_PRIORITY_ALWAYS_ON			(1 << 20) +#define		MODE_PRIORITY_FORCE_MASK		(1 << 24) +#define D1MODE_PRIORITY_B_CNT		0x654C +#define LB_MAX_REQ_OUTSTANDING		0x6D58 +#define		LB_D1_MAX_REQ_OUTSTANDING_MASK		0x0000000F +#define		LB_D1_MAX_REQ_OUTSTANDING_SHIFT		0 +#define		LB_D2_MAX_REQ_OUTSTANDING_MASK		0x000F0000 +#define		LB_D2_MAX_REQ_OUTSTANDING_SHIFT		16 +#define D2MODE_PRIORITY_A_CNT		0x6D48 +#define D2MODE_PRIORITY_B_CNT		0x6D4C + +/* ix[MC] registers */ +#define MC_FB_LOCATION			0x01 +#define		MC_FB_START_MASK			0x0000FFFF +#define		MC_FB_START_SHIFT			0 +#define		MC_FB_TOP_MASK				0xFFFF0000 +#define		MC_FB_TOP_SHIFT				16 +#define MC_AGP_LOCATION			0x02 +#define		MC_AGP_START_MASK			0x0000FFFF +#define		MC_AGP_START_SHIFT			0 +#define		MC_AGP_TOP_MASK				0xFFFF0000 +#define		MC_AGP_TOP_SHIFT			16 +#define MC_AGP_BASE			0x03 +#define MC_AGP_BASE_2			0x04 +#define	MC_CNTL				0x5 +#define		MEM_NUM_CHANNELS_MASK			0x00000003 +#define	MC_STATUS			0x08 +#define		MC_STATUS_IDLE				(1 << 4) +#define	MC_MISC_LAT_TIMER		0x09 +#define		MC_CPR_INIT_LAT_MASK			0x0000000F +#define		MC_VF_INIT_LAT_MASK			0x000000F0 +#define		MC_DISP0R_INIT_LAT_MASK			0x00000F00 +#define		MC_DISP0R_INIT_LAT_SHIFT		8 +#define		MC_DISP1R_INIT_LAT_MASK			0x0000F000 +#define		MC_DISP1R_INIT_LAT_SHIFT		12 +#define		MC_FIXED_INIT_LAT_MASK			0x000F0000 +#define		MC_E2R_INIT_LAT_MASK			0x00F00000 +#define		SAME_PAGE_PRIO_MASK			0x0F000000 +#define		MC_GLOBW_INIT_LAT_MASK			0xF0000000 + + +#endif + diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index da50cc51ede..21d8ffd5730 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -67,7 +67,7 @@ int rv770_mc_init(struct radeon_device *rdev)  		       "programming pipes. Bad things might happen.\n");  	} -	tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1; +	tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;  	tmp = REG_SET(R700_MC_FB_TOP, tmp >> 24);  	tmp |= REG_SET(R700_MC_FB_BASE, rdev->mc.vram_location >> 24);  	WREG32(R700_MC_VM_FB_LOCATION, tmp); diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 0d0b1b7afbc..fa87ccbcc6c 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -43,7 +43,6 @@  #define TTM_BO_HASH_ORDER 13  static int ttm_bo_setup_vm(struct ttm_buffer_object *bo); -static void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo);  static int ttm_bo_swapout(struct ttm_mem_shrink *shrink);  static void ttm_bo_global_kobj_release(struct kobject *kobj); @@ -259,6 +258,9 @@ static int ttm_bo_add_ttm(struct ttm_buffer_object *bo, bool zero_alloc)  	TTM_ASSERT_LOCKED(&bo->mutex);  	bo->ttm = NULL; +	if (bdev->need_dma32) +		page_flags |= TTM_PAGE_FLAG_DMA32; +  	switch (bo->type) {  	case ttm_bo_type_device:  		if (zero_alloc) @@ -339,6 +341,9 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,  	} +	if (bdev->driver->move_notify) +		bdev->driver->move_notify(bo, mem); +  	if (!(old_man->flags & TTM_MEMTYPE_FLAG_FIXED) &&  	    !(new_man->flags & TTM_MEMTYPE_FLAG_FIXED))  		ret = ttm_bo_move_ttm(bo, evict, no_wait, mem); @@ -694,31 +699,52 @@ retry_pre_get:  	return 0;  } +static uint32_t ttm_bo_select_caching(struct ttm_mem_type_manager *man, +				      uint32_t cur_placement, +				      uint32_t proposed_placement) +{ +	uint32_t caching = proposed_placement & TTM_PL_MASK_CACHING; +	uint32_t result = proposed_placement & ~TTM_PL_MASK_CACHING; + +	/** +	 * Keep current caching if possible. +	 */ + +	if ((cur_placement & caching) != 0) +		result |= (cur_placement & caching); +	else if ((man->default_caching & caching) != 0) +		result |= man->default_caching; +	else if ((TTM_PL_FLAG_CACHED & caching) != 0) +		result |= TTM_PL_FLAG_CACHED; +	else if ((TTM_PL_FLAG_WC & caching) != 0) +		result |= TTM_PL_FLAG_WC; +	else if ((TTM_PL_FLAG_UNCACHED & caching) != 0) +		result |= TTM_PL_FLAG_UNCACHED; + +	return result; +} + +  static bool ttm_bo_mt_compatible(struct ttm_mem_type_manager *man,  				 bool disallow_fixed,  				 uint32_t mem_type, -				 uint32_t mask, uint32_t *res_mask) +				 uint32_t proposed_placement, +				 uint32_t *masked_placement)  {  	uint32_t cur_flags = ttm_bo_type_flags(mem_type);  	if ((man->flags & TTM_MEMTYPE_FLAG_FIXED) && disallow_fixed)  		return false; -	if ((cur_flags & mask & TTM_PL_MASK_MEM) == 0) +	if ((cur_flags & proposed_placement & TTM_PL_MASK_MEM) == 0)  		return false; -	if ((mask & man->available_caching) == 0) +	if ((proposed_placement & man->available_caching) == 0)  		return false; -	if (mask & man->default_caching) -		cur_flags |= man->default_caching; -	else if (mask & TTM_PL_FLAG_CACHED) -		cur_flags |= TTM_PL_FLAG_CACHED; -	else if (mask & TTM_PL_FLAG_WC) -		cur_flags |= TTM_PL_FLAG_WC; -	else -		cur_flags |= TTM_PL_FLAG_UNCACHED; -	*res_mask = cur_flags; +	cur_flags |= (proposed_placement & man->available_caching); + +	*masked_placement = cur_flags;  	return true;  } @@ -763,6 +789,9 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,  		if (!type_ok)  			continue; +		cur_flags = ttm_bo_select_caching(man, bo->mem.placement, +						  cur_flags); +  		if (mem_type == TTM_PL_SYSTEM)  			break; @@ -819,6 +848,9 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,  					  proposed_placement, &cur_flags))  			continue; +		cur_flags = ttm_bo_select_caching(man, bo->mem.placement, +						  cur_flags); +  		ret = ttm_bo_mem_force_space(bdev, mem, mem_type,  					     interruptible, no_wait); @@ -1194,13 +1226,14 @@ static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev,  int ttm_bo_clean_mm(struct ttm_bo_device *bdev, unsigned mem_type)  {  	struct ttm_bo_global *glob = bdev->glob; -	struct ttm_mem_type_manager *man = &bdev->man[mem_type]; +	struct ttm_mem_type_manager *man;  	int ret = -EINVAL;  	if (mem_type >= TTM_NUM_MEM_TYPES) {  		printk(KERN_ERR TTM_PFX "Illegal memory type %d\n", mem_type);  		return ret;  	} +	man = &bdev->man[mem_type];  	if (!man->has_type) {  		printk(KERN_ERR TTM_PFX "Trying to take down uninitialized " @@ -1417,7 +1450,8 @@ EXPORT_SYMBOL(ttm_bo_device_release);  int ttm_bo_device_init(struct ttm_bo_device *bdev,  		       struct ttm_bo_global *glob,  		       struct ttm_bo_driver *driver, -		       uint64_t file_page_offset) +		       uint64_t file_page_offset, +		       bool need_dma32)  {  	int ret = -EINVAL; @@ -1446,6 +1480,7 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev,  	INIT_LIST_HEAD(&bdev->ddestroy);  	bdev->dev_mapping = NULL;  	bdev->glob = glob; +	bdev->need_dma32 = need_dma32;  	mutex_lock(&glob->device_list_mutex);  	list_add_tail(&bdev->device_list, &glob->device_list); @@ -1511,6 +1546,7 @@ void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo)  	unmap_mapping_range(bdev->dev_mapping, offset, holelen, 1);  } +EXPORT_SYMBOL(ttm_bo_unmap_virtual);  static void ttm_bo_vm_insert_rb(struct ttm_buffer_object *bo)  { @@ -1632,6 +1668,10 @@ int ttm_bo_wait(struct ttm_buffer_object *bo,  			driver->sync_obj_unref(&sync_obj);  			driver->sync_obj_unref(&tmp_obj);  			spin_lock(&bo->lock); +		} else { +			spin_unlock(&bo->lock); +			driver->sync_obj_unref(&sync_obj); +			spin_lock(&bo->lock);  		}  	}  	return 0; diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 12cd47aa18c..c70927ecda2 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -136,7 +136,8 @@ static int ttm_copy_io_page(void *dst, void *src, unsigned long page)  }  static int ttm_copy_io_ttm_page(struct ttm_tt *ttm, void *src, -				unsigned long page) +				unsigned long page, +				pgprot_t prot)  {  	struct page *d = ttm_tt_get_page(ttm, page);  	void *dst; @@ -145,17 +146,35 @@ static int ttm_copy_io_ttm_page(struct ttm_tt *ttm, void *src,  		return -ENOMEM;  	src = (void *)((unsigned long)src + (page << PAGE_SHIFT)); -	dst = kmap(d); + +#ifdef CONFIG_X86 +	dst = kmap_atomic_prot(d, KM_USER0, prot); +#else +	if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) +		dst = vmap(&d, 1, 0, prot); +	else +		dst = kmap(d); +#endif  	if (!dst)  		return -ENOMEM;  	memcpy_fromio(dst, src, PAGE_SIZE); -	kunmap(d); + +#ifdef CONFIG_X86 +	kunmap_atomic(dst, KM_USER0); +#else +	if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) +		vunmap(dst); +	else +		kunmap(d); +#endif +  	return 0;  }  static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst, -				unsigned long page) +				unsigned long page, +				pgprot_t prot)  {  	struct page *s = ttm_tt_get_page(ttm, page);  	void *src; @@ -164,12 +183,28 @@ static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst,  		return -ENOMEM;  	dst = (void *)((unsigned long)dst + (page << PAGE_SHIFT)); -	src = kmap(s); +#ifdef CONFIG_X86 +	src = kmap_atomic_prot(s, KM_USER0, prot); +#else +	if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) +		src = vmap(&s, 1, 0, prot); +	else +		src = kmap(s); +#endif  	if (!src)  		return -ENOMEM;  	memcpy_toio(dst, src, PAGE_SIZE); -	kunmap(s); + +#ifdef CONFIG_X86 +	kunmap_atomic(src, KM_USER0); +#else +	if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) +		vunmap(src); +	else +		kunmap(s); +#endif +  	return 0;  } @@ -214,11 +249,17 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,  	for (i = 0; i < new_mem->num_pages; ++i) {  		page = i * dir + add; -		if (old_iomap == NULL) -			ret = ttm_copy_ttm_io_page(ttm, new_iomap, page); -		else if (new_iomap == NULL) -			ret = ttm_copy_io_ttm_page(ttm, old_iomap, page); -		else +		if (old_iomap == NULL) { +			pgprot_t prot = ttm_io_prot(old_mem->placement, +						    PAGE_KERNEL); +			ret = ttm_copy_ttm_io_page(ttm, new_iomap, page, +						   prot); +		} else if (new_iomap == NULL) { +			pgprot_t prot = ttm_io_prot(new_mem->placement, +						    PAGE_KERNEL); +			ret = ttm_copy_io_ttm_page(ttm, old_iomap, page, +						   prot); +		} else  			ret = ttm_copy_io_page(new_iomap, old_iomap, page);  		if (ret)  			goto out1; @@ -509,8 +550,8 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,  	if (evict) {  		ret = ttm_bo_wait(bo, false, false, false);  		spin_unlock(&bo->lock); -		driver->sync_obj_unref(&bo->sync_obj); - +		if (tmp_obj) +			driver->sync_obj_unref(&tmp_obj);  		if (ret)  			return ret; @@ -532,6 +573,8 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,  		set_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags);  		spin_unlock(&bo->lock); +		if (tmp_obj) +			driver->sync_obj_unref(&tmp_obj);  		ret = ttm_buffer_object_transfer(bo, &ghost_obj);  		if (ret) diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 40b75032ea4..33de7637c0c 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -101,6 +101,9 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)  		return VM_FAULT_NOPAGE;  	} +	if (bdev->driver->fault_reserve_notify) +		bdev->driver->fault_reserve_notify(bo); +  	/*  	 * Wait for buffer data in transit, due to a pipelined  	 * move. @@ -327,7 +330,7 @@ ssize_t ttm_bo_io(struct ttm_bo_device *bdev, struct file *filp,  		goto out_unref;  	kmap_offset = dev_offset - bo->vm_node->start; -	if (unlikely(kmap_offset) >= bo->num_pages) { +	if (unlikely(kmap_offset >= bo->num_pages)) {  		ret = -EFBIG;  		goto out_unref;  	} @@ -401,7 +404,7 @@ ssize_t ttm_bo_fbdev_io(struct ttm_buffer_object *bo, const char __user *wbuf,  	bool dummy;  	kmap_offset = (*f_pos >> PAGE_SHIFT); -	if (unlikely(kmap_offset) >= bo->num_pages) +	if (unlikely(kmap_offset >= bo->num_pages))  		return -EFBIG;  	page_offset = *f_pos & ~PAGE_MASK; diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index b0f73096d37..42cca551976 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -86,10 +86,16 @@ void ttm_tt_cache_flush(struct page *pages[], unsigned long num_pages)  	unsigned long i;  	for (i = 0; i < num_pages; ++i) { -		if (pages[i]) { -			unsigned long start = (unsigned long)page_address(pages[i]); -			flush_dcache_range(start, start + PAGE_SIZE); -		} +		struct page *page = pages[i]; +		void *page_virtual; + +		if (unlikely(page == NULL)) +			continue; + +		page_virtual = kmap_atomic(page, KM_USER0); +		flush_dcache_range((unsigned long) page_virtual, +				   (unsigned long) page_virtual + PAGE_SIZE); +		kunmap_atomic(page_virtual, KM_USER0);  	}  #else  	if (on_each_cpu(ttm_tt_ipi_handler, NULL, 1) != 0) @@ -131,10 +137,17 @@ static void ttm_tt_free_page_directory(struct ttm_tt *ttm)  static struct page *ttm_tt_alloc_page(unsigned page_flags)  { +	gfp_t gfp_flags = GFP_USER; +  	if (page_flags & TTM_PAGE_FLAG_ZERO_ALLOC) -		return alloc_page(GFP_HIGHUSER | __GFP_ZERO); +		gfp_flags |= __GFP_ZERO; + +	if (page_flags & TTM_PAGE_FLAG_DMA32) +		gfp_flags |= __GFP_DMA32; +	else +		gfp_flags |= __GFP_HIGHMEM; -	return alloc_page(GFP_HIGHUSER); +	return alloc_page(gfp_flags);  }  static void ttm_tt_free_user_pages(struct ttm_tt *ttm) diff --git a/drivers/gpu/drm/via/via_irq.c b/drivers/gpu/drm/via/via_irq.c index c248c1d3726..5935b8842e8 100644 --- a/drivers/gpu/drm/via/via_irq.c +++ b/drivers/gpu/drm/via/via_irq.c @@ -183,7 +183,7 @@ int via_enable_vblank(struct drm_device *dev, int crtc)  	}  	status = VIA_READ(VIA_REG_INTERRUPT); -	VIA_WRITE(VIA_REG_INTERRUPT, status & VIA_IRQ_VBLANK_ENABLE); +	VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_VBLANK_ENABLE);  	VIA_WRITE8(0x83d4, 0x11);  	VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30); @@ -194,6 +194,10 @@ int via_enable_vblank(struct drm_device *dev, int crtc)  void via_disable_vblank(struct drm_device *dev, int crtc)  {  	drm_via_private_t *dev_priv = dev->dev_private; +	u32 status; + +	status = VIA_READ(VIA_REG_INTERRUPT); +	VIA_WRITE(VIA_REG_INTERRUPT, status & ~VIA_IRQ_VBLANK_ENABLE);  	VIA_WRITE8(0x83d4, 0x11);  	VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30);  |