diff options
Diffstat (limited to 'drivers')
37 files changed, 669 insertions, 328 deletions
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 7f3be3506057..1fafc2f8e8f9 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -10,7 +10,7 @@ drm-y       :=	drm_auth.o drm_bufs.o drm_cache.o \  		drm_scatter.o drm_pci.o \  		drm_sysfs.o drm_hashtab.o drm_mm.o \  		drm_crtc.o drm_fourcc.o drm_modes.o drm_edid.o \ -		drm_info.o drm_encoder_slave.o \ +		drm_encoder_slave.o \  		drm_trace_points.o drm_prime.o \  		drm_rect.o drm_vma_manager.o drm_flip_work.o \  		drm_modeset_lock.o drm_atomic.o drm_bridge.o \ diff --git a/drivers/gpu/drm/arc/arcpgu_drv.c b/drivers/gpu/drm/arc/arcpgu_drv.c index 2af847ebca34..206a76abf771 100644 --- a/drivers/gpu/drm/arc/arcpgu_drv.c +++ b/drivers/gpu/drm/arc/arcpgu_drv.c @@ -190,7 +190,7 @@ err_unload:  	arcpgu_unload(drm);  err_unref: -	drm_dev_unref(drm); +	drm_dev_put(drm);  	return ret;  } @@ -201,7 +201,7 @@ static int arcpgu_remove(struct platform_device *pdev)  	drm_dev_unregister(drm);  	arcpgu_unload(drm); -	drm_dev_unref(drm); +	drm_dev_put(drm);  	return 0;  } diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c index ee6b98efa9c2..afd491018bfc 100644 --- a/drivers/gpu/drm/bridge/tc358764.c +++ b/drivers/gpu/drm/bridge/tc358764.c @@ -379,7 +379,7 @@ static void tc358764_detach(struct drm_bridge *bridge)  	drm_fb_helper_remove_one_connector(drm->fb_helper, &ctx->connector);  	drm_panel_detach(ctx->panel);  	ctx->panel = NULL; -	drm_connector_unreference(&ctx->connector); +	drm_connector_put(&ctx->connector);  }  static const struct drm_bridge_funcs tc358764_bridge_funcs = { diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index fa95f9974f6d..bc9fc9665614 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1460,6 +1460,9 @@ void drm_atomic_helper_wait_for_flip_done(struct drm_device *dev,  			DRM_ERROR("[CRTC:%d:%s] flip_done timed out\n",  				  crtc->base.id, crtc->name);  	} + +	if (old_state->fake_commit) +		complete_all(&old_state->fake_commit->flip_done);  }  EXPORT_SYMBOL(drm_atomic_helper_wait_for_flip_done); @@ -2217,8 +2220,10 @@ void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *old_state)  		spin_unlock(&crtc->commit_lock);  	} -	if (old_state->fake_commit) +	if (old_state->fake_commit) {  		complete_all(&old_state->fake_commit->cleanup_done); +		WARN_ON(!try_wait_for_completion(&old_state->fake_commit->hw_done)); +	}  }  EXPORT_SYMBOL(drm_atomic_helper_commit_cleanup_done); diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 373bd4c2b698..f8468eae0503 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -32,6 +32,8 @@  #include <drm/drm_debugfs.h>  #include <drm/drm_edid.h>  #include <drm/drm_atomic.h> +#include <drm/drm_auth.h> +#include <drm/drm_gem.h>  #include <drm/drmP.h>  #include "drm_internal.h" @@ -43,6 +45,93 @@   * Initialization, etc.   **************************************************/ +static int drm_name_info(struct seq_file *m, void *data) +{ +	struct drm_info_node *node = (struct drm_info_node *) m->private; +	struct drm_minor *minor = node->minor; +	struct drm_device *dev = minor->dev; +	struct drm_master *master; + +	mutex_lock(&dev->master_mutex); +	master = dev->master; +	seq_printf(m, "%s", dev->driver->name); +	if (dev->dev) +		seq_printf(m, " dev=%s", dev_name(dev->dev)); +	if (master && master->unique) +		seq_printf(m, " master=%s", master->unique); +	if (dev->unique) +		seq_printf(m, " unique=%s", dev->unique); +	seq_printf(m, "\n"); +	mutex_unlock(&dev->master_mutex); + +	return 0; +} + +static int drm_clients_info(struct seq_file *m, void *data) +{ +	struct drm_info_node *node = (struct drm_info_node *) m->private; +	struct drm_device *dev = node->minor->dev; +	struct drm_file *priv; +	kuid_t uid; + +	seq_printf(m, +		   "%20s %5s %3s master a %5s %10s\n", +		   "command", +		   "pid", +		   "dev", +		   "uid", +		   "magic"); + +	/* dev->filelist is sorted youngest first, but we want to present +	 * oldest first (i.e. kernel, servers, clients), so walk backwardss. +	 */ +	mutex_lock(&dev->filelist_mutex); +	list_for_each_entry_reverse(priv, &dev->filelist, lhead) { +		struct task_struct *task; + +		rcu_read_lock(); /* locks pid_task()->comm */ +		task = pid_task(priv->pid, PIDTYPE_PID); +		uid = task ? __task_cred(task)->euid : GLOBAL_ROOT_UID; +		seq_printf(m, "%20s %5d %3d   %c    %c %5d %10u\n", +			   task ? task->comm : "<unknown>", +			   pid_vnr(priv->pid), +			   priv->minor->index, +			   drm_is_current_master(priv) ? 'y' : 'n', +			   priv->authenticated ? 'y' : 'n', +			   from_kuid_munged(seq_user_ns(m), uid), +			   priv->magic); +		rcu_read_unlock(); +	} +	mutex_unlock(&dev->filelist_mutex); +	return 0; +} + +static int drm_gem_one_name_info(int id, void *ptr, void *data) +{ +	struct drm_gem_object *obj = ptr; +	struct seq_file *m = data; + +	seq_printf(m, "%6d %8zd %7d %8d\n", +		   obj->name, obj->size, +		   obj->handle_count, +		   kref_read(&obj->refcount)); +	return 0; +} + +static int drm_gem_name_info(struct seq_file *m, void *data) +{ +	struct drm_info_node *node = (struct drm_info_node *) m->private; +	struct drm_device *dev = node->minor->dev; + +	seq_printf(m, "  name     size handles refcount\n"); + +	mutex_lock(&dev->object_name_lock); +	idr_for_each(&dev->object_name_idr, drm_gem_one_name_info, m); +	mutex_unlock(&dev->object_name_lock); + +	return 0; +} +  static const struct drm_info_list drm_debugfs_list[] = {  	{"name", drm_name_info, 0},  	{"clients", drm_clients_info, 0}, diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index e2ffecd5e453..12e5e2be7890 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -704,19 +704,6 @@ void drm_dev_put(struct drm_device *dev)  }  EXPORT_SYMBOL(drm_dev_put); -/** - * drm_dev_unref - Drop reference of a DRM device - * @dev: device to drop reference of or NULL - * - * This is a compatibility alias for drm_dev_put() and should not be used by new - * code. - */ -void drm_dev_unref(struct drm_device *dev) -{ -	drm_dev_put(dev); -} -EXPORT_SYMBOL(drm_dev_unref); -  static int create_compat_control_link(struct drm_device *dev)  {  	struct drm_minor *minor; diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c deleted file mode 100644 index 6b68e9088436..000000000000 --- a/drivers/gpu/drm/drm_info.c +++ /dev/null @@ -1,137 +0,0 @@ -/** - * \file drm_info.c - * DRM info file implementations - * - * \author Ben Gamari <bgamari@gmail.com> - */ - -/* - * Created: Sun Dec 21 13:09:50 2008 by bgamari@gmail.com - * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * Copyright 2008 Ben Gamari <bgamari@gmail.com> - * All Rights Reserved. - * - * 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 (including the next - * paragraph) 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 - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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. - */ - -#include <linux/seq_file.h> -#include <drm/drmP.h> -#include <drm/drm_gem.h> - -#include "drm_internal.h" -#include "drm_legacy.h" - -/** - * Called when "/proc/dri/.../name" is read. - * - * Prints the device name together with the bus id if available. - */ -int drm_name_info(struct seq_file *m, void *data) -{ -	struct drm_info_node *node = (struct drm_info_node *) m->private; -	struct drm_minor *minor = node->minor; -	struct drm_device *dev = minor->dev; -	struct drm_master *master; - -	mutex_lock(&dev->master_mutex); -	master = dev->master; -	seq_printf(m, "%s", dev->driver->name); -	if (dev->dev) -		seq_printf(m, " dev=%s", dev_name(dev->dev)); -	if (master && master->unique) -		seq_printf(m, " master=%s", master->unique); -	if (dev->unique) -		seq_printf(m, " unique=%s", dev->unique); -	seq_printf(m, "\n"); -	mutex_unlock(&dev->master_mutex); - -	return 0; -} - -/** - * Called when "/proc/dri/.../clients" is read. - * - */ -int drm_clients_info(struct seq_file *m, void *data) -{ -	struct drm_info_node *node = (struct drm_info_node *) m->private; -	struct drm_device *dev = node->minor->dev; -	struct drm_file *priv; -	kuid_t uid; - -	seq_printf(m, -		   "%20s %5s %3s master a %5s %10s\n", -		   "command", -		   "pid", -		   "dev", -		   "uid", -		   "magic"); - -	/* dev->filelist is sorted youngest first, but we want to present -	 * oldest first (i.e. kernel, servers, clients), so walk backwardss. -	 */ -	mutex_lock(&dev->filelist_mutex); -	list_for_each_entry_reverse(priv, &dev->filelist, lhead) { -		struct task_struct *task; - -		rcu_read_lock(); /* locks pid_task()->comm */ -		task = pid_task(priv->pid, PIDTYPE_PID); -		uid = task ? __task_cred(task)->euid : GLOBAL_ROOT_UID; -		seq_printf(m, "%20s %5d %3d   %c    %c %5d %10u\n", -			   task ? task->comm : "<unknown>", -			   pid_vnr(priv->pid), -			   priv->minor->index, -			   drm_is_current_master(priv) ? 'y' : 'n', -			   priv->authenticated ? 'y' : 'n', -			   from_kuid_munged(seq_user_ns(m), uid), -			   priv->magic); -		rcu_read_unlock(); -	} -	mutex_unlock(&dev->filelist_mutex); -	return 0; -} - -static int drm_gem_one_name_info(int id, void *ptr, void *data) -{ -	struct drm_gem_object *obj = ptr; -	struct seq_file *m = data; - -	seq_printf(m, "%6d %8zd %7d %8d\n", -		   obj->name, obj->size, -		   obj->handle_count, -		   kref_read(&obj->refcount)); -	return 0; -} - -int drm_gem_name_info(struct seq_file *m, void *data) -{ -	struct drm_info_node *node = (struct drm_info_node *) m->private; -	struct drm_device *dev = node->minor->dev; - -	seq_printf(m, "  name     size handles refcount\n"); - -	mutex_lock(&dev->object_name_lock); -	idr_for_each(&dev->object_name_idr, drm_gem_one_name_info, m); -	mutex_unlock(&dev->object_name_lock); - -	return 0; -} diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 0c4eb4a9ab31..c7a7d7ce5d1c 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -56,11 +56,6 @@ void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpr  struct drm_minor *drm_minor_acquire(unsigned int minor_id);  void drm_minor_release(struct drm_minor *minor); -/* drm_info.c */ -int drm_name_info(struct seq_file *m, void *data); -int drm_clients_info(struct seq_file *m, void* data); -int drm_gem_name_info(struct seq_file *m, void *data); -  /* drm_vblank.c */  void drm_vblank_disable_and_save(struct drm_device *dev, unsigned int pipe);  void drm_vblank_cleanup(struct drm_device *dev); diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 5737cb8c6f03..231e3f6d5f41 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -663,24 +663,33 @@ EXPORT_SYMBOL(drm_gem_prime_handle_to_fd);   */  int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)  { -	/* Used by drm_gem_mmap() to lookup the GEM object */ -	struct drm_file priv = { -		.minor = obj->dev->primary, -	}; -	struct file fil = { -		.private_data = &priv, -	}; +	struct drm_file *priv; +	struct file *fil;  	int ret; -	ret = drm_vma_node_allow(&obj->vma_node, &priv); +	priv = kzalloc(sizeof(*priv), GFP_KERNEL); +	fil = kzalloc(sizeof(*fil), GFP_KERNEL); +	if (!priv || !fil) { +		ret = -ENOMEM; +		goto out; +	} + +	/* Used by drm_gem_mmap() to lookup the GEM object */ +	priv->minor = obj->dev->primary; +	fil->private_data = priv; + +	ret = drm_vma_node_allow(&obj->vma_node, priv);  	if (ret) -		return ret; +		goto out;  	vma->vm_pgoff += drm_vma_node_start(&obj->vma_node); -	ret = obj->dev->driver->fops->mmap(&fil, vma); +	ret = obj->dev->driver->fops->mmap(fil, vma); -	drm_vma_node_revoke(&obj->vma_node, &priv); +	drm_vma_node_revoke(&obj->vma_node, priv); +out: +	kfree(priv); +	kfree(fil);  	return ret;  } diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index 83c1f46670bf..52802e6049e0 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -550,7 +550,7 @@ out_register:  out_bind:  	kfree(priv);  out_unref: -	drm_dev_unref(drm); +	drm_dev_put(drm);  	return ret;  } @@ -567,7 +567,7 @@ static void etnaviv_unbind(struct device *dev)  	drm->dev_private = NULL;  	kfree(priv); -	drm_dev_unref(drm); +	drm_dev_put(drm);  }  static const struct component_master_ops etnaviv_master_ops = { diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c index df7247cd93f9..d8c5cc34e22e 100644 --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c @@ -594,17 +594,7 @@ dw_hdmi_mode_valid(struct drm_connector *connector,  	dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__,  		vclk_freq, venc_freq, hdmi_freq); -	/* Finally filter by configurable vclk frequencies for VIC modes */ -	switch (vclk_freq) { -	case 54000: -	case 74250: -	case 148500: -	case 297000: -	case 594000: -		return MODE_OK; -	} - -	return MODE_CLOCK_RANGE; +	return meson_vclk_vic_supported_freq(vclk_freq);  }  /* Encoder */ diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c index 9aebc5e4b418..691a9fd16b36 100644 --- a/drivers/gpu/drm/meson/meson_overlay.c +++ b/drivers/gpu/drm/meson/meson_overlay.c @@ -16,6 +16,7 @@  #include <drm/drm_plane_helper.h>  #include <drm/drm_gem_cma_helper.h>  #include <drm/drm_fb_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h>  #include <drm/drm_rect.h>  #include "meson_overlay.h" @@ -532,6 +533,7 @@ static const struct drm_plane_helper_funcs meson_overlay_helper_funcs = {  	.atomic_check	= meson_overlay_atomic_check,  	.atomic_disable	= meson_overlay_atomic_disable,  	.atomic_update	= meson_overlay_atomic_update, +	.prepare_fb	= drm_gem_fb_prepare_fb,  };  static const struct drm_plane_funcs meson_overlay_funcs = { diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index 12a47b4f65a5..8ee2cf9e47cd 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c @@ -32,6 +32,7 @@  #include <drm/drm_plane_helper.h>  #include <drm/drm_gem_cma_helper.h>  #include <drm/drm_fb_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h>  #include <drm/drm_rect.h>  #include "meson_plane.h" @@ -322,6 +323,7 @@ static const struct drm_plane_helper_funcs meson_plane_helper_funcs = {  	.atomic_check	= meson_plane_atomic_check,  	.atomic_disable	= meson_plane_atomic_disable,  	.atomic_update	= meson_plane_atomic_update, +	.prepare_fb	= drm_gem_fb_prepare_fb,  };  static const struct drm_plane_funcs meson_plane_funcs = { diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c index ae5473257f72..f6ba35a405f8 100644 --- a/drivers/gpu/drm/meson/meson_vclk.c +++ b/drivers/gpu/drm/meson/meson_vclk.c @@ -117,6 +117,8 @@  #define HDMI_PLL_RESET		BIT(28)  #define HDMI_PLL_LOCK		BIT(31) +#define FREQ_1000_1001(_freq)	DIV_ROUND_CLOSEST(_freq * 1000, 1001) +  /* VID PLL Dividers */  enum {  	VID_PLL_DIV_1 = 0, @@ -323,7 +325,7 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)  enum {  /* PLL	O1 O2 O3 VP DV     EN TX */  /* 4320 /4 /4 /1 /5 /1  => /2 /2 */ -	MESON_VCLK_HDMI_ENCI_54000 = 1, +	MESON_VCLK_HDMI_ENCI_54000 = 0,  /* 4320 /4 /4 /1 /5 /1  => /1 /2 */  	MESON_VCLK_HDMI_DDR_54000,  /* 2970 /4 /1 /1 /5 /1  => /1 /2 */ @@ -339,6 +341,7 @@ enum {  };  struct meson_vclk_params { +	unsigned int pixel_freq;  	unsigned int pll_base_freq;  	unsigned int pll_od1;  	unsigned int pll_od2; @@ -347,6 +350,7 @@ struct meson_vclk_params {  	unsigned int vclk_div;  } params[] = {  	[MESON_VCLK_HDMI_ENCI_54000] = { +		.pixel_freq = 54000,  		.pll_base_freq = 4320000,  		.pll_od1 = 4,  		.pll_od2 = 4, @@ -355,6 +359,7 @@ struct meson_vclk_params {  		.vclk_div = 1,  	},  	[MESON_VCLK_HDMI_DDR_54000] = { +		.pixel_freq = 54000,  		.pll_base_freq = 4320000,  		.pll_od1 = 4,  		.pll_od2 = 4, @@ -363,6 +368,7 @@ struct meson_vclk_params {  		.vclk_div = 1,  	},  	[MESON_VCLK_HDMI_DDR_148500] = { +		.pixel_freq = 148500,  		.pll_base_freq = 2970000,  		.pll_od1 = 4,  		.pll_od2 = 1, @@ -371,6 +377,7 @@ struct meson_vclk_params {  		.vclk_div = 1,  	},  	[MESON_VCLK_HDMI_74250] = { +		.pixel_freq = 74250,  		.pll_base_freq = 2970000,  		.pll_od1 = 2,  		.pll_od2 = 2, @@ -379,6 +386,7 @@ struct meson_vclk_params {  		.vclk_div = 1,  	},  	[MESON_VCLK_HDMI_148500] = { +		.pixel_freq = 148500,  		.pll_base_freq = 2970000,  		.pll_od1 = 1,  		.pll_od2 = 2, @@ -387,6 +395,7 @@ struct meson_vclk_params {  		.vclk_div = 1,  	},  	[MESON_VCLK_HDMI_297000] = { +		.pixel_freq = 297000,  		.pll_base_freq = 2970000,  		.pll_od1 = 1,  		.pll_od2 = 1, @@ -395,6 +404,7 @@ struct meson_vclk_params {  		.vclk_div = 2,  	},  	[MESON_VCLK_HDMI_594000] = { +		.pixel_freq = 594000,  		.pll_base_freq = 5940000,  		.pll_od1 = 1,  		.pll_od2 = 1, @@ -402,6 +412,7 @@ struct meson_vclk_params {  		.vid_pll_div = VID_PLL_DIV_5,  		.vclk_div = 1,  	}, +	{ /* sentinel */ },  };  static inline unsigned int pll_od_to_reg(unsigned int od) @@ -626,12 +637,37 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv,  		  pll_freq);  } +enum drm_mode_status +meson_vclk_vic_supported_freq(unsigned int freq) +{ +	int i; + +	DRM_DEBUG_DRIVER("freq = %d\n", freq); + +	for (i = 0 ; params[i].pixel_freq ; ++i) { +		DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n", +				 i, params[i].pixel_freq, +				 FREQ_1000_1001(params[i].pixel_freq)); +		/* Match strict frequency */ +		if (freq == params[i].pixel_freq) +			return MODE_OK; +		/* Match 1000/1001 variant */ +		if (freq == FREQ_1000_1001(params[i].pixel_freq)) +			return MODE_OK; +	} + +	return MODE_CLOCK_RANGE; +} +EXPORT_SYMBOL_GPL(meson_vclk_vic_supported_freq); +  static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,  			   unsigned int od1, unsigned int od2, unsigned int od3,  			   unsigned int vid_pll_div, unsigned int vclk_div,  			   unsigned int hdmi_tx_div, unsigned int venc_div, -			   bool hdmi_use_enci) +			   bool hdmi_use_enci, bool vic_alternate_clock)  { +	unsigned int m = 0, frac = 0; +  	/* Set HDMI-TX sys clock */  	regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,  			   CTS_HDMI_SYS_SEL_MASK, 0); @@ -646,34 +682,38 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,  	} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {  		switch (pll_base_freq) {  		case 2970000: -			meson_hdmi_pll_set_params(priv, 0x3d, 0xe00, -						  od1, od2, od3); +			m = 0x3d; +			frac = vic_alternate_clock ? 0xd02 : 0xe00;  			break;  		case 4320000: -			meson_hdmi_pll_set_params(priv, 0x5a, 0, -						  od1, od2, od3); +			m = vic_alternate_clock ? 0x59 : 0x5a; +			frac = vic_alternate_clock ? 0xe8f : 0;  			break;  		case 5940000: -			meson_hdmi_pll_set_params(priv, 0x7b, 0xc00, -						  od1, od2, od3); +			m = 0x7b; +			frac = vic_alternate_clock ? 0xa05 : 0xc00;  			break;  		} + +		meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);  	} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||  		   meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {  		switch (pll_base_freq) {  		case 2970000: -			meson_hdmi_pll_set_params(priv, 0x7b, 0x300, -						  od1, od2, od3); +			m = 0x7b; +			frac = vic_alternate_clock ? 0x281 : 0x300;  			break;  		case 4320000: -			meson_hdmi_pll_set_params(priv, 0xb4, 0, -						  od1, od2, od3); +			m = vic_alternate_clock ? 0xb3 : 0xb4; +			frac = vic_alternate_clock ? 0x347 : 0;  			break;  		case 5940000: -			meson_hdmi_pll_set_params(priv, 0xf7, 0x200, -						  od1, od2, od3); +			m = 0xf7; +			frac = vic_alternate_clock ? 0x102 : 0x200;  			break;  		} + +		meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);  	}  	/* Setup vid_pll divider */ @@ -826,6 +866,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,  		      unsigned int vclk_freq, unsigned int venc_freq,  		      unsigned int dac_freq, bool hdmi_use_enci)  { +	bool vic_alternate_clock = false;  	unsigned int freq;  	unsigned int hdmi_tx_div;  	unsigned int venc_div; @@ -843,7 +884,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,  		 * - encp encoder  		 */  		meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0, -			       VID_PLL_DIV_5, 2, 1, 1, false); +			       VID_PLL_DIV_5, 2, 1, 1, false, false);  		return;  	} @@ -863,31 +904,35 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,  		return;  	} -	switch (vclk_freq) { -	case 54000: -		if (hdmi_use_enci) -			freq = MESON_VCLK_HDMI_ENCI_54000; -		else -			freq = MESON_VCLK_HDMI_DDR_54000; -		break; -	case 74250: -		freq = MESON_VCLK_HDMI_74250; -		break; -	case 148500: -		if (dac_freq != 148500) -			freq = MESON_VCLK_HDMI_DDR_148500; -		else -			freq = MESON_VCLK_HDMI_148500; -		break; -	case 297000: -		freq = MESON_VCLK_HDMI_297000; -		break; -	case 594000: -		freq = MESON_VCLK_HDMI_594000; -		break; -	default: -		pr_err("Fatal Error, invalid HDMI vclk freq %d\n", -		       vclk_freq); +	for (freq = 0 ; params[freq].pixel_freq ; ++freq) { +		if (vclk_freq == params[freq].pixel_freq || +		    vclk_freq == FREQ_1000_1001(params[freq].pixel_freq)) { +			if (vclk_freq != params[freq].pixel_freq) +				vic_alternate_clock = true; +			else +				vic_alternate_clock = false; + +			if (freq == MESON_VCLK_HDMI_ENCI_54000 && +			    !hdmi_use_enci) +				continue; + +			if (freq == MESON_VCLK_HDMI_DDR_54000 && +			    hdmi_use_enci) +				continue; + +			if (freq == MESON_VCLK_HDMI_DDR_148500 && +			    dac_freq == vclk_freq) +				continue; + +			if (freq == MESON_VCLK_HDMI_148500 && +			    dac_freq != vclk_freq) +				continue; +			break; +		} +	} + +	if (!params[freq].pixel_freq) { +		pr_err("Fatal Error, invalid HDMI vclk freq %d\n", vclk_freq);  		return;  	} @@ -895,6 +940,6 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,  		       params[freq].pll_od1, params[freq].pll_od2,  		       params[freq].pll_od3, params[freq].vid_pll_div,  		       params[freq].vclk_div, hdmi_tx_div, venc_div, -		       hdmi_use_enci); +		       hdmi_use_enci, vic_alternate_clock);  }  EXPORT_SYMBOL_GPL(meson_vclk_setup); diff --git a/drivers/gpu/drm/meson/meson_vclk.h b/drivers/gpu/drm/meson/meson_vclk.h index 869fa3a3073e..4bd8752da02a 100644 --- a/drivers/gpu/drm/meson/meson_vclk.h +++ b/drivers/gpu/drm/meson/meson_vclk.h @@ -32,6 +32,8 @@ enum {  enum drm_mode_status  meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq); +enum drm_mode_status +meson_vclk_vic_supported_freq(unsigned int freq);  void meson_vclk_setup(struct meson_drm *priv, unsigned int target,  		      unsigned int vclk_freq, unsigned int venc_freq, diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c index acbbad3e322c..e95e0e7a7fa1 100644 --- a/drivers/gpu/drm/meson/meson_venc.c +++ b/drivers/gpu/drm/meson/meson_venc.c @@ -697,6 +697,132 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = {  	},  }; +union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p24 = { +	.encp = { +		.dvi_settings = 0x1, +		.video_mode = 0x4040, +		.video_mode_adv = 0x8, +		/* video_sync_mode */ +		/* video_yc_dly */ +		/* video_rgb_ctrl */ +		.video_filt_ctrl = 0x1000, +		.video_filt_ctrl_present = true, +		/* video_ofld_voav_ofst */ +		.yfp1_htime = 140, +		.yfp2_htime = 140+3840, +		.max_pxcnt = 3840+1660-1, +		.hspuls_begin = 2156+1920, +		.hspuls_end = 44, +		.hspuls_switch = 44, +		.vspuls_begin = 140, +		.vspuls_end = 2059+1920, +		.vspuls_bline = 0, +		.vspuls_eline = 4, +		.havon_begin = 148, +		.havon_end = 3987, +		.vavon_bline = 89, +		.vavon_eline = 2248, +		/* eqpuls_begin */ +		/* eqpuls_end */ +		/* eqpuls_bline */ +		/* eqpuls_eline */ +		.hso_begin = 44, +		.hso_end = 2156+1920, +		.vso_begin = 2100+1920, +		.vso_end = 2164+1920, +		.vso_bline = 51, +		.vso_eline = 53, +		.vso_eline_present = true, +		/* sy_val */ +		/* sy2_val */ +		.max_lncnt = 2249, +	}, +}; + +union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p25 = { +	.encp = { +		.dvi_settings = 0x1, +		.video_mode = 0x4040, +		.video_mode_adv = 0x8, +		/* video_sync_mode */ +		/* video_yc_dly */ +		/* video_rgb_ctrl */ +		.video_filt_ctrl = 0x1000, +		.video_filt_ctrl_present = true, +		/* video_ofld_voav_ofst */ +		.yfp1_htime = 140, +		.yfp2_htime = 140+3840, +		.max_pxcnt = 3840+1440-1, +		.hspuls_begin = 2156+1920, +		.hspuls_end = 44, +		.hspuls_switch = 44, +		.vspuls_begin = 140, +		.vspuls_end = 2059+1920, +		.vspuls_bline = 0, +		.vspuls_eline = 4, +		.havon_begin = 148, +		.havon_end = 3987, +		.vavon_bline = 89, +		.vavon_eline = 2248, +		/* eqpuls_begin */ +		/* eqpuls_end */ +		/* eqpuls_bline */ +		/* eqpuls_eline */ +		.hso_begin = 44, +		.hso_end = 2156+1920, +		.vso_begin = 2100+1920, +		.vso_end = 2164+1920, +		.vso_bline = 51, +		.vso_eline = 53, +		.vso_eline_present = true, +		/* sy_val */ +		/* sy2_val */ +		.max_lncnt = 2249, +	}, +}; + +union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p30 = { +	.encp = { +		.dvi_settings = 0x1, +		.video_mode = 0x4040, +		.video_mode_adv = 0x8, +		/* video_sync_mode */ +		/* video_yc_dly */ +		/* video_rgb_ctrl */ +		.video_filt_ctrl = 0x1000, +		.video_filt_ctrl_present = true, +		/* video_ofld_voav_ofst */ +		.yfp1_htime = 140, +		.yfp2_htime = 140+3840, +		.max_pxcnt = 3840+560-1, +		.hspuls_begin = 2156+1920, +		.hspuls_end = 44, +		.hspuls_switch = 44, +		.vspuls_begin = 140, +		.vspuls_end = 2059+1920, +		.vspuls_bline = 0, +		.vspuls_eline = 4, +		.havon_begin = 148, +		.havon_end = 3987, +		.vavon_bline = 89, +		.vavon_eline = 2248, +		/* eqpuls_begin */ +		/* eqpuls_end */ +		/* eqpuls_bline */ +		/* eqpuls_eline */ +		.hso_begin = 44, +		.hso_end = 2156+1920, +		.vso_begin = 2100+1920, +		.vso_end = 2164+1920, +		.vso_bline = 51, +		.vso_eline = 53, +		.vso_eline_present = true, +		/* sy_val */ +		/* sy2_val */ +		.max_lncnt = 2249, +	}, +}; +  struct meson_hdmi_venc_vic_mode {  	unsigned int vic;  	union meson_hdmi_venc_mode *mode; @@ -717,6 +843,9 @@ struct meson_hdmi_venc_vic_mode {  	{ 34, &meson_hdmi_encp_mode_1080p30 },  	{ 31, &meson_hdmi_encp_mode_1080p50 },  	{ 16, &meson_hdmi_encp_mode_1080p60 }, +	{ 93, &meson_hdmi_encp_mode_2160p24 }, +	{ 94, &meson_hdmi_encp_mode_2160p25 }, +	{ 95, &meson_hdmi_encp_mode_2160p30 },  	{ 0, NULL}, /* sentinel */  }; diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c index 2393e6d16ffd..88ba003979e6 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c @@ -417,7 +417,7 @@ static int mxsfb_probe(struct platform_device *pdev)  err_unload:  	mxsfb_unload(drm);  err_free: -	drm_dev_unref(drm); +	drm_dev_put(drm);  	return ret;  } @@ -428,7 +428,7 @@ static int mxsfb_remove(struct platform_device *pdev)  	drm_dev_unregister(drm);  	mxsfb_unload(drm); -	drm_dev_unref(drm); +	drm_dev_put(drm);  	return 0;  } diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index bf49c55b0f2c..9e9255ee59cd 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -48,8 +48,12 @@ static const u32 sunxi_rgb2yuv_coef[12] = {  /*   * These coefficients are taken from the A33 BSP from Allwinner.   * - * The formula is for each component, each coefficient being multiplied by - * 1024 and each constant being multiplied by 16: + * The first three values of each row are coded as 13-bit signed fixed-point + * numbers, with 10 bits for the fractional part. The fourth value is a + * constant coded as a 14-bit signed fixed-point number with 4 bits for the + * fractional part. + * + * The values in table order give the following colorspace translation:   * G = 1.164 * Y - 0.391 * U - 0.813 * V + 135   * R = 1.164 * Y + 1.596 * V - 222   * B = 1.164 * Y + 2.018 * U + 276 @@ -155,6 +159,36 @@ static int sun4i_backend_drm_format_to_layer(u32 format, u32 *mode)  	return 0;  } +static const uint32_t sun4i_backend_formats[] = { +	DRM_FORMAT_ARGB1555, +	DRM_FORMAT_ARGB4444, +	DRM_FORMAT_ARGB8888, +	DRM_FORMAT_BGRX8888, +	DRM_FORMAT_RGB565, +	DRM_FORMAT_RGB888, +	DRM_FORMAT_RGBA4444, +	DRM_FORMAT_RGBA5551, +	DRM_FORMAT_UYVY, +	DRM_FORMAT_VYUY, +	DRM_FORMAT_XRGB8888, +	DRM_FORMAT_YUYV, +	DRM_FORMAT_YVYU, +}; + +bool sun4i_backend_format_is_supported(uint32_t fmt, uint64_t modifier) +{ +	unsigned int i; + +	if (modifier != DRM_FORMAT_MOD_LINEAR) +		return false; + +	for (i = 0; i < ARRAY_SIZE(sun4i_backend_formats); i++) +		if (sun4i_backend_formats[i] == fmt) +			return true; + +	return false; +} +  int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,  				     int layer, struct drm_plane *plane)  { @@ -395,6 +429,15 @@ int sun4i_backend_update_layer_zpos(struct sun4i_backend *backend, int layer,  	return 0;  } +void sun4i_backend_cleanup_layer(struct sun4i_backend *backend, +				 int layer) +{ +	regmap_update_bits(backend->engine.regs, +			   SUN4I_BACKEND_ATTCTL_REG0(layer), +			   SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN | +			   SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN, 0); +} +  static bool sun4i_backend_plane_uses_scaler(struct drm_plane_state *state)  {  	u16 src_h = state->src_h >> 16; @@ -413,11 +456,50 @@ static bool sun4i_backend_plane_uses_frontend(struct drm_plane_state *state)  {  	struct sun4i_layer *layer = plane_to_sun4i_layer(state->plane);  	struct sun4i_backend *backend = layer->backend; +	uint32_t format = state->fb->format->format; +	uint64_t modifier = state->fb->modifier;  	if (IS_ERR(backend->frontend))  		return false; -	return sun4i_backend_plane_uses_scaler(state); +	if (!sun4i_frontend_format_is_supported(format, modifier)) +		return false; + +	if (!sun4i_backend_format_is_supported(format, modifier)) +		return true; + +	/* +	 * TODO: The backend alone allows 2x and 4x integer scaling, including +	 * support for an alpha component (which the frontend doesn't support). +	 * Use the backend directly instead of the frontend in this case, with +	 * another test to return false. +	 */ + +	if (sun4i_backend_plane_uses_scaler(state)) +		return true; + +	/* +	 * Here the format is supported by both the frontend and the backend +	 * and no frontend scaling is required, so use the backend directly. +	 */ +	return false; +} + +static bool sun4i_backend_plane_is_supported(struct drm_plane_state *state, +					     bool *uses_frontend) +{ +	if (sun4i_backend_plane_uses_frontend(state)) { +		*uses_frontend = true; +		return true; +	} + +	*uses_frontend = false; + +	/* Scaling is not supported without the frontend. */ +	if (sun4i_backend_plane_uses_scaler(state)) +		return false; + +	return true;  }  static void sun4i_backend_atomic_begin(struct sunxi_engine *engine, @@ -460,14 +542,19 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,  		struct drm_framebuffer *fb = plane_state->fb;  		struct drm_format_name_buf format_name; -		if (sun4i_backend_plane_uses_frontend(plane_state)) { +		if (!sun4i_backend_plane_is_supported(plane_state, +						      &layer_state->uses_frontend)) +			return -EINVAL; + +		if (layer_state->uses_frontend) {  			DRM_DEBUG_DRIVER("Using the frontend for plane %d\n",  					 plane->index); - -			layer_state->uses_frontend = true;  			num_frontend_planes++;  		} else { -			layer_state->uses_frontend = false; +			if (fb->format->is_yuv) { +				DRM_DEBUG_DRIVER("Plane FB format is YUV\n"); +				num_yuv_planes++; +			}  		}  		DRM_DEBUG_DRIVER("Plane FB format is %s\n", @@ -476,11 +563,6 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,  		if (fb->format->has_alpha || (plane_state->alpha != DRM_BLEND_ALPHA_OPAQUE))  			num_alpha_planes++; -		if (fb->format->is_yuv) { -			DRM_DEBUG_DRIVER("Plane FB format is YUV\n"); -			num_yuv_planes++; -		} -  		DRM_DEBUG_DRIVER("Plane zpos is %d\n",  				 plane_state->normalized_zpos); diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h index e3d4c6035eb2..01f66463271b 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.h +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h @@ -198,6 +198,7 @@ engine_to_sun4i_backend(struct sunxi_engine *engine)  void sun4i_backend_layer_enable(struct sun4i_backend *backend,  				int layer, bool enable); +bool sun4i_backend_format_is_supported(uint32_t fmt, uint64_t modifier);  int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,  				     int layer, struct drm_plane *plane);  int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, @@ -208,5 +209,7 @@ int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,  					int layer, uint32_t in_fmt);  int sun4i_backend_update_layer_zpos(struct sun4i_backend *backend,  				    int layer, struct drm_plane *plane); +void sun4i_backend_cleanup_layer(struct sun4i_backend *backend, +				 int layer);  #endif /* _SUN4I_BACKEND_H_ */ diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index ef773d36baf0..ccdeae6299eb 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -28,6 +28,16 @@  #include "sun4i_tcon.h"  #include "sun8i_tcon_top.h" +static int drm_sun4i_gem_dumb_create(struct drm_file *file_priv, +				     struct drm_device *drm, +				     struct drm_mode_create_dumb *args) +{ +	/* The hardware only allows even pitches for YUV buffers. */ +	args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8), 2); + +	return drm_gem_cma_dumb_create_internal(file_priv, drm, args); +} +  DEFINE_DRM_GEM_CMA_FOPS(sun4i_drv_fops);  static struct drm_driver sun4i_drv_driver = { @@ -42,7 +52,7 @@ static struct drm_driver sun4i_drv_driver = {  	.minor			= 0,  	/* GEM Operations */ -	.dumb_create		= drm_gem_cma_dumb_create, +	.dumb_create		= drm_sun4i_gem_dumb_create,  	.gem_free_object_unlocked = drm_gem_cma_free_object,  	.gem_vm_ops		= &drm_gem_cma_vm_ops, diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c index ddf6cfa6dd23..1a7ebc45747e 100644 --- a/drivers/gpu/drm/sun4i/sun4i_frontend.c +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c @@ -107,8 +107,34 @@ EXPORT_SYMBOL(sun4i_frontend_update_buffer);  static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val)  {  	switch (fmt) { -	case DRM_FORMAT_ARGB8888: -		*val = 5; +	case DRM_FORMAT_XRGB8888: +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_RGB; +		return 0; + +	default: +		return -EINVAL; +	} +} + +static int sun4i_frontend_drm_format_to_input_mode(uint32_t fmt, u32 *val) +{ +	if (drm_format_num_planes(fmt) == 1) +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PACKED; +	else +		return -EINVAL; + +	return 0; +} + +static int sun4i_frontend_drm_format_to_input_sequence(uint32_t fmt, u32 *val) +{ +	switch (fmt) { +	case DRM_FORMAT_BGRX8888: +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_BGRX; +		return 0; + +	case DRM_FORMAT_XRGB8888: +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_XRGB;  		return 0;  	default: @@ -119,9 +145,12 @@ static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val)  static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val)  {  	switch (fmt) { +	case DRM_FORMAT_BGRX8888: +		*val = SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_BGRX8888; +		return 0; +  	case DRM_FORMAT_XRGB8888: -	case DRM_FORMAT_ARGB8888: -		*val = 2; +		*val = SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_XRGB8888;  		return 0;  	default: @@ -129,22 +158,54 @@ static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val)  	}  } +static const uint32_t sun4i_frontend_formats[] = { +	DRM_FORMAT_BGRX8888, +	DRM_FORMAT_XRGB8888, +}; + +bool sun4i_frontend_format_is_supported(uint32_t fmt, uint64_t modifier) +{ +	unsigned int i; + +	if (modifier != DRM_FORMAT_MOD_LINEAR) +		return false; + +	for (i = 0; i < ARRAY_SIZE(sun4i_frontend_formats); i++) +		if (sun4i_frontend_formats[i] == fmt) +			return true; + +	return false; +} +EXPORT_SYMBOL(sun4i_frontend_format_is_supported); +  int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,  				  struct drm_plane *plane, uint32_t out_fmt)  {  	struct drm_plane_state *state = plane->state;  	struct drm_framebuffer *fb = state->fb; +	uint32_t format = fb->format->format;  	u32 out_fmt_val; -	u32 in_fmt_val; +	u32 in_fmt_val, in_mod_val, in_ps_val;  	int ret; -	ret = sun4i_frontend_drm_format_to_input_fmt(fb->format->format, -						     &in_fmt_val); +	ret = sun4i_frontend_drm_format_to_input_fmt(format, &in_fmt_val);  	if (ret) {  		DRM_DEBUG_DRIVER("Invalid input format\n");  		return ret;  	} +	ret = sun4i_frontend_drm_format_to_input_mode(format, &in_mod_val); +	if (ret) { +		DRM_DEBUG_DRIVER("Invalid input mode\n"); +		return ret; +	} + +	ret = sun4i_frontend_drm_format_to_input_sequence(format, &in_ps_val); +	if (ret) { +		DRM_DEBUG_DRIVER("Invalid pixel sequence\n"); +		return ret; +	} +  	ret = sun4i_frontend_drm_format_to_output_fmt(out_fmt, &out_fmt_val);  	if (ret) {  		DRM_DEBUG_DRIVER("Invalid output format\n"); @@ -162,10 +223,12 @@ int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,  	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, 0x400);  	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, 0x400); +	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG, +			   SUN4I_FRONTEND_BYPASS_CSC_EN, +			   SUN4I_FRONTEND_BYPASS_CSC_EN); +  	regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG, -		     SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(1) | -		     SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(in_fmt_val) | -		     SUN4I_FRONTEND_INPUT_FMT_PS(1)); +		     in_mod_val | in_fmt_val | in_ps_val);  	/*  	 * TODO: It look like the A31 and A80 at least will need the @@ -173,7 +236,7 @@ int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,  	 * ARGB8888).  	 */  	regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG, -		     SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(out_fmt_val)); +		     out_fmt_val);  	return 0;  } @@ -183,16 +246,24 @@ void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,  				 struct drm_plane *plane)  {  	struct drm_plane_state *state = plane->state; +	struct drm_framebuffer *fb = state->fb; +	uint32_t luma_width, luma_height; +	uint32_t chroma_width, chroma_height;  	/* Set height and width */  	DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n",  			 state->crtc_w, state->crtc_h); + +	luma_width = state->src_w >> 16; +	luma_height = state->src_h >> 16; + +	chroma_width = DIV_ROUND_UP(luma_width, fb->format->hsub); +	chroma_height = DIV_ROUND_UP(luma_height, fb->format->vsub); +  	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG, -		     SUN4I_FRONTEND_INSIZE(state->src_h >> 16, -					   state->src_w >> 16)); +		     SUN4I_FRONTEND_INSIZE(luma_height, luma_width));  	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG, -		     SUN4I_FRONTEND_INSIZE(state->src_h >> 16, -					   state->src_w >> 16)); +		     SUN4I_FRONTEND_INSIZE(chroma_height, chroma_width));  	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG,  		     SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w)); @@ -200,14 +271,14 @@ void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,  		     SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));  	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG, -		     state->src_w / state->crtc_w); +		     (luma_width << 16) / state->crtc_w);  	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZFACT_REG, -		     state->src_w / state->crtc_w); +		     (chroma_width << 16) / state->crtc_w);  	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTFACT_REG, -		     state->src_h / state->crtc_h); +		     (luma_height << 16) / state->crtc_h);  	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTFACT_REG, -		     state->src_h / state->crtc_h); +		     (chroma_height << 16) / state->crtc_h);  	regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,  			  SUN4I_FRONTEND_FRM_CTRL_REG_RDY, @@ -339,10 +410,6 @@ static int sun4i_frontend_runtime_resume(struct device *dev)  			   SUN4I_FRONTEND_EN_EN,  			   SUN4I_FRONTEND_EN_EN); -	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG, -			   SUN4I_FRONTEND_BYPASS_CSC_EN, -			   SUN4I_FRONTEND_BYPASS_CSC_EN); -  	sun4i_frontend_scaler_init(frontend);  	return 0; diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.h b/drivers/gpu/drm/sun4i/sun4i_frontend.h index 02661ce81f3e..ad146e8d8d70 100644 --- a/drivers/gpu/drm/sun4i/sun4i_frontend.h +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h @@ -26,12 +26,14 @@  #define SUN4I_FRONTEND_LINESTRD0_REG		0x040  #define SUN4I_FRONTEND_INPUT_FMT_REG		0x04c -#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(mod)		((mod) << 8) -#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(fmt)		((fmt) << 4) -#define SUN4I_FRONTEND_INPUT_FMT_PS(ps)			(ps) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PACKED	(1 << 8) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_RGB		(5 << 4) +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_BGRX		0 +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_XRGB		1  #define SUN4I_FRONTEND_OUTPUT_FMT_REG		0x05c -#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(fmt)		(fmt) +#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_BGRX8888	1 +#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_XRGB8888	2  #define SUN4I_FRONTEND_CH0_INSIZE_REG		0x100  #define SUN4I_FRONTEND_INSIZE(h, w)			((((h) - 1) << 16) | (((w) - 1))) @@ -95,5 +97,6 @@ void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,  				 struct drm_plane *plane);  int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,  				  struct drm_plane *plane, uint32_t out_fmt); +bool sun4i_frontend_format_is_supported(uint32_t fmt, uint64_t modifier);  #endif /* _SUN4I_FRONTEND_H_ */ diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c index 78f77af8805a..29631e0efde3 100644 --- a/drivers/gpu/drm/sun4i/sun4i_layer.c +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c @@ -12,6 +12,7 @@  #include <drm/drm_atomic_helper.h>  #include <drm/drm_plane_helper.h> +#include <drm/drm_gem_framebuffer_helper.h>  #include <drm/drmP.h>  #include "sun4i_backend.h" @@ -92,14 +93,16 @@ static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,  	struct sun4i_backend *backend = layer->backend;  	struct sun4i_frontend *frontend = backend->frontend; +	sun4i_backend_cleanup_layer(backend, layer->id); +  	if (layer_state->uses_frontend) {  		sun4i_frontend_init(frontend);  		sun4i_frontend_update_coord(frontend, plane);  		sun4i_frontend_update_buffer(frontend, plane);  		sun4i_frontend_update_formats(frontend, plane, -					      DRM_FORMAT_ARGB8888); +					      DRM_FORMAT_XRGB8888);  		sun4i_backend_update_layer_frontend(backend, layer->id, -						    DRM_FORMAT_ARGB8888); +						    DRM_FORMAT_XRGB8888);  		sun4i_frontend_enable(frontend);  	} else {  		sun4i_backend_update_layer_formats(backend, layer->id, plane); @@ -112,6 +115,7 @@ static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,  }  static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = { +	.prepare_fb	= drm_gem_fb_prepare_fb,  	.atomic_disable	= sun4i_backend_layer_atomic_disable,  	.atomic_update	= sun4i_backend_layer_atomic_update,  }; @@ -125,10 +129,11 @@ static const struct drm_plane_funcs sun4i_backend_layer_funcs = {  	.update_plane		= drm_atomic_helper_update_plane,  }; -static const uint32_t sun4i_backend_layer_formats[] = { +static const uint32_t sun4i_layer_formats[] = {  	DRM_FORMAT_ARGB8888,  	DRM_FORMAT_ARGB4444,  	DRM_FORMAT_ARGB1555, +	DRM_FORMAT_BGRX8888,  	DRM_FORMAT_RGBA5551,  	DRM_FORMAT_RGBA4444,  	DRM_FORMAT_RGB888, @@ -154,8 +159,8 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,  	/* possible crtcs are set later */  	ret = drm_universal_plane_init(drm, &layer->plane, 0,  				       &sun4i_backend_layer_funcs, -				       sun4i_backend_layer_formats, -				       ARRAY_SIZE(sun4i_backend_layer_formats), +				       sun4i_layer_formats, +				       ARRAY_SIZE(sun4i_layer_formats),  				       NULL, type, NULL);  	if (ret) {  		dev_err(drm->dev, "Couldn't initialize layer\n"); diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c index e3fc8fa920fb..18534263a05d 100644 --- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c @@ -19,6 +19,7 @@  #include <drm/drm_crtc_helper.h>  #include <drm/drm_fb_cma_helper.h>  #include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h>  #include <drm/drm_plane_helper.h>  #include <drm/drmP.h> @@ -300,6 +301,7 @@ static void sun8i_ui_layer_atomic_update(struct drm_plane *plane,  }  static struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = { +	.prepare_fb	= drm_gem_fb_prepare_fb,  	.atomic_check	= sun8i_ui_layer_atomic_check,  	.atomic_disable	= sun8i_ui_layer_atomic_disable,  	.atomic_update	= sun8i_ui_layer_atomic_update, diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c index 4249edfb47ed..87be898f9b7a 100644 --- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c @@ -13,6 +13,7 @@  #include <drm/drm_crtc_helper.h>  #include <drm/drm_fb_cma_helper.h>  #include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h>  #include <drm/drm_plane_helper.h>  #include <drm/drmP.h> @@ -336,6 +337,7 @@ static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,  }  static struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = { +	.prepare_fb	= drm_gem_fb_prepare_fb,  	.atomic_check	= sun8i_vi_layer_atomic_check,  	.atomic_disable	= sun8i_vi_layer_atomic_disable,  	.atomic_update	= sun8i_vi_layer_atomic_update, diff --git a/drivers/gpu/drm/tve200/tve200_drv.c b/drivers/gpu/drm/tve200/tve200_drv.c index 72efcecb44f7..28e2d03c0ccf 100644 --- a/drivers/gpu/drm/tve200/tve200_drv.c +++ b/drivers/gpu/drm/tve200/tve200_drv.c @@ -249,7 +249,7 @@ static int tve200_probe(struct platform_device *pdev)  clk_disable:  	clk_disable_unprepare(priv->pclk);  dev_unref: -	drm_dev_unref(drm); +	drm_dev_put(drm);  	return ret;  } @@ -263,7 +263,7 @@ static int tve200_remove(struct platform_device *pdev)  		drm_panel_bridge_remove(priv->bridge);  	drm_mode_config_cleanup(drm);  	clk_disable_unprepare(priv->pclk); -	drm_dev_unref(drm); +	drm_dev_put(drm);  	return 0;  } diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index b88c96911453..1e8947c7d954 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -210,14 +210,11 @@ static void  v3d_attach_object_fences(struct v3d_exec_info *exec)  {  	struct dma_fence *out_fence = exec->render_done_fence; -	struct v3d_bo *bo;  	int i;  	for (i = 0; i < exec->bo_count; i++) { -		bo = to_v3d_bo(&exec->bo[i]->base); -  		/* XXX: Use shared fences for read-only objects. */ -		reservation_object_add_excl_fence(bo->resv, out_fence); +		reservation_object_add_excl_fence(exec->bo[i]->resv, out_fence);  	}  } @@ -228,11 +225,8 @@ v3d_unlock_bo_reservations(struct drm_device *dev,  {  	int i; -	for (i = 0; i < exec->bo_count; i++) { -		struct v3d_bo *bo = to_v3d_bo(&exec->bo[i]->base); - -		ww_mutex_unlock(&bo->resv->lock); -	} +	for (i = 0; i < exec->bo_count; i++) +		ww_mutex_unlock(&exec->bo[i]->resv->lock);  	ww_acquire_fini(acquire_ctx);  } @@ -251,13 +245,13 @@ v3d_lock_bo_reservations(struct drm_device *dev,  {  	int contended_lock = -1;  	int i, ret; -	struct v3d_bo *bo;  	ww_acquire_init(acquire_ctx, &reservation_ww_class);  retry:  	if (contended_lock != -1) { -		bo = to_v3d_bo(&exec->bo[contended_lock]->base); +		struct v3d_bo *bo = exec->bo[contended_lock]; +  		ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock,  						       acquire_ctx);  		if (ret) { @@ -270,19 +264,16 @@ retry:  		if (i == contended_lock)  			continue; -		bo = to_v3d_bo(&exec->bo[i]->base); - -		ret = ww_mutex_lock_interruptible(&bo->resv->lock, acquire_ctx); +		ret = ww_mutex_lock_interruptible(&exec->bo[i]->resv->lock, +						  acquire_ctx);  		if (ret) {  			int j; -			for (j = 0; j < i; j++) { -				bo = to_v3d_bo(&exec->bo[j]->base); -				ww_mutex_unlock(&bo->resv->lock); -			} +			for (j = 0; j < i; j++) +				ww_mutex_unlock(&exec->bo[j]->resv->lock);  			if (contended_lock != -1 && contended_lock >= i) { -				bo = to_v3d_bo(&exec->bo[contended_lock]->base); +				struct v3d_bo *bo = exec->bo[contended_lock];  				ww_mutex_unlock(&bo->resv->lock);  			} @@ -303,9 +294,7 @@ retry:  	 * before we commit the CL to the hardware.  	 */  	for (i = 0; i < exec->bo_count; i++) { -		bo = to_v3d_bo(&exec->bo[i]->base); - -		ret = reservation_object_reserve_shared(bo->resv, 1); +		ret = reservation_object_reserve_shared(exec->bo[i]->resv, 1);  		if (ret) {  			v3d_unlock_bo_reservations(dev, exec, acquire_ctx);  			return ret; diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index 445b2ef03303..c66d0ce21435 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -41,7 +41,7 @@ v3d_job_free(struct drm_sched_job *sched_job)  }  /** - * Returns the fences that the bin job depends on, one by one. + * Returns the fences that the bin or render job depends on, one by one.   * v3d_job_run() won't be called until all of them have been signaled.   */  static struct dma_fence * diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index 8f8fed471e34..b5580b11a063 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c @@ -169,6 +169,12 @@ static int virtio_gpu_conn_get_modes(struct drm_connector *connector)  	struct drm_display_mode *mode = NULL;  	int count, width, height; +	if (output->edid) { +		count = drm_add_edid_modes(connector, output->edid); +		if (count) +			return count; +	} +  	width  = le32_to_cpu(output->info.r.width);  	height = le32_to_cpu(output->info.r.height);  	count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX); @@ -287,6 +293,8 @@ static int vgdev_output_init(struct virtio_gpu_device *vgdev, int index)  	drm_connector_init(dev, connector, &virtio_gpu_connector_funcs,  			   DRM_MODE_CONNECTOR_VIRTUAL);  	drm_connector_helper_add(connector, &virtio_gpu_conn_helper_funcs); +	if (vgdev->has_edid) +		drm_connector_attach_edid_property(connector);  	drm_encoder_init(dev, encoder, &virtio_gpu_enc_funcs,  			 DRM_MODE_ENCODER_VIRTUAL, NULL); @@ -378,6 +386,10 @@ int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev)  void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev)  { +	int i; + +	for (i = 0 ; i < vgdev->num_scanouts; ++i) +		kfree(vgdev->outputs[i].edid);  	virtio_gpu_fbdev_fini(vgdev);  	drm_mode_config_cleanup(vgdev->ddev);  } diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index d9287c144fe5..f7f32a885af7 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -80,6 +80,7 @@ static unsigned int features[] = {  	 */  	VIRTIO_GPU_F_VIRGL,  #endif +	VIRTIO_GPU_F_EDID,  };  static struct virtio_driver virtio_gpu_driver = {  	.feature_table = features, diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 9db568054d66..f7e877857c1f 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -115,6 +115,7 @@ struct virtio_gpu_output {  	struct drm_encoder enc;  	struct virtio_gpu_display_one info;  	struct virtio_gpu_update_cursor cursor; +	struct edid *edid;  	int cur_x;  	int cur_y;  	bool enabled; @@ -201,6 +202,7 @@ struct virtio_gpu_device {  	struct ida	ctx_id_ida;  	bool has_virgl_3d; +	bool has_edid;  	struct work_struct config_changed_work; @@ -291,6 +293,7 @@ int virtio_gpu_cmd_get_capset_info(struct virtio_gpu_device *vgdev, int idx);  int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev,  			      int idx, int version,  			      struct virtio_gpu_drv_cap_cache **cache_p); +int virtio_gpu_cmd_get_edids(struct virtio_gpu_device *vgdev);  void virtio_gpu_cmd_context_create(struct virtio_gpu_device *vgdev, uint32_t id,  				   uint32_t nlen, const char *name);  void virtio_gpu_cmd_context_destroy(struct virtio_gpu_device *vgdev, diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c index 691b842d5f3a..3af6181c05a8 100644 --- a/drivers/gpu/drm/virtio/virtgpu_kms.c +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c @@ -44,6 +44,8 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work)  	virtio_cread(vgdev->vdev, struct virtio_gpu_config,  		     events_read, &events_read);  	if (events_read & VIRTIO_GPU_EVENT_DISPLAY) { +		if (vgdev->has_edid) +			virtio_gpu_cmd_get_edids(vgdev);  		virtio_gpu_cmd_get_display_info(vgdev);  		drm_helper_hpd_irq_event(vgdev->ddev);  		events_clear |= VIRTIO_GPU_EVENT_DISPLAY; @@ -156,6 +158,10 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)  #else  	DRM_INFO("virgl 3d acceleration not supported by guest\n");  #endif +	if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_EDID)) { +		vgdev->has_edid = true; +		DRM_INFO("EDID support available.\n"); +	}  	ret = virtio_find_vqs(vgdev->vdev, 2, vqs, callbacks, names, NULL);  	if (ret) { @@ -201,6 +207,8 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)  	if (num_capsets)  		virtio_gpu_get_capsets(vgdev, num_capsets); +	if (vgdev->has_edid) +		virtio_gpu_cmd_get_edids(vgdev);  	virtio_gpu_cmd_get_display_info(vgdev);  	wait_event_timeout(vgdev->resp_wq, !vgdev->display_info_pending,  			   5 * HZ); diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 93f2c3a51ee8..2c6764f08f18 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -584,6 +584,45 @@ static void virtio_gpu_cmd_capset_cb(struct virtio_gpu_device *vgdev,  	wake_up(&vgdev->resp_wq);  } +static int virtio_get_edid_block(void *data, u8 *buf, +				 unsigned int block, size_t len) +{ +	struct virtio_gpu_resp_edid *resp = data; +	size_t start = block * EDID_LENGTH; + +	if (start + len > le32_to_cpu(resp->size)) +		return -1; +	memcpy(buf, resp->edid + start, len); +	return 0; +} + +static void virtio_gpu_cmd_get_edid_cb(struct virtio_gpu_device *vgdev, +				       struct virtio_gpu_vbuffer *vbuf) +{ +	struct virtio_gpu_cmd_get_edid *cmd = +		(struct virtio_gpu_cmd_get_edid *)vbuf->buf; +	struct virtio_gpu_resp_edid *resp = +		(struct virtio_gpu_resp_edid *)vbuf->resp_buf; +	uint32_t scanout = le32_to_cpu(cmd->scanout); +	struct virtio_gpu_output *output; +	struct edid *new_edid, *old_edid; + +	if (scanout >= vgdev->num_scanouts) +		return; +	output = vgdev->outputs + scanout; + +	new_edid = drm_do_get_edid(&output->conn, virtio_get_edid_block, resp); + +	spin_lock(&vgdev->display_info_lock); +	old_edid = output->edid; +	output->edid = new_edid; +	drm_connector_update_edid_property(&output->conn, output->edid); +	spin_unlock(&vgdev->display_info_lock); + +	kfree(old_edid); +	wake_up(&vgdev->resp_wq); +} +  int virtio_gpu_cmd_get_display_info(struct virtio_gpu_device *vgdev)  {  	struct virtio_gpu_ctrl_hdr *cmd_p; @@ -686,6 +725,34 @@ int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev,  	return 0;  } +int virtio_gpu_cmd_get_edids(struct virtio_gpu_device *vgdev) +{ +	struct virtio_gpu_cmd_get_edid *cmd_p; +	struct virtio_gpu_vbuffer *vbuf; +	void *resp_buf; +	int scanout; + +	if (WARN_ON(!vgdev->has_edid)) +		return -EINVAL; + +	for (scanout = 0; scanout < vgdev->num_scanouts; scanout++) { +		resp_buf = kzalloc(sizeof(struct virtio_gpu_resp_edid), +				   GFP_KERNEL); +		if (!resp_buf) +			return -ENOMEM; + +		cmd_p = virtio_gpu_alloc_cmd_resp +			(vgdev, &virtio_gpu_cmd_get_edid_cb, &vbuf, +			 sizeof(*cmd_p), sizeof(struct virtio_gpu_resp_edid), +			 resp_buf); +		cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_GET_EDID); +		cmd_p->scanout = cpu_to_le32(scanout); +		virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); +	} + +	return 0; +} +  void virtio_gpu_cmd_context_create(struct virtio_gpu_device *vgdev, uint32_t id,  				   uint32_t nlen, const char *name)  { diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index a3d57e0f5ee5..83087877565c 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -68,7 +68,6 @@ static struct drm_driver vkms_driver = {  	.release		= vkms_release,  	.fops			= &vkms_driver_fops,  	.dumb_create		= vkms_dumb_create, -	.dumb_map_offset	= vkms_dumb_map,  	.gem_vm_ops		= &vkms_gem_vm_ops,  	.gem_free_object_unlocked = vkms_gem_free_object,  	.get_vblank_timestamp	= vkms_get_vblank_timestamp, diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index 1c93990693e3..e4469cd3d254 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -127,9 +127,6 @@ vm_fault_t vkms_gem_fault(struct vm_fault *vmf);  int vkms_dumb_create(struct drm_file *file, struct drm_device *dev,  		     struct drm_mode_create_dumb *args); -int vkms_dumb_map(struct drm_file *file, struct drm_device *dev, -		  u32 handle, u64 *offset); -  void vkms_gem_free_object(struct drm_gem_object *obj);  int vkms_gem_vmap(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/vkms/vkms_gem.c b/drivers/gpu/drm/vkms/vkms_gem.c index d04e988b4cbe..80311daed47a 100644 --- a/drivers/gpu/drm/vkms/vkms_gem.c +++ b/drivers/gpu/drm/vkms/vkms_gem.c @@ -153,32 +153,6 @@ int vkms_dumb_create(struct drm_file *file, struct drm_device *dev,  	return 0;  } -int vkms_dumb_map(struct drm_file *file, struct drm_device *dev, -		  u32 handle, u64 *offset) -{ -	struct drm_gem_object *obj; -	int ret; - -	obj = drm_gem_object_lookup(file, handle); -	if (!obj) -		return -ENOENT; - -	if (!obj->filp) { -		ret = -EINVAL; -		goto unref; -	} - -	ret = drm_gem_create_mmap_offset(obj); -	if (ret) -		goto unref; - -	*offset = drm_vma_node_offset_addr(&obj->vma_node); -unref: -	drm_gem_object_put_unlocked(obj); - -	return ret; -} -  static struct page **_get_pages(struct vkms_gem_object *vkms_obj)  {  	struct drm_gem_object *gem_obj = &vkms_obj->gem; diff --git a/drivers/staging/vboxvideo/vbox_drv.c b/drivers/staging/vboxvideo/vbox_drv.c index 257030460fb6..d3e23dd70c1b 100644 --- a/drivers/staging/vboxvideo/vbox_drv.c +++ b/drivers/staging/vboxvideo/vbox_drv.c @@ -279,7 +279,6 @@ static struct drm_driver driver = {  	.gem_free_object_unlocked = vbox_gem_free_object,  	.dumb_create = vbox_dumb_create,  	.dumb_map_offset = vbox_dumb_mmap_offset, -	.dumb_destroy = drm_gem_dumb_destroy,  	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,  	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,  	.gem_prime_export = drm_gem_prime_export,  | 
