Commit 61647c77 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm-misc-next-2018-11-28' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

drm-misc-next for v4.21:

Core Changes:
- Merge drm_info.c into drm_debugfs.c
- Complete the fake drm_crtc_commit's hw_done/flip_done sooner.
- Remove deprecated drm_obj_ref/unref functions. All drivers use get/put now.
- Decrease stack use of drm_gem_prime_mmap.
- Improve documentation for dumb callbacks.

Driver Changes:
- Add edid support to virtio.
- Wait on implicit fence in meson and sun4i.
- Add support for BGRX8888 to sun4i.
- Preparation patches for sun4i driver to start supporting linear and tiled YUV formats.
- Add support for HDMI 1.4 4k modes to meson, and support for VIC alternate timings.
- Drop custom dumb_map in vkms.
- Small fixes and cleanups to v3d.
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/151a3270-b1be-ed75-bd58-6b29d741f592@linux.intel.com
parents 1a31c26e 08f73d66
...@@ -28,22 +28,16 @@ them, but also all the virtual ones used by KVM, so everyone qualifies). ...@@ -28,22 +28,16 @@ them, but also all the virtual ones used by KVM, so everyone qualifies).
Contact: Daniel Vetter, Thierry Reding, respective driver maintainers Contact: Daniel Vetter, Thierry Reding, respective driver maintainers
Switch from reference/unreference to get/put
--------------------------------------------
For some reason DRM core uses ``reference``/``unreference`` suffixes for
refcounting functions, but kernel uses ``get``/``put`` (e.g.
``kref_get``/``put()``). It would be good to switch over for consistency, and
it's shorter. Needs to be done in 3 steps for each pair of functions:
* Create new ``get``/``put`` functions, define the old names as compatibility Remove custom dumb_map_offset implementations
wrappers ---------------------------------------------
* Switch over each file/driver using a cocci-generated spatch.
* Once all users of the old names are gone, remove them.
This way drivers/patches in the progress of getting merged won't break. All GEM based drivers should be using drm_gem_create_mmap_offset() instead.
Audit each individual driver, make sure it'll work with the generic
implementation (there's lots of outdated locking leftovers in various
implementations), and then remove it.
Contact: Daniel Vetter Contact: Daniel Vetter, respective driver maintainers
Convert existing KMS drivers to atomic modesetting Convert existing KMS drivers to atomic modesetting
-------------------------------------------------- --------------------------------------------------
......
...@@ -10,7 +10,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ ...@@ -10,7 +10,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \
drm_scatter.o drm_pci.o \ drm_scatter.o drm_pci.o \
drm_sysfs.o drm_hashtab.o drm_mm.o \ drm_sysfs.o drm_hashtab.o drm_mm.o \
drm_crtc.o drm_fourcc.o drm_modes.o drm_edid.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_trace_points.o drm_prime.o \
drm_rect.o drm_vma_manager.o drm_flip_work.o \ drm_rect.o drm_vma_manager.o drm_flip_work.o \
drm_modeset_lock.o drm_atomic.o drm_bridge.o \ drm_modeset_lock.o drm_atomic.o drm_bridge.o \
......
...@@ -190,7 +190,7 @@ static int arcpgu_probe(struct platform_device *pdev) ...@@ -190,7 +190,7 @@ static int arcpgu_probe(struct platform_device *pdev)
arcpgu_unload(drm); arcpgu_unload(drm);
err_unref: err_unref:
drm_dev_unref(drm); drm_dev_put(drm);
return ret; return ret;
} }
...@@ -201,7 +201,7 @@ static int arcpgu_remove(struct platform_device *pdev) ...@@ -201,7 +201,7 @@ static int arcpgu_remove(struct platform_device *pdev)
drm_dev_unregister(drm); drm_dev_unregister(drm);
arcpgu_unload(drm); arcpgu_unload(drm);
drm_dev_unref(drm); drm_dev_put(drm);
return 0; return 0;
} }
......
...@@ -379,7 +379,7 @@ static void tc358764_detach(struct drm_bridge *bridge) ...@@ -379,7 +379,7 @@ static void tc358764_detach(struct drm_bridge *bridge)
drm_fb_helper_remove_one_connector(drm->fb_helper, &ctx->connector); drm_fb_helper_remove_one_connector(drm->fb_helper, &ctx->connector);
drm_panel_detach(ctx->panel); drm_panel_detach(ctx->panel);
ctx->panel = NULL; ctx->panel = NULL;
drm_connector_unreference(&ctx->connector); drm_connector_put(&ctx->connector);
} }
static const struct drm_bridge_funcs tc358764_bridge_funcs = { static const struct drm_bridge_funcs tc358764_bridge_funcs = {
......
...@@ -1460,6 +1460,9 @@ void drm_atomic_helper_wait_for_flip_done(struct drm_device *dev, ...@@ -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", DRM_ERROR("[CRTC:%d:%s] flip_done timed out\n",
crtc->base.id, crtc->name); 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); 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) ...@@ -2217,8 +2220,10 @@ void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *old_state)
spin_unlock(&crtc->commit_lock); spin_unlock(&crtc->commit_lock);
} }
if (old_state->fake_commit) if (old_state->fake_commit) {
complete_all(&old_state->fake_commit->cleanup_done); 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); EXPORT_SYMBOL(drm_atomic_helper_commit_cleanup_done);
......
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#include <drm/drm_debugfs.h> #include <drm/drm_debugfs.h>
#include <drm/drm_edid.h> #include <drm/drm_edid.h>
#include <drm/drm_atomic.h> #include <drm/drm_atomic.h>
#include <drm/drm_auth.h>
#include <drm/drm_gem.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#include "drm_internal.h" #include "drm_internal.h"
...@@ -43,6 +45,93 @@ ...@@ -43,6 +45,93 @@
* Initialization, etc. * 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[] = { static const struct drm_info_list drm_debugfs_list[] = {
{"name", drm_name_info, 0}, {"name", drm_name_info, 0},
{"clients", drm_clients_info, 0}, {"clients", drm_clients_info, 0},
......
...@@ -704,19 +704,6 @@ void drm_dev_put(struct drm_device *dev) ...@@ -704,19 +704,6 @@ void drm_dev_put(struct drm_device *dev)
} }
EXPORT_SYMBOL(drm_dev_put); 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) static int create_compat_control_link(struct drm_device *dev)
{ {
struct drm_minor *minor; struct drm_minor *minor;
......
/**
* \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;
}
...@@ -56,11 +56,6 @@ void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpr ...@@ -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); struct drm_minor *drm_minor_acquire(unsigned int minor_id);
void drm_minor_release(struct drm_minor *minor); 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 */ /* drm_vblank.c */
void drm_vblank_disable_and_save(struct drm_device *dev, unsigned int pipe); void drm_vblank_disable_and_save(struct drm_device *dev, unsigned int pipe);
void drm_vblank_cleanup(struct drm_device *dev); void drm_vblank_cleanup(struct drm_device *dev);
......
...@@ -663,24 +663,33 @@ EXPORT_SYMBOL(drm_gem_prime_handle_to_fd); ...@@ -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) 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;
struct drm_file priv = { struct file *fil;
.minor = obj->dev->primary,
};
struct file fil = {
.private_data = &priv,
};
int ret; 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) if (ret)
return ret; goto out;
vma->vm_pgoff += drm_vma_node_start(&obj->vma_node); 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; return ret;
} }
......
...@@ -550,7 +550,7 @@ static int etnaviv_bind(struct device *dev) ...@@ -550,7 +550,7 @@ static int etnaviv_bind(struct device *dev)
out_bind: out_bind:
kfree(priv); kfree(priv);
out_unref: out_unref:
drm_dev_unref(drm); drm_dev_put(drm);
return ret; return ret;
} }
...@@ -567,7 +567,7 @@ static void etnaviv_unbind(struct device *dev) ...@@ -567,7 +567,7 @@ static void etnaviv_unbind(struct device *dev)
drm->dev_private = NULL; drm->dev_private = NULL;
kfree(priv); kfree(priv);
drm_dev_unref(drm); drm_dev_put(drm);
} }
static const struct component_master_ops etnaviv_master_ops = { static const struct component_master_ops etnaviv_master_ops = {
......
...@@ -594,17 +594,7 @@ dw_hdmi_mode_valid(struct drm_connector *connector, ...@@ -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__, dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__,
vclk_freq, venc_freq, hdmi_freq); vclk_freq, venc_freq, hdmi_freq);
/* Finally filter by configurable vclk frequencies for VIC modes */ return meson_vclk_vic_supported_freq(vclk_freq);
switch (vclk_freq) {
case 54000:
case 74250:
case 148500:
case 297000:
case 594000:
return MODE_OK;
}
return MODE_CLOCK_RANGE;
} }
/* Encoder */ /* Encoder */
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <drm/drm_plane_helper.h> #include <drm/drm_plane_helper.h>
#include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_rect.h> #include <drm/drm_rect.h>
#include "meson_overlay.h" #include "meson_overlay.h"
...@@ -532,6 +533,7 @@ static const struct drm_plane_helper_funcs meson_overlay_helper_funcs = { ...@@ -532,6 +533,7 @@ static const struct drm_plane_helper_funcs meson_overlay_helper_funcs = {
.atomic_check = meson_overlay_atomic_check, .atomic_check = meson_overlay_atomic_check,
.atomic_disable = meson_overlay_atomic_disable, .atomic_disable = meson_overlay_atomic_disable,
.atomic_update = meson_overlay_atomic_update, .atomic_update = meson_overlay_atomic_update,
.prepare_fb = drm_gem_fb_prepare_fb,
}; };
static const struct drm_plane_funcs meson_overlay_funcs = { static const struct drm_plane_funcs meson_overlay_funcs = {
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <drm/drm_plane_helper.h> #include <drm/drm_plane_helper.h>
#include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_rect.h> #include <drm/drm_rect.h>
#include "meson_plane.h" #include "meson_plane.h"
...@@ -322,6 +323,7 @@ static const struct drm_plane_helper_funcs meson_plane_helper_funcs = { ...@@ -322,6 +323,7 @@ static const struct drm_plane_helper_funcs meson_plane_helper_funcs = {
.atomic_check = meson_plane_atomic_check, .atomic_check = meson_plane_atomic_check,
.atomic_disable = meson_plane_atomic_disable, .atomic_disable = meson_plane_atomic_disable,
.atomic_update = meson_plane_atomic_update, .atomic_update = meson_plane_atomic_update,
.prepare_fb = drm_gem_fb_prepare_fb,
}; };
static const struct drm_plane_funcs meson_plane_funcs = { static const struct drm_plane_funcs meson_plane_funcs = {
......
...@@ -117,6 +117,8 @@ ...@@ -117,6 +117,8 @@
#define HDMI_PLL_RESET BIT(28) #define HDMI_PLL_RESET BIT(28)
#define HDMI_PLL_LOCK BIT(31) #define HDMI_PLL_LOCK BIT(31)
#define FREQ_1000_1001(_freq) DIV_ROUND_CLOSEST(_freq * 1000, 1001)
/* VID PLL Dividers */ /* VID PLL Dividers */
enum { enum {
VID_PLL_DIV_1 = 0, VID_PLL_DIV_1 = 0,
...@@ -323,7 +325,7 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) ...@@ -323,7 +325,7 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
enum { enum {
/* PLL O1 O2 O3 VP DV EN TX */ /* PLL O1 O2 O3 VP DV EN TX */
/* 4320 /4 /4 /1 /5 /1 => /2 /2 */ /* 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 */ /* 4320 /4 /4 /1 /5 /1 => /1 /2 */
MESON_VCLK_HDMI_DDR_54000, MESON_VCLK_HDMI_DDR_54000,
/* 2970 /4 /1 /1 /5 /1 => /1 /2 */ /* 2970 /4 /1 /1 /5 /1 => /1 /2 */
...@@ -339,6 +341,7 @@ enum { ...@@ -339,6 +341,7 @@ enum {
}; };
struct meson_vclk_params { struct meson_vclk_params {
unsigned int pixel_freq;
unsigned int pll_base_freq; unsigned int pll_base_freq;
unsigned int pll_od1; unsigned int pll_od1;
unsigned int pll_od2; unsigned int pll_od2;
...@@ -347,6 +350,7 @@ struct meson_vclk_params { ...@@ -347,6 +350,7 @@ struct meson_vclk_params {
unsigned int vclk_div; unsigned int vclk_div;
} params[] = { } params[] = {
[MESON_VCLK_HDMI_ENCI_54000] = { [MESON_VCLK_HDMI_ENCI_54000] = {
.pixel_freq = 54000,
.pll_base_freq = 4320000, .pll_base_freq = 4320000,
.pll_od1 = 4, .pll_od1 = 4,
.pll_od2 = 4, .pll_od2 = 4,
...@@ -355,6 +359,7 @@ struct meson_vclk_params { ...@@ -355,6 +359,7 @@ struct meson_vclk_params {
.vclk_div = 1, .vclk_div = 1,
}, },
[MESON_VCLK_HDMI_DDR_54000] = { [MESON_VCLK_HDMI_DDR_54000] = {
.pixel_freq = 54000,
.pll_base_freq = 4320000, .pll_base_freq = 4320000,
.pll_od1 = 4, .pll_od1 = 4,
.pll_od2 = 4, .pll_od2 = 4,
...@@ -363,6 +368,7 @@ struct meson_vclk_params { ...@@ -363,6 +368,7 @@ struct meson_vclk_params {
.vclk_div = 1, .vclk_div = 1,
}, },
[MESON_VCLK_HDMI_DDR_148500] = { [MESON_VCLK_HDMI_DDR_148500] = {
.pixel_freq = 148500,
.pll_base_freq = 2970000, .pll_base_freq = 2970000,
.pll_od1 = 4, .pll_od1 = 4,
.pll_od2 = 1, .pll_od2 = 1,
...@@ -371,6 +377,7 @@ struct meson_vclk_params { ...@@ -371,6 +377,7 @@ struct meson_vclk_params {
.vclk_div = 1, .vclk_div = 1,
}, },
[MESON_VCLK_HDMI_74250] = { [MESON_VCLK_HDMI_74250] = {
.pixel_freq = 74250,
.pll_base_freq = 2970000, .pll_base_freq = 2970000,
.pll_od1 = 2, .pll_od1 = 2,
.pll_od2 = 2, .pll_od2 = 2,
...@@ -379,6 +386,7 @@ struct meson_vclk_params { ...@@ -379,6 +386,7 @@ struct meson_vclk_params {
.vclk_div = 1, .vclk_div = 1,
}, },
[MESON_VCLK_HDMI_148500] = { [MESON_VCLK_HDMI_148500] = {
.pixel_freq = 148500,
.pll_base_freq = 2970000, .pll_base_freq = 2970000,
.pll_od1 = 1, .pll_od1 = 1,
.pll_od2 = 2, .pll_od2 = 2,
...@@ -387,6 +395,7 @@ struct meson_vclk_params { ...@@ -387,6 +395,7 @@ struct meson_vclk_params {
.vclk_div = 1, .vclk_div = 1,
}, },
[MESON_VCLK_HDMI_297000] = { [MESON_VCLK_HDMI_297000] = {
.pixel_freq = 297000,
.pll_base_freq = 2970000, .pll_base_freq = 2970000,
.pll_od1 = 1, .pll_od1 = 1,
.pll_od2 = 1, .pll_od2 = 1,
...@@ -395,6 +404,7 @@ struct meson_vclk_params { ...@@ -395,6 +404,7 @@ struct meson_vclk_params {
.vclk_div = 2, .vclk_div = 2,
}, },
[MESON_VCLK_HDMI_594000] = { [MESON_VCLK_HDMI_594000] = {
.pixel_freq = 594000,
.pll_base_freq = 5940000, .pll_base_freq = 5940000,
.pll_od1 = 1, .pll_od1 = 1,
.pll_od2 = 1, .pll_od2 = 1,
...@@ -402,6 +412,7 @@ struct meson_vclk_params { ...@@ -402,6 +412,7 @@ struct meson_vclk_params {
.vid_pll_div = VID_PLL_DIV_5, .vid_pll_div = VID_PLL_DIV_5,
.vclk_div = 1, .vclk_div = 1,
}, },
{ /* sentinel */ },
}; };
static inline unsigned int pll_od_to_reg(unsigned int od) 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, ...@@ -626,12 +637,37 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv,
pll_freq); 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, 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 od1, unsigned int od2, unsigned int od3,
unsigned int vid_pll_div, unsigned int vclk_div, unsigned int vid_pll_div, unsigned int vclk_div,
unsigned int hdmi_tx_div, unsigned int venc_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 */ /* Set HDMI-TX sys clock */
regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
CTS_HDMI_SYS_SEL_MASK, 0); CTS_HDMI_SYS_SEL_MASK, 0);
...@@ -646,34 +682,38 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq, ...@@ -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")) { } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
switch (pll_base_freq) { switch (pll_base_freq) {
case 2970000: case 2970000:
meson_hdmi_pll_set_params(priv, 0x3d, 0xe00, m = 0x3d;
od1, od2, od3); frac = vic_alternate_clock ? 0xd02 : 0xe00;
break; break;
case 4320000: case 4320000:
meson_hdmi_pll_set_params(priv, 0x5a, 0, m = vic_alternate_clock ? 0x59 : 0x5a;
od1, od2, od3); frac = vic_alternate_clock ? 0xe8f : 0;
break; break;
case 5940000: case 5940000:
meson_hdmi_pll_set_params(priv, 0x7b, 0xc00, m = 0x7b;
od1, od2, od3); frac = vic_alternate_clock ? 0xa05 : 0xc00;
break; break;
} }
meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
switch (pll_base_freq) { switch (pll_base_freq) {
case 2970000: case 2970000:
meson_hdmi_pll_set_params(priv, 0x7b, 0x300, m = 0x7b;
od1, od2, od3); frac = vic_alternate_clock ? 0x281 : 0x300;
break; break;
case 4320000: case 4320000:
meson_hdmi_pll_set_params(priv, 0xb4, 0, m = vic_alternate_clock ? 0xb3 : 0xb4;
od1, od2, od3); frac = vic_alternate_clock ? 0x347 : 0;
break; break;
case 5940000: case 5940000:
meson_hdmi_pll_set_params(priv, 0xf7, 0x200, m = 0xf7;
od1, od2, od3); frac = vic_alternate_clock ? 0x102 : 0x200;
break; break;
} }
meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
} }
/* Setup vid_pll divider */ /* Setup vid_pll divider */
...@@ -826,6 +866,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, ...@@ -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 vclk_freq, unsigned int venc_freq,
unsigned int dac_freq, bool hdmi_use_enci) unsigned int dac_freq, bool hdmi_use_enci)
{ {
bool vic_alternate_clock = false;
unsigned int freq; unsigned int freq;
unsigned int hdmi_tx_div; unsigned int hdmi_tx_div;
unsigned int venc_div; unsigned int venc_div;
...@@ -843,7 +884,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, ...@@ -843,7 +884,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
* - encp encoder * - encp encoder
*/ */
meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0, 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; return;
} }
...@@ -863,31 +904,35 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, ...@@ -863,31 +904,35 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
return; return;
} }
switch (vclk_freq) { for (freq = 0 ; params[freq].pixel_freq ; ++freq) {
case 54000: if (vclk_freq == params[freq].pixel_freq ||
if (hdmi_use_enci) vclk_freq == FREQ_1000_1001(params[freq].pixel_freq)) {
freq = MESON_VCLK_HDMI_ENCI_54000; if (vclk_freq != params[freq].pixel_freq)
vic_alternate_clock = true;
else else
freq = MESON_VCLK_HDMI_DDR_54000; vic_alternate_clock = false;
break;
case 74250: if (freq == MESON_VCLK_HDMI_ENCI_54000 &&
freq = MESON_VCLK_HDMI_74250; !hdmi_use_enci)
break; continue;
case 148500:
if (dac_freq != 148500) if (freq == MESON_VCLK_HDMI_DDR_54000 &&
freq = MESON_VCLK_HDMI_DDR_148500; hdmi_use_enci)
else continue;
freq = MESON_VCLK_HDMI_148500;
break; if (freq == MESON_VCLK_HDMI_DDR_148500 &&
case 297000: dac_freq == vclk_freq)
freq = MESON_VCLK_HDMI_297000; continue;
break;
case 594000: if (freq == MESON_VCLK_HDMI_148500 &&
freq = MESON_VCLK_HDMI_594000; dac_freq != vclk_freq)
continue;
break; break;
default: }
pr_err("Fatal Error, invalid HDMI vclk freq %d\n", }
vclk_freq);
if (!params[freq].pixel_freq) {
pr_err("Fatal Error, invalid HDMI vclk freq %d\n", vclk_freq);
return; return;
} }
...@@ -895,6 +940,6 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, ...@@ -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_od1, params[freq].pll_od2,
params[freq].pll_od3, params[freq].vid_pll_div, params[freq].pll_od3, params[freq].vid_pll_div,
params[freq].vclk_div, hdmi_tx_div, venc_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); EXPORT_SYMBOL_GPL(meson_vclk_setup);
...@@ -32,6 +32,8 @@ enum { ...@@ -32,6 +32,8 @@ enum {
enum drm_mode_status enum drm_mode_status
meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq); 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, void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
unsigned int vclk_freq, unsigned int venc_freq, unsigned int vclk_freq, unsigned int venc_freq,
......
...@@ -697,6 +697,132 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = { ...@@ -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 { struct meson_hdmi_venc_vic_mode {
unsigned int vic; unsigned int vic;
union meson_hdmi_venc_mode *mode; union meson_hdmi_venc_mode *mode;
...@@ -717,6 +843,9 @@ struct meson_hdmi_venc_vic_mode { ...@@ -717,6 +843,9 @@ struct meson_hdmi_venc_vic_mode {
{ 34, &meson_hdmi_encp_mode_1080p30 }, { 34, &meson_hdmi_encp_mode_1080p30 },
{ 31, &meson_hdmi_encp_mode_1080p50 }, { 31, &meson_hdmi_encp_mode_1080p50 },
{ 16, &meson_hdmi_encp_mode_1080p60 }, { 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 */ { 0, NULL}, /* sentinel */
}; };
......
...@@ -417,7 +417,7 @@ static int mxsfb_probe(struct platform_device *pdev) ...@@ -417,7 +417,7 @@ static int mxsfb_probe(struct platform_device *pdev)
err_unload: err_unload:
mxsfb_unload(drm); mxsfb_unload(drm);
err_free: err_free:
drm_dev_unref(drm); drm_dev_put(drm);
return ret; return ret;
} }
...@@ -428,7 +428,7 @@ static int mxsfb_remove(struct platform_device *pdev) ...@@ -428,7 +428,7 @@ static int mxsfb_remove(struct platform_device *pdev)
drm_dev_unregister(drm); drm_dev_unregister(drm);
mxsfb_unload(drm); mxsfb_unload(drm);
drm_dev_unref(drm); drm_dev_put(drm);
return 0; return 0;
} }
......
...@@ -48,8 +48,12 @@ static const u32 sunxi_rgb2yuv_coef[12] = { ...@@ -48,8 +48,12 @@ static const u32 sunxi_rgb2yuv_coef[12] = {
/* /*
* These coefficients are taken from the A33 BSP from Allwinner. * These coefficients are taken from the A33 BSP from Allwinner.
* *
* The formula is for each component, each coefficient being multiplied by * The first three values of each row are coded as 13-bit signed fixed-point
* 1024 and each constant being multiplied by 16: * 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 * G = 1.164 * Y - 0.391 * U - 0.813 * V + 135
* R = 1.164 * Y + 1.596 * V - 222 * R = 1.164 * Y + 1.596 * V - 222
* B = 1.164 * Y + 2.018 * U + 276 * B = 1.164 * Y + 2.018 * U + 276
...@@ -155,6 +159,36 @@ static int sun4i_backend_drm_format_to_layer(u32 format, u32 *mode) ...@@ -155,6 +159,36 @@ static int sun4i_backend_drm_format_to_layer(u32 format, u32 *mode)
return 0; 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 sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
int layer, struct drm_plane *plane) int layer, struct drm_plane *plane)
{ {
...@@ -395,6 +429,15 @@ int sun4i_backend_update_layer_zpos(struct sun4i_backend *backend, int layer, ...@@ -395,6 +429,15 @@ int sun4i_backend_update_layer_zpos(struct sun4i_backend *backend, int layer,
return 0; 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) static bool sun4i_backend_plane_uses_scaler(struct drm_plane_state *state)
{ {
u16 src_h = state->src_h >> 16; u16 src_h = state->src_h >> 16;
...@@ -413,11 +456,50 @@ static bool sun4i_backend_plane_uses_frontend(struct drm_plane_state *state) ...@@ -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_layer *layer = plane_to_sun4i_layer(state->plane);
struct sun4i_backend *backend = layer->backend; struct sun4i_backend *backend = layer->backend;
uint32_t format = state->fb->format->format;
uint64_t modifier = state->fb->modifier;
if (IS_ERR(backend->frontend)) if (IS_ERR(backend->frontend))
return false; 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, static void sun4i_backend_atomic_begin(struct sunxi_engine *engine,
...@@ -460,14 +542,19 @@ static int sun4i_backend_atomic_check(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_framebuffer *fb = plane_state->fb;
struct drm_format_name_buf format_name; 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", DRM_DEBUG_DRIVER("Using the frontend for plane %d\n",
plane->index); plane->index);
layer_state->uses_frontend = true;
num_frontend_planes++; num_frontend_planes++;
} else { } 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", DRM_DEBUG_DRIVER("Plane FB format is %s\n",
...@@ -476,11 +563,6 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, ...@@ -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)) if (fb->format->has_alpha || (plane_state->alpha != DRM_BLEND_ALPHA_OPAQUE))
num_alpha_planes++; 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", DRM_DEBUG_DRIVER("Plane zpos is %d\n",
plane_state->normalized_zpos); plane_state->normalized_zpos);
......
...@@ -198,6 +198,7 @@ engine_to_sun4i_backend(struct sunxi_engine *engine) ...@@ -198,6 +198,7 @@ engine_to_sun4i_backend(struct sunxi_engine *engine)
void sun4i_backend_layer_enable(struct sun4i_backend *backend, void sun4i_backend_layer_enable(struct sun4i_backend *backend,
int layer, bool enable); 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 sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
int layer, struct drm_plane *plane); int layer, struct drm_plane *plane);
int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
...@@ -208,5 +209,7 @@ int sun4i_backend_update_layer_frontend(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 layer, uint32_t in_fmt);
int sun4i_backend_update_layer_zpos(struct sun4i_backend *backend, int sun4i_backend_update_layer_zpos(struct sun4i_backend *backend,
int layer, struct drm_plane *plane); int layer, struct drm_plane *plane);
void sun4i_backend_cleanup_layer(struct sun4i_backend *backend,
int layer);
#endif /* _SUN4I_BACKEND_H_ */ #endif /* _SUN4I_BACKEND_H_ */
...@@ -28,6 +28,16 @@ ...@@ -28,6 +28,16 @@
#include "sun4i_tcon.h" #include "sun4i_tcon.h"
#include "sun8i_tcon_top.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); DEFINE_DRM_GEM_CMA_FOPS(sun4i_drv_fops);
static struct drm_driver sun4i_drv_driver = { static struct drm_driver sun4i_drv_driver = {
...@@ -42,7 +52,7 @@ static struct drm_driver sun4i_drv_driver = { ...@@ -42,7 +52,7 @@ static struct drm_driver sun4i_drv_driver = {
.minor = 0, .minor = 0,
/* GEM Operations */ /* 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_free_object_unlocked = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops, .gem_vm_ops = &drm_gem_cma_vm_ops,
......
...@@ -107,8 +107,34 @@ EXPORT_SYMBOL(sun4i_frontend_update_buffer); ...@@ -107,8 +107,34 @@ EXPORT_SYMBOL(sun4i_frontend_update_buffer);
static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val) static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val)
{ {
switch (fmt) { switch (fmt) {
case DRM_FORMAT_ARGB8888: case DRM_FORMAT_XRGB8888:
*val = 5; *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; return 0;
default: default:
...@@ -119,9 +145,12 @@ static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val) ...@@ -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) static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val)
{ {
switch (fmt) { switch (fmt) {
case DRM_FORMAT_BGRX8888:
*val = SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_BGRX8888;
return 0;
case DRM_FORMAT_XRGB8888: case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_ARGB8888: *val = SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_XRGB8888;
*val = 2;
return 0; return 0;
default: default:
...@@ -129,22 +158,54 @@ static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val) ...@@ -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, int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
struct drm_plane *plane, uint32_t out_fmt) struct drm_plane *plane, uint32_t out_fmt)
{ {
struct drm_plane_state *state = plane->state; struct drm_plane_state *state = plane->state;
struct drm_framebuffer *fb = state->fb; struct drm_framebuffer *fb = state->fb;
uint32_t format = fb->format->format;
u32 out_fmt_val; u32 out_fmt_val;
u32 in_fmt_val; u32 in_fmt_val, in_mod_val, in_ps_val;
int ret; int ret;
ret = sun4i_frontend_drm_format_to_input_fmt(fb->format->format, ret = sun4i_frontend_drm_format_to_input_fmt(format, &in_fmt_val);
&in_fmt_val);
if (ret) { if (ret) {
DRM_DEBUG_DRIVER("Invalid input format\n"); DRM_DEBUG_DRIVER("Invalid input format\n");
return ret; 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); ret = sun4i_frontend_drm_format_to_output_fmt(out_fmt, &out_fmt_val);
if (ret) { if (ret) {
DRM_DEBUG_DRIVER("Invalid output format\n"); DRM_DEBUG_DRIVER("Invalid output format\n");
...@@ -162,10 +223,12 @@ int sun4i_frontend_update_formats(struct sun4i_frontend *frontend, ...@@ -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_CH0_VERTPHASE1_REG, 0x400);
regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_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, regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG,
SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(1) | in_mod_val | in_fmt_val | in_ps_val);
SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(in_fmt_val) |
SUN4I_FRONTEND_INPUT_FMT_PS(1));
/* /*
* TODO: It look like the A31 and A80 at least will need the * 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, ...@@ -173,7 +236,7 @@ int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
* ARGB8888). * ARGB8888).
*/ */
regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG, regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG,
SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(out_fmt_val)); out_fmt_val);
return 0; return 0;
} }
...@@ -183,16 +246,24 @@ void sun4i_frontend_update_coord(struct sun4i_frontend *frontend, ...@@ -183,16 +246,24 @@ void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
struct drm_plane *plane) struct drm_plane *plane)
{ {
struct drm_plane_state *state = plane->state; 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 */ /* Set height and width */
DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n", DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n",
state->crtc_w, state->crtc_h); 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, regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG,
SUN4I_FRONTEND_INSIZE(state->src_h >> 16, SUN4I_FRONTEND_INSIZE(luma_height, luma_width));
state->src_w >> 16));
regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG, regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG,
SUN4I_FRONTEND_INSIZE(state->src_h >> 16, SUN4I_FRONTEND_INSIZE(chroma_height, chroma_width));
state->src_w >> 16));
regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG, regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG,
SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w)); SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
...@@ -200,14 +271,14 @@ void sun4i_frontend_update_coord(struct sun4i_frontend *frontend, ...@@ -200,14 +271,14 @@ void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w)); SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG, 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, 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, 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, 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, regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
SUN4I_FRONTEND_FRM_CTRL_REG_RDY, SUN4I_FRONTEND_FRM_CTRL_REG_RDY,
...@@ -339,10 +410,6 @@ static int sun4i_frontend_runtime_resume(struct device *dev) ...@@ -339,10 +410,6 @@ static int sun4i_frontend_runtime_resume(struct device *dev)
SUN4I_FRONTEND_EN_EN, SUN4I_FRONTEND_EN_EN,
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); sun4i_frontend_scaler_init(frontend);
return 0; return 0;
......
...@@ -26,12 +26,14 @@ ...@@ -26,12 +26,14 @@
#define SUN4I_FRONTEND_LINESTRD0_REG 0x040 #define SUN4I_FRONTEND_LINESTRD0_REG 0x040
#define SUN4I_FRONTEND_INPUT_FMT_REG 0x04c #define SUN4I_FRONTEND_INPUT_FMT_REG 0x04c
#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(mod) ((mod) << 8) #define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PACKED (1 << 8)
#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(fmt) ((fmt) << 4) #define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_RGB (5 << 4)
#define SUN4I_FRONTEND_INPUT_FMT_PS(ps) (ps) #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_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_CH0_INSIZE_REG 0x100
#define SUN4I_FRONTEND_INSIZE(h, w) ((((h) - 1) << 16) | (((w) - 1))) #define SUN4I_FRONTEND_INSIZE(h, w) ((((h) - 1) << 16) | (((w) - 1)))
...@@ -95,5 +97,6 @@ void sun4i_frontend_update_coord(struct sun4i_frontend *frontend, ...@@ -95,5 +97,6 @@ void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
struct drm_plane *plane); struct drm_plane *plane);
int sun4i_frontend_update_formats(struct sun4i_frontend *frontend, int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
struct drm_plane *plane, uint32_t out_fmt); struct drm_plane *plane, uint32_t out_fmt);
bool sun4i_frontend_format_is_supported(uint32_t fmt, uint64_t modifier);
#endif /* _SUN4I_FRONTEND_H_ */ #endif /* _SUN4I_FRONTEND_H_ */
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_plane_helper.h> #include <drm/drm_plane_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#include "sun4i_backend.h" #include "sun4i_backend.h"
...@@ -92,14 +93,16 @@ static void sun4i_backend_layer_atomic_update(struct drm_plane *plane, ...@@ -92,14 +93,16 @@ static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
struct sun4i_backend *backend = layer->backend; struct sun4i_backend *backend = layer->backend;
struct sun4i_frontend *frontend = backend->frontend; struct sun4i_frontend *frontend = backend->frontend;
sun4i_backend_cleanup_layer(backend, layer->id);
if (layer_state->uses_frontend) { if (layer_state->uses_frontend) {
sun4i_frontend_init(frontend); sun4i_frontend_init(frontend);
sun4i_frontend_update_coord(frontend, plane); sun4i_frontend_update_coord(frontend, plane);
sun4i_frontend_update_buffer(frontend, plane); sun4i_frontend_update_buffer(frontend, plane);
sun4i_frontend_update_formats(frontend, plane, sun4i_frontend_update_formats(frontend, plane,
DRM_FORMAT_ARGB8888); DRM_FORMAT_XRGB8888);
sun4i_backend_update_layer_frontend(backend, layer->id, sun4i_backend_update_layer_frontend(backend, layer->id,
DRM_FORMAT_ARGB8888); DRM_FORMAT_XRGB8888);
sun4i_frontend_enable(frontend); sun4i_frontend_enable(frontend);
} else { } else {
sun4i_backend_update_layer_formats(backend, layer->id, plane); sun4i_backend_update_layer_formats(backend, layer->id, plane);
...@@ -112,6 +115,7 @@ static void sun4i_backend_layer_atomic_update(struct drm_plane *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 = { 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_disable = sun4i_backend_layer_atomic_disable,
.atomic_update = sun4i_backend_layer_atomic_update, .atomic_update = sun4i_backend_layer_atomic_update,
}; };
...@@ -125,10 +129,11 @@ static const struct drm_plane_funcs sun4i_backend_layer_funcs = { ...@@ -125,10 +129,11 @@ static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
.update_plane = drm_atomic_helper_update_plane, .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_ARGB8888,
DRM_FORMAT_ARGB4444, DRM_FORMAT_ARGB4444,
DRM_FORMAT_ARGB1555, DRM_FORMAT_ARGB1555,
DRM_FORMAT_BGRX8888,
DRM_FORMAT_RGBA5551, DRM_FORMAT_RGBA5551,
DRM_FORMAT_RGBA4444, DRM_FORMAT_RGBA4444,
DRM_FORMAT_RGB888, DRM_FORMAT_RGB888,
...@@ -154,8 +159,8 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm, ...@@ -154,8 +159,8 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
/* possible crtcs are set later */ /* possible crtcs are set later */
ret = drm_universal_plane_init(drm, &layer->plane, 0, ret = drm_universal_plane_init(drm, &layer->plane, 0,
&sun4i_backend_layer_funcs, &sun4i_backend_layer_funcs,
sun4i_backend_layer_formats, sun4i_layer_formats,
ARRAY_SIZE(sun4i_backend_layer_formats), ARRAY_SIZE(sun4i_layer_formats),
NULL, type, NULL); NULL, type, NULL);
if (ret) { if (ret) {
dev_err(drm->dev, "Couldn't initialize layer\n"); dev_err(drm->dev, "Couldn't initialize layer\n");
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <drm/drm_crtc_helper.h> #include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_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/drm_plane_helper.h>
#include <drm/drmP.h> #include <drm/drmP.h>
...@@ -300,6 +301,7 @@ static void sun8i_ui_layer_atomic_update(struct drm_plane *plane, ...@@ -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 = { 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_check = sun8i_ui_layer_atomic_check,
.atomic_disable = sun8i_ui_layer_atomic_disable, .atomic_disable = sun8i_ui_layer_atomic_disable,
.atomic_update = sun8i_ui_layer_atomic_update, .atomic_update = sun8i_ui_layer_atomic_update,
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <drm/drm_crtc_helper.h> #include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_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/drm_plane_helper.h>
#include <drm/drmP.h> #include <drm/drmP.h>
...@@ -336,6 +337,7 @@ static void sun8i_vi_layer_atomic_update(struct drm_plane *plane, ...@@ -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 = { 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_check = sun8i_vi_layer_atomic_check,
.atomic_disable = sun8i_vi_layer_atomic_disable, .atomic_disable = sun8i_vi_layer_atomic_disable,
.atomic_update = sun8i_vi_layer_atomic_update, .atomic_update = sun8i_vi_layer_atomic_update,
......
...@@ -249,7 +249,7 @@ static int tve200_probe(struct platform_device *pdev) ...@@ -249,7 +249,7 @@ static int tve200_probe(struct platform_device *pdev)
clk_disable: clk_disable:
clk_disable_unprepare(priv->pclk); clk_disable_unprepare(priv->pclk);
dev_unref: dev_unref:
drm_dev_unref(drm); drm_dev_put(drm);
return ret; return ret;
} }
...@@ -263,7 +263,7 @@ static int tve200_remove(struct platform_device *pdev) ...@@ -263,7 +263,7 @@ static int tve200_remove(struct platform_device *pdev)
drm_panel_bridge_remove(priv->bridge); drm_panel_bridge_remove(priv->bridge);
drm_mode_config_cleanup(drm); drm_mode_config_cleanup(drm);
clk_disable_unprepare(priv->pclk); clk_disable_unprepare(priv->pclk);
drm_dev_unref(drm); drm_dev_put(drm);
return 0; return 0;
} }
......
...@@ -210,14 +210,11 @@ static void ...@@ -210,14 +210,11 @@ static void
v3d_attach_object_fences(struct v3d_exec_info *exec) v3d_attach_object_fences(struct v3d_exec_info *exec)
{ {
struct dma_fence *out_fence = exec->render_done_fence; struct dma_fence *out_fence = exec->render_done_fence;
struct v3d_bo *bo;
int i; int i;
for (i = 0; i < exec->bo_count; 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. */ /* 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, ...@@ -228,11 +225,8 @@ v3d_unlock_bo_reservations(struct drm_device *dev,
{ {
int i; int i;
for (i = 0; i < exec->bo_count; i++) { for (i = 0; i < exec->bo_count; i++)
struct v3d_bo *bo = to_v3d_bo(&exec->bo[i]->base); ww_mutex_unlock(&exec->bo[i]->resv->lock);
ww_mutex_unlock(&bo->resv->lock);
}
ww_acquire_fini(acquire_ctx); ww_acquire_fini(acquire_ctx);
} }
...@@ -251,13 +245,13 @@ v3d_lock_bo_reservations(struct drm_device *dev, ...@@ -251,13 +245,13 @@ v3d_lock_bo_reservations(struct drm_device *dev,
{ {
int contended_lock = -1; int contended_lock = -1;
int i, ret; int i, ret;
struct v3d_bo *bo;
ww_acquire_init(acquire_ctx, &reservation_ww_class); ww_acquire_init(acquire_ctx, &reservation_ww_class);
retry: retry:
if (contended_lock != -1) { 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, ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock,
acquire_ctx); acquire_ctx);
if (ret) { if (ret) {
...@@ -270,19 +264,16 @@ v3d_lock_bo_reservations(struct drm_device *dev, ...@@ -270,19 +264,16 @@ v3d_lock_bo_reservations(struct drm_device *dev,
if (i == contended_lock) if (i == contended_lock)
continue; continue;
bo = to_v3d_bo(&exec->bo[i]->base); ret = ww_mutex_lock_interruptible(&exec->bo[i]->resv->lock,
acquire_ctx);
ret = ww_mutex_lock_interruptible(&bo->resv->lock, acquire_ctx);
if (ret) { if (ret) {
int j; int j;
for (j = 0; j < i; j++) { for (j = 0; j < i; j++)
bo = to_v3d_bo(&exec->bo[j]->base); ww_mutex_unlock(&exec->bo[j]->resv->lock);
ww_mutex_unlock(&bo->resv->lock);
}
if (contended_lock != -1 && contended_lock >= i) { 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); ww_mutex_unlock(&bo->resv->lock);
} }
...@@ -303,9 +294,7 @@ v3d_lock_bo_reservations(struct drm_device *dev, ...@@ -303,9 +294,7 @@ v3d_lock_bo_reservations(struct drm_device *dev,
* before we commit the CL to the hardware. * before we commit the CL to the hardware.
*/ */
for (i = 0; i < exec->bo_count; i++) { for (i = 0; i < exec->bo_count; i++) {
bo = to_v3d_bo(&exec->bo[i]->base); ret = reservation_object_reserve_shared(exec->bo[i]->resv, 1);
ret = reservation_object_reserve_shared(bo->resv, 1);
if (ret) { if (ret) {
v3d_unlock_bo_reservations(dev, exec, acquire_ctx); v3d_unlock_bo_reservations(dev, exec, acquire_ctx);
return ret; return ret;
......
...@@ -41,7 +41,7 @@ v3d_job_free(struct drm_sched_job *sched_job) ...@@ -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. * v3d_job_run() won't be called until all of them have been signaled.
*/ */
static struct dma_fence * static struct dma_fence *
......
...@@ -169,6 +169,12 @@ static int virtio_gpu_conn_get_modes(struct drm_connector *connector) ...@@ -169,6 +169,12 @@ static int virtio_gpu_conn_get_modes(struct drm_connector *connector)
struct drm_display_mode *mode = NULL; struct drm_display_mode *mode = NULL;
int count, width, height; 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); width = le32_to_cpu(output->info.r.width);
height = le32_to_cpu(output->info.r.height); height = le32_to_cpu(output->info.r.height);
count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX); 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) ...@@ -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_connector_init(dev, connector, &virtio_gpu_connector_funcs,
DRM_MODE_CONNECTOR_VIRTUAL); DRM_MODE_CONNECTOR_VIRTUAL);
drm_connector_helper_add(connector, &virtio_gpu_conn_helper_funcs); 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_encoder_init(dev, encoder, &virtio_gpu_enc_funcs,
DRM_MODE_ENCODER_VIRTUAL, NULL); DRM_MODE_ENCODER_VIRTUAL, NULL);
...@@ -378,6 +386,10 @@ int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev) ...@@ -378,6 +386,10 @@ int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev)
void virtio_gpu_modeset_fini(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); virtio_gpu_fbdev_fini(vgdev);
drm_mode_config_cleanup(vgdev->ddev); drm_mode_config_cleanup(vgdev->ddev);
} }
...@@ -80,6 +80,7 @@ static unsigned int features[] = { ...@@ -80,6 +80,7 @@ static unsigned int features[] = {
*/ */
VIRTIO_GPU_F_VIRGL, VIRTIO_GPU_F_VIRGL,
#endif #endif
VIRTIO_GPU_F_EDID,
}; };
static struct virtio_driver virtio_gpu_driver = { static struct virtio_driver virtio_gpu_driver = {
.feature_table = features, .feature_table = features,
......
...@@ -115,6 +115,7 @@ struct virtio_gpu_output { ...@@ -115,6 +115,7 @@ struct virtio_gpu_output {
struct drm_encoder enc; struct drm_encoder enc;
struct virtio_gpu_display_one info; struct virtio_gpu_display_one info;
struct virtio_gpu_update_cursor cursor; struct virtio_gpu_update_cursor cursor;
struct edid *edid;
int cur_x; int cur_x;
int cur_y; int cur_y;
bool enabled; bool enabled;
...@@ -201,6 +202,7 @@ struct virtio_gpu_device { ...@@ -201,6 +202,7 @@ struct virtio_gpu_device {
struct ida ctx_id_ida; struct ida ctx_id_ida;
bool has_virgl_3d; bool has_virgl_3d;
bool has_edid;
struct work_struct config_changed_work; struct work_struct config_changed_work;
...@@ -291,6 +293,7 @@ int virtio_gpu_cmd_get_capset_info(struct virtio_gpu_device *vgdev, int idx); ...@@ -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 virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev,
int idx, int version, int idx, int version,
struct virtio_gpu_drv_cap_cache **cache_p); 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, void virtio_gpu_cmd_context_create(struct virtio_gpu_device *vgdev, uint32_t id,
uint32_t nlen, const char *name); uint32_t nlen, const char *name);
void virtio_gpu_cmd_context_destroy(struct virtio_gpu_device *vgdev, void virtio_gpu_cmd_context_destroy(struct virtio_gpu_device *vgdev,
......
...@@ -44,6 +44,8 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work) ...@@ -44,6 +44,8 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work)
virtio_cread(vgdev->vdev, struct virtio_gpu_config, virtio_cread(vgdev->vdev, struct virtio_gpu_config,
events_read, &events_read); events_read, &events_read);
if (events_read & VIRTIO_GPU_EVENT_DISPLAY) { if (events_read & VIRTIO_GPU_EVENT_DISPLAY) {
if (vgdev->has_edid)
virtio_gpu_cmd_get_edids(vgdev);
virtio_gpu_cmd_get_display_info(vgdev); virtio_gpu_cmd_get_display_info(vgdev);
drm_helper_hpd_irq_event(vgdev->ddev); drm_helper_hpd_irq_event(vgdev->ddev);
events_clear |= VIRTIO_GPU_EVENT_DISPLAY; events_clear |= VIRTIO_GPU_EVENT_DISPLAY;
...@@ -156,6 +158,10 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -156,6 +158,10 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
#else #else
DRM_INFO("virgl 3d acceleration not supported by guest\n"); DRM_INFO("virgl 3d acceleration not supported by guest\n");
#endif #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); ret = virtio_find_vqs(vgdev->vdev, 2, vqs, callbacks, names, NULL);
if (ret) { if (ret) {
...@@ -201,6 +207,8 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -201,6 +207,8 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
if (num_capsets) if (num_capsets)
virtio_gpu_get_capsets(vgdev, 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); virtio_gpu_cmd_get_display_info(vgdev);
wait_event_timeout(vgdev->resp_wq, !vgdev->display_info_pending, wait_event_timeout(vgdev->resp_wq, !vgdev->display_info_pending,
5 * HZ); 5 * HZ);
......
...@@ -584,6 +584,45 @@ static void virtio_gpu_cmd_capset_cb(struct virtio_gpu_device *vgdev, ...@@ -584,6 +584,45 @@ static void virtio_gpu_cmd_capset_cb(struct virtio_gpu_device *vgdev,
wake_up(&vgdev->resp_wq); 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) int virtio_gpu_cmd_get_display_info(struct virtio_gpu_device *vgdev)
{ {
struct virtio_gpu_ctrl_hdr *cmd_p; struct virtio_gpu_ctrl_hdr *cmd_p;
...@@ -686,6 +725,34 @@ int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev, ...@@ -686,6 +725,34 @@ int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev,
return 0; 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, void virtio_gpu_cmd_context_create(struct virtio_gpu_device *vgdev, uint32_t id,
uint32_t nlen, const char *name) uint32_t nlen, const char *name)
{ {
......
...@@ -68,7 +68,6 @@ static struct drm_driver vkms_driver = { ...@@ -68,7 +68,6 @@ static struct drm_driver vkms_driver = {
.release = vkms_release, .release = vkms_release,
.fops = &vkms_driver_fops, .fops = &vkms_driver_fops,
.dumb_create = vkms_dumb_create, .dumb_create = vkms_dumb_create,
.dumb_map_offset = vkms_dumb_map,
.gem_vm_ops = &vkms_gem_vm_ops, .gem_vm_ops = &vkms_gem_vm_ops,
.gem_free_object_unlocked = vkms_gem_free_object, .gem_free_object_unlocked = vkms_gem_free_object,
.get_vblank_timestamp = vkms_get_vblank_timestamp, .get_vblank_timestamp = vkms_get_vblank_timestamp,
......
...@@ -127,9 +127,6 @@ vm_fault_t vkms_gem_fault(struct vm_fault *vmf); ...@@ -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, int vkms_dumb_create(struct drm_file *file, struct drm_device *dev,
struct drm_mode_create_dumb *args); 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); void vkms_gem_free_object(struct drm_gem_object *obj);
int vkms_gem_vmap(struct drm_gem_object *obj); int vkms_gem_vmap(struct drm_gem_object *obj);
......
...@@ -153,32 +153,6 @@ int vkms_dumb_create(struct drm_file *file, struct drm_device *dev, ...@@ -153,32 +153,6 @@ int vkms_dumb_create(struct drm_file *file, struct drm_device *dev,
return 0; 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) static struct page **_get_pages(struct vkms_gem_object *vkms_obj)
{ {
struct drm_gem_object *gem_obj = &vkms_obj->gem; struct drm_gem_object *gem_obj = &vkms_obj->gem;
......
...@@ -279,7 +279,6 @@ static struct drm_driver driver = { ...@@ -279,7 +279,6 @@ static struct drm_driver driver = {
.gem_free_object_unlocked = vbox_gem_free_object, .gem_free_object_unlocked = vbox_gem_free_object,
.dumb_create = vbox_dumb_create, .dumb_create = vbox_dumb_create,
.dumb_map_offset = vbox_dumb_mmap_offset, .dumb_map_offset = vbox_dumb_mmap_offset,
.dumb_destroy = drm_gem_dumb_destroy,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle, .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_export = drm_gem_prime_export, .gem_prime_export = drm_gem_prime_export,
......
...@@ -1210,30 +1210,6 @@ static inline void drm_connector_put(struct drm_connector *connector) ...@@ -1210,30 +1210,6 @@ static inline void drm_connector_put(struct drm_connector *connector)
drm_mode_object_put(&connector->base); drm_mode_object_put(&connector->base);
} }
/**
* drm_connector_reference - acquire a connector reference
* @connector: DRM connector
*
* This is a compatibility alias for drm_connector_get() and should not be
* used by new code.
*/
static inline void drm_connector_reference(struct drm_connector *connector)
{
drm_connector_get(connector);
}
/**
* drm_connector_unreference - release a connector reference
* @connector: DRM connector
*
* This is a compatibility alias for drm_connector_put() and should not be
* used by new code.
*/
static inline void drm_connector_unreference(struct drm_connector *connector)
{
drm_connector_put(connector);
}
/** /**
* drm_connector_is_unregistered - has the connector been unregistered from * drm_connector_is_unregistered - has the connector been unregistered from
* userspace? * userspace?
......
...@@ -527,8 +527,10 @@ struct drm_driver { ...@@ -527,8 +527,10 @@ struct drm_driver {
* @dumb_map_offset: * @dumb_map_offset:
* *
* Allocate an offset in the drm device node's address space to be able to * Allocate an offset in the drm device node's address space to be able to
* memory map a dumb buffer. GEM-based drivers must use * memory map a dumb buffer.
* drm_gem_create_mmap_offset() to implement this. *
* The default implementation is drm_gem_create_mmap_offset(). GEM based
* drivers must not overwrite this.
* *
* Called by the user via ioctl. * Called by the user via ioctl.
* *
...@@ -548,6 +550,9 @@ struct drm_driver { ...@@ -548,6 +550,9 @@ struct drm_driver {
* *
* Called by the user via ioctl. * Called by the user via ioctl.
* *
* The default implementation is drm_gem_dumb_destroy(). GEM based drivers
* must not overwrite this.
*
* Returns: * Returns:
* *
* Zero on success, negative errno on failure. * Zero on success, negative errno on failure.
...@@ -625,7 +630,6 @@ void drm_dev_unregister(struct drm_device *dev); ...@@ -625,7 +630,6 @@ void drm_dev_unregister(struct drm_device *dev);
void drm_dev_get(struct drm_device *dev); void drm_dev_get(struct drm_device *dev);
void drm_dev_put(struct drm_device *dev); void drm_dev_put(struct drm_device *dev);
void drm_dev_unref(struct drm_device *dev);
void drm_put_dev(struct drm_device *dev); void drm_put_dev(struct drm_device *dev);
bool drm_dev_enter(struct drm_device *dev, int *idx); bool drm_dev_enter(struct drm_device *dev, int *idx);
void drm_dev_exit(int idx); void drm_dev_exit(int idx);
......
...@@ -240,30 +240,6 @@ static inline void drm_framebuffer_put(struct drm_framebuffer *fb) ...@@ -240,30 +240,6 @@ static inline void drm_framebuffer_put(struct drm_framebuffer *fb)
drm_mode_object_put(&fb->base); drm_mode_object_put(&fb->base);
} }
/**
* drm_framebuffer_reference - acquire a framebuffer reference
* @fb: DRM framebuffer
*
* This is a compatibility alias for drm_framebuffer_get() and should not be
* used by new code.
*/
static inline void drm_framebuffer_reference(struct drm_framebuffer *fb)
{
drm_framebuffer_get(fb);
}
/**
* drm_framebuffer_unreference - release a framebuffer reference
* @fb: DRM framebuffer
*
* This is a compatibility alias for drm_framebuffer_put() and should not be
* used by new code.
*/
static inline void drm_framebuffer_unreference(struct drm_framebuffer *fb)
{
drm_framebuffer_put(fb);
}
/** /**
* drm_framebuffer_read_refcount - read the framebuffer reference count. * drm_framebuffer_read_refcount - read the framebuffer reference count.
* @fb: framebuffer * @fb: framebuffer
......
...@@ -348,56 +348,6 @@ __drm_gem_object_put(struct drm_gem_object *obj) ...@@ -348,56 +348,6 @@ __drm_gem_object_put(struct drm_gem_object *obj)
void drm_gem_object_put_unlocked(struct drm_gem_object *obj); void drm_gem_object_put_unlocked(struct drm_gem_object *obj);
void drm_gem_object_put(struct drm_gem_object *obj); void drm_gem_object_put(struct drm_gem_object *obj);
/**
* drm_gem_object_reference - acquire a GEM buffer object reference
* @obj: GEM buffer object
*
* This is a compatibility alias for drm_gem_object_get() and should not be
* used by new code.
*/
static inline void drm_gem_object_reference(struct drm_gem_object *obj)
{
drm_gem_object_get(obj);
}
/**
* __drm_gem_object_unreference - raw function to release a GEM buffer object
* reference
* @obj: GEM buffer object
*
* This is a compatibility alias for __drm_gem_object_put() and should not be
* used by new code.
*/
static inline void __drm_gem_object_unreference(struct drm_gem_object *obj)
{
__drm_gem_object_put(obj);
}
/**
* drm_gem_object_unreference_unlocked - release a GEM buffer object reference
* @obj: GEM buffer object
*
* This is a compatibility alias for drm_gem_object_put_unlocked() and should
* not be used by new code.
*/
static inline void
drm_gem_object_unreference_unlocked(struct drm_gem_object *obj)
{
drm_gem_object_put_unlocked(obj);
}
/**
* drm_gem_object_unreference - release a GEM buffer object reference
* @obj: GEM buffer object
*
* This is a compatibility alias for drm_gem_object_put() and should not be
* used by new code.
*/
static inline void drm_gem_object_unreference(struct drm_gem_object *obj)
{
drm_gem_object_put(obj);
}
int drm_gem_handle_create(struct drm_file *file_priv, int drm_gem_handle_create(struct drm_file *file_priv,
struct drm_gem_object *obj, struct drm_gem_object *obj,
u32 *handlep); u32 *handlep);
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include <linux/types.h> #include <linux/types.h>
#define VIRTIO_GPU_F_VIRGL 0 #define VIRTIO_GPU_F_VIRGL 0
#define VIRTIO_GPU_F_EDID 1
enum virtio_gpu_ctrl_type { enum virtio_gpu_ctrl_type {
VIRTIO_GPU_UNDEFINED = 0, VIRTIO_GPU_UNDEFINED = 0,
...@@ -56,6 +57,7 @@ enum virtio_gpu_ctrl_type { ...@@ -56,6 +57,7 @@ enum virtio_gpu_ctrl_type {
VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING, VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING,
VIRTIO_GPU_CMD_GET_CAPSET_INFO, VIRTIO_GPU_CMD_GET_CAPSET_INFO,
VIRTIO_GPU_CMD_GET_CAPSET, VIRTIO_GPU_CMD_GET_CAPSET,
VIRTIO_GPU_CMD_GET_EDID,
/* 3d commands */ /* 3d commands */
VIRTIO_GPU_CMD_CTX_CREATE = 0x0200, VIRTIO_GPU_CMD_CTX_CREATE = 0x0200,
...@@ -76,6 +78,7 @@ enum virtio_gpu_ctrl_type { ...@@ -76,6 +78,7 @@ enum virtio_gpu_ctrl_type {
VIRTIO_GPU_RESP_OK_DISPLAY_INFO, VIRTIO_GPU_RESP_OK_DISPLAY_INFO,
VIRTIO_GPU_RESP_OK_CAPSET_INFO, VIRTIO_GPU_RESP_OK_CAPSET_INFO,
VIRTIO_GPU_RESP_OK_CAPSET, VIRTIO_GPU_RESP_OK_CAPSET,
VIRTIO_GPU_RESP_OK_EDID,
/* error responses */ /* error responses */
VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200, VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200,
...@@ -291,6 +294,21 @@ struct virtio_gpu_resp_capset { ...@@ -291,6 +294,21 @@ struct virtio_gpu_resp_capset {
__u8 capset_data[]; __u8 capset_data[];
}; };
/* VIRTIO_GPU_CMD_GET_EDID */
struct virtio_gpu_cmd_get_edid {
struct virtio_gpu_ctrl_hdr hdr;
__le32 scanout;
__le32 padding;
};
/* VIRTIO_GPU_RESP_OK_EDID */
struct virtio_gpu_resp_edid {
struct virtio_gpu_ctrl_hdr hdr;
__le32 size;
__le32 padding;
__u8 edid[1024];
};
#define VIRTIO_GPU_EVENT_DISPLAY (1 << 0) #define VIRTIO_GPU_EVENT_DISPLAY (1 << 0)
struct virtio_gpu_config { struct virtio_gpu_config {
......
// SPDX-License-Identifier: GPL-2.0
///
/// Use drm_*_get() and drm_*_put() helpers instead of drm_*_reference() and
/// drm_*_unreference() helpers.
///
// Confidence: High
// Copyright: (C) 2017 NVIDIA Corporation
// Options: --no-includes --include-headers
//
virtual patch
virtual report
@depends on patch@
expression object;
@@
(
- drm_connector_reference(object)
+ drm_connector_get(object)
|
- drm_connector_unreference(object)
+ drm_connector_put(object)
|
- drm_framebuffer_reference(object)
+ drm_framebuffer_get(object)
|
- drm_framebuffer_unreference(object)
+ drm_framebuffer_put(object)
|
- drm_gem_object_reference(object)
+ drm_gem_object_get(object)
|
- drm_gem_object_unreference(object)
+ drm_gem_object_put(object)
|
- __drm_gem_object_unreference(object)
+ __drm_gem_object_put(object)
|
- drm_gem_object_unreference_unlocked(object)
+ drm_gem_object_put_unlocked(object)
|
- drm_dev_unref(object)
+ drm_dev_put(object)
)
@r depends on report@
expression object;
position p;
@@
(
drm_connector_unreference@p(object)
|
drm_connector_reference@p(object)
|
drm_framebuffer_unreference@p(object)
|
drm_framebuffer_reference@p(object)
|
drm_gem_object_unreference@p(object)
|
drm_gem_object_reference@p(object)
|
__drm_gem_object_unreference(object)
|
drm_gem_object_unreference_unlocked(object)
|
drm_dev_unref@p(object)
)
@script:python depends on report@
object << r.object;
p << r.p;
@@
msg="WARNING: use get/put helpers to reference and dereference %s" % (object)
coccilib.report.print_report(p[0], msg)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment