summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2018-09-14 09:43:06 +1000
committerDave Airlie <airlied@redhat.com>2018-09-14 09:43:16 +1000
commit2dc7bad71cd310dc94d1c9907909324dd2b0618f (patch)
treea087555dd4b1588eeac02c1af5d8dde7b5bb15fa
parentb1c1566822ab489a945dfdafee651aa29de160c7 (diff)
parent169cc4c7a14e988985c8833ddec2f3e897de2c28 (diff)
Merge tag 'drm-misc-next-2018-09-13' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for 4.20: UAPI Changes: - Add host endian variants for the most common formats (Gerd) - Fail ADDFB2 for big-endian drivers that don't advertise BE quirk (Gerd) - clear smem_start in fbdev for drm drivers to avoid leaking fb addr (Daniel) Cross-subsystem Changes: Core Changes: - fix drm_mode_addfb() on big endian machines (Gerd) - add timeline point to syncobj find+replace (Chunming) - more drmP.h removal effort (Daniel) - split uapi portions of drm_atomic.c into drm_atomic_uapi.c (Daniel) Driver Changes: - bochs: Convert open-coded portions to use helpers (Peter) - vkms: Add cursor support (Haneen) - udmabuf: Lots of fixups (mostly cosmetic afaict) (Gerd) - qxl: Convert to use fbdev helper (Peter) Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: Chunming Zhou <david1.zhou@amd.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Peter Wu <peter@lekensteyn.nl> Cc: Haneen Mohammed <hamohammed.sa@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> From: Sean Paul <sean@poorly.run> Link: https://patchwork.freedesktop.org/patch/msgid/20180913130254.GA156437@art_vandelay
-rw-r--r--Documentation/gpu/drivers.rst1
-rw-r--r--Documentation/gpu/drm-kms.rst12
-rw-r--r--Documentation/gpu/todo.rst71
-rw-r--r--Documentation/gpu/vkms.rst24
-rw-r--r--drivers/dma-buf/Kconfig1
-rw-r--r--drivers/dma-buf/udmabuf.c93
-rw-r--r--drivers/gpu/drm/Makefile3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c4
-rw-r--r--drivers/gpu/drm/armada/armada_overlay.c1
-rw-r--r--drivers/gpu/drm/bochs/bochs.h21
-rw-r--r--drivers/gpu/drm/bochs/bochs_drv.c46
-rw-r--r--drivers/gpu/drm/bochs/bochs_fbdev.c79
-rw-r--r--drivers/gpu/drm/bochs/bochs_hw.c2
-rw-r--r--drivers/gpu/drm/bochs/bochs_kms.c7
-rw-r--r--drivers/gpu/drm/bochs/bochs_mm.c74
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix_dp_core.c4
-rw-r--r--drivers/gpu/drm/drm_atomic.c1510
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c1
-rw-r--r--drivers/gpu/drm/drm_atomic_uapi.c1393
-rw-r--r--drivers/gpu/drm/drm_blend.c22
-rw-r--r--drivers/gpu/drm/drm_bridge.c4
-rw-r--r--drivers/gpu/drm/drm_connector.c6
-rw-r--r--drivers/gpu/drm/drm_crtc.c5
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c1
-rw-r--r--drivers/gpu/drm/drm_crtc_internal.h19
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c26
-rw-r--r--drivers/gpu/drm/drm_fourcc.c37
-rw-r--r--drivers/gpu/drm/drm_framebuffer.c49
-rw-r--r--drivers/gpu/drm/drm_gem_framebuffer_helper.c1
-rw-r--r--drivers/gpu/drm/drm_internal.h5
-rw-r--r--drivers/gpu/drm/drm_ioctl.c2
-rw-r--r--drivers/gpu/drm/drm_plane.c13
-rw-r--r--drivers/gpu/drm/drm_plane_helper.c1
-rw-r--r--drivers/gpu/drm/drm_syncobj.c73
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h1
-rw-r--r--drivers/gpu/drm/i915/i915_gem_execbuffer.c2
-rw-r--r--drivers/gpu/drm/i915/intel_display.c1
-rw-r--r--drivers/gpu/drm/i915/intel_display.h2
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.h2
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c2
-rw-r--r--drivers/gpu/drm/msm/msm_atomic.c2
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/disp.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c1
-rw-r--r--drivers/gpu/drm/qxl/qxl_display.c101
-rw-r--r--drivers/gpu/drm/qxl/qxl_draw.c6
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.h32
-rw-r--r--drivers/gpu/drm/qxl/qxl_fb.c197
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_drv.c6
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_tcon.c90
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_tcon.h27
-rw-r--r--drivers/gpu/drm/v3d/v3d_gem.c6
-rw-r--r--drivers/gpu/drm/vc4/vc4_crtc.c1
-rw-r--r--drivers/gpu/drm/vc4/vc4_gem.c4
-rw-r--r--drivers/gpu/drm/vc4/vc4_plane.c1
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_display.c3
-rw-r--r--drivers/gpu/drm/vkms/vkms_crc.c154
-rw-r--r--drivers/gpu/drm/vkms/vkms_drv.c13
-rw-r--r--drivers/gpu/drm/vkms/vkms_drv.h18
-rw-r--r--drivers/gpu/drm/vkms/vkms_output.c19
-rw-r--r--drivers/gpu/drm/vkms/vkms_plane.c43
-rw-r--r--drivers/staging/vboxvideo/vbox_fb.c3
-rw-r--r--drivers/tty/vt/vt.c12
-rw-r--r--drivers/video/fbdev/core/fbcon.c4
-rw-r--r--drivers/video/fbdev/core/fbmem.c8
-rw-r--r--include/drm/drmP.h3
-rw-r--r--include/drm/drm_atomic.h23
-rw-r--r--include/drm/drm_atomic_helper.h1
-rw-r--r--include/drm/drm_atomic_uapi.h58
-rw-r--r--include/drm/drm_color_mgmt.h1
-rw-r--r--include/drm/drm_connector.h1
-rw-r--r--include/drm/drm_drv.h1
-rw-r--r--include/drm/drm_encoder.h1
-rw-r--r--include/drm/drm_fb_helper.h22
-rw-r--r--include/drm/drm_fourcc.h22
-rw-r--r--include/drm/drm_mode_config.h15
-rw-r--r--include/drm/drm_plane.h3
-rw-r--r--include/drm/drm_property.h2
-rw-r--r--include/drm/drm_syncobj.h4
-rw-r--r--include/drm/drm_util.h32
-rw-r--r--include/linux/console_struct.h1
-rw-r--r--include/linux/fb.h9
-rw-r--r--include/linux/vt_kern.h7
-rw-r--r--include/uapi/drm/drm_fourcc.h3
-rw-r--r--include/uapi/drm/drm_mode.h3
85 files changed, 2327 insertions, 2261 deletions
diff --git a/Documentation/gpu/drivers.rst b/Documentation/gpu/drivers.rst
index 65be325bf282..7d2d3875ff1a 100644
--- a/Documentation/gpu/drivers.rst
+++ b/Documentation/gpu/drivers.rst
@@ -13,6 +13,7 @@ GPU Driver Documentation
tve200
v3d
vc4
+ vkms
bridge/dw-hdmi
xen-front
diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst
index f8f5bf11a6ca..4b1501b4835b 100644
--- a/Documentation/gpu/drm-kms.rst
+++ b/Documentation/gpu/drm-kms.rst
@@ -287,8 +287,14 @@ Atomic Mode Setting Function Reference
.. kernel-doc:: drivers/gpu/drm/drm_atomic.c
:export:
-.. kernel-doc:: drivers/gpu/drm/drm_atomic.c
- :internal:
+Atomic Mode Setting IOCTL and UAPI Functions
+--------------------------------------------
+
+.. kernel-doc:: drivers/gpu/drm/drm_atomic_uapi.c
+ :doc: overview
+
+.. kernel-doc:: drivers/gpu/drm/drm_atomic_uapi.c
+ :export:
CRTC Abstraction
================
@@ -566,7 +572,7 @@ Tile Group Property
Explicit Fencing Properties
---------------------------
-.. kernel-doc:: drivers/gpu/drm/drm_atomic.c
+.. kernel-doc:: drivers/gpu/drm/drm_atomic_uapi.c
:doc: explicit fencing properties
Existing KMS Properties
diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst
index a7c150d6b63f..77c2b3c25565 100644
--- a/Documentation/gpu/todo.rst
+++ b/Documentation/gpu/todo.rst
@@ -127,7 +127,8 @@ interfaces to fix these issues:
the acquire context explicitly on stack and then also pass it down into
drivers explicitly so that the legacy-on-atomic functions can use them.
- Except for some driver code this is done.
+ Except for some driver code this is done. This task should be finished by
+ adding WARN_ON(!drm_drv_uses_atomic_modeset) in drm_modeset_lock_all().
* A bunch of the vtable hooks are now in the wrong place: DRM has a split
between core vfunc tables (named ``drm_foo_funcs``), which are used to
@@ -137,13 +138,6 @@ interfaces to fix these issues:
``_helper_funcs`` since they are not part of the core ABI. There's a
``FIXME`` comment in the kerneldoc for each such case in ``drm_crtc.h``.
-* There's a new helper ``drm_atomic_helper_best_encoder()`` which could be
- used by all atomic drivers which don't select the encoder for a given
- connector at runtime. That's almost all of them, and would allow us to get
- rid of a lot of ``best_encoder`` boilerplate in drivers.
-
- This was almost done, but new drivers added a few more cases again.
-
Contact: Daniel Vetter
Get rid of dev->struct_mutex from GEM drivers
@@ -164,9 +158,8 @@ private lock. The tricky part is the BO free functions, since those can't
reliably take that lock any more. Instead state needs to be protected with
suitable subordinate locks or some cleanup work pushed to a worker thread. For
performance-critical drivers it might also be better to go with a more
-fine-grained per-buffer object and per-context lockings scheme. Currently the
-following drivers still use ``struct_mutex``: ``msm``, ``omapdrm`` and
-``udl``.
+fine-grained per-buffer object and per-context lockings scheme. Currently only the
+``msm`` driver still use ``struct_mutex``.
Contact: Daniel Vetter, respective driver maintainers
@@ -190,7 +183,8 @@ Convert drivers to use simple modeset suspend/resume
Most drivers (except i915 and nouveau) that use
drm_atomic_helper_suspend/resume() can probably be converted to use
-drm_mode_config_helper_suspend/resume().
+drm_mode_config_helper_suspend/resume(). Also there's still open-coded version
+of the atomic suspend/resume code in older atomic modeset drivers.
Contact: Maintainer of the driver you plan to convert
@@ -246,20 +240,10 @@ Core refactorings
Clean up the DRM header mess
----------------------------
-Currently the DRM subsystem has only one global header, ``drmP.h``. This is
-used both for functions exported to helper libraries and drivers and functions
-only used internally in the ``drm.ko`` module. The goal would be to move all
-header declarations not needed outside of ``drm.ko`` into
-``drivers/gpu/drm/drm_*_internal.h`` header files. ``EXPORT_SYMBOL`` also
-needs to be dropped for these functions.
-
-This would nicely tie in with the below task to create kerneldoc after the API
-is cleaned up. Or with the "hide legacy cruft better" task.
-
-Note that this is well in progress, but ``drmP.h`` is still huge. The updated
-plan is to switch to per-file driver API headers, which will also structure
-the kerneldoc better. This should also allow more fine-grained ``#include``
-directives.
+The DRM subsystem originally had only one huge global header, ``drmP.h``. This
+is now split up, but many source files still include it. The remaining part of
+the cleanup work here is to replace any ``#include <drm/drmP.h>`` by only the
+headers needed (and fixing up any missing pre-declarations in the headers).
In the end no .c file should need to include ``drmP.h`` anymore.
@@ -278,26 +262,6 @@ See https://dri.freedesktop.org/docs/drm/ for what's there already.
Contact: Daniel Vetter
-Hide legacy cruft better
-------------------------
-
-Way back DRM supported only drivers which shadow-attached to PCI devices with
-userspace or fbdev drivers setting up outputs. Modern DRM drivers take charge
-of the entire device, you can spot them with the DRIVER_MODESET flag.
-
-Unfortunately there's still large piles of legacy code around which needs to
-be hidden so that driver writers don't accidentally end up using it. And to
-prevent security issues in those legacy IOCTLs from being exploited on modern
-drivers. This has multiple possible subtasks:
-
-* Extract support code for legacy features into a ``drm-legacy.ko`` kernel
- module and compile it only when one of the legacy drivers is enabled.
-
-This is mostly done, the only thing left is to split up ``drm_irq.c`` into
-legacy cruft and the parts needed by modern KMS drivers.
-
-Contact: Daniel Vetter
-
Make panic handling work
------------------------
@@ -396,17 +360,12 @@ converting things over. For modeset tests we also first need a bit of
infrastructure to use dumb buffers for untiled buffers, to be able to run all
the non-i915 specific modeset tests.
-Contact: Daniel Vetter
-
-Create a virtual KMS driver for testing (vkms)
-----------------------------------------------
-
-With all the latest helpers it should be fairly simple to create a virtual KMS
-driver useful for testing, or for running X or similar on headless machines
-(to be able to still use the GPU). This would be similar to vgem, but aimed at
-the modeset side.
+Extend virtual test driver (VKMS)
+---------------------------------
-Once the basics are there there's tons of possibilities to extend it.
+See the documentation of :ref:`VKMS <vkms>` for more details. This is an ideal
+internship task, since it only requires a virtual machine and can be sized to
+fit the available time.
Contact: Daniel Vetter
diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
new file mode 100644
index 000000000000..0a6ea6216e41
--- /dev/null
+++ b/Documentation/gpu/vkms.rst
@@ -0,0 +1,24 @@
+.. _vkms:
+
+==========================================
+ drm/vkms Virtual Kernel Modesetting
+==========================================
+
+.. kernel-doc:: drivers/gpu/drm/vkms/vkms_drv.c
+ :doc: vkms (Virtual Kernel Modesetting)
+
+TODO
+====
+
+CRC API
+-------
+
+- Optimize CRC computation ``compute_crc()`` and plane blending ``blend()``
+
+- Use the alpha value to blend vaddr_src with vaddr_dst instead of
+ overwriting it in ``blend()``.
+
+- Add igt test to check cleared alpha value for XRGB plane format.
+
+- Add igt test to check extreme alpha values i.e. fully opaque and fully
+ transparent (intermediate values are affected by hw-specific rounding modes).
diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig
index 338129eb126f..2e5a0faa2cb1 100644
--- a/drivers/dma-buf/Kconfig
+++ b/drivers/dma-buf/Kconfig
@@ -34,6 +34,7 @@ config UDMABUF
bool "userspace dmabuf misc driver"
default n
depends on DMA_SHARED_BUFFER
+ depends on MEMFD_CREATE || COMPILE_TEST
help
A driver to let userspace turn memfd regions into dma-bufs.
Qemu can use this to create host dmabufs for guest framebuffers.
diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c
index 2e8502250afe..9edabce0b8ab 100644
--- a/drivers/dma-buf/udmabuf.c
+++ b/drivers/dma-buf/udmabuf.c
@@ -1,20 +1,22 @@
// SPDX-License-Identifier: GPL-2.0
-#include <linux/init.h>
-#include <linux/module.h>
+#include <linux/cred.h>
#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/miscdevice.h>
#include <linux/dma-buf.h>
#include <linux/highmem.h>
-#include <linux/cred.h>
-#include <linux/shmem_fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
#include <linux/memfd.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/shmem_fs.h>
+#include <linux/slab.h>
+#include <linux/udmabuf.h>
-#include <uapi/linux/udmabuf.h>
+static const u32 list_limit = 1024; /* udmabuf_create_list->count limit */
+static const size_t size_limit_mb = 64; /* total dmabuf size, in megabytes */
struct udmabuf {
- u32 pagecount;
+ pgoff_t pagecount;
struct page **pages;
};
@@ -23,9 +25,6 @@ static int udmabuf_vm_fault(struct vm_fault *vmf)
struct vm_area_struct *vma = vmf->vma;
struct udmabuf *ubuf = vma->vm_private_data;
- if (WARN_ON(vmf->pgoff >= ubuf->pagecount))
- return VM_FAULT_SIGBUS;
-
vmf->page = ubuf->pages[vmf->pgoff];
get_page(vmf->page);
return 0;
@@ -52,25 +51,24 @@ static struct sg_table *map_udmabuf(struct dma_buf_attachment *at,
{
struct udmabuf *ubuf = at->dmabuf->priv;
struct sg_table *sg;
+ int ret;
sg = kzalloc(sizeof(*sg), GFP_KERNEL);
if (!sg)
- goto err1;
- if (sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount,
- 0, ubuf->pagecount << PAGE_SHIFT,
- GFP_KERNEL) < 0)
- goto err2;
+ return ERR_PTR(-ENOMEM);
+ ret = sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount,
+ 0, ubuf->pagecount << PAGE_SHIFT,
+ GFP_KERNEL);
+ if (ret < 0)
+ goto err;
if (!dma_map_sg(at->dev, sg->sgl, sg->nents, direction))
- goto err3;
-
+ goto err;
return sg;
-err3:
+err:
sg_free_table(sg);
-err2:
kfree(sg);
-err1:
- return ERR_PTR(-ENOMEM);
+ return ERR_PTR(ret);
}
static void unmap_udmabuf(struct dma_buf_attachment *at,
@@ -106,7 +104,7 @@ static void kunmap_udmabuf(struct dma_buf *buf, unsigned long page_num,
kunmap(vaddr);
}
-static struct dma_buf_ops udmabuf_ops = {
+static const struct dma_buf_ops udmabuf_ops = {
.map_dma_buf = map_udmabuf,
.unmap_dma_buf = unmap_udmabuf,
.release = release_udmabuf,
@@ -118,48 +116,54 @@ static struct dma_buf_ops udmabuf_ops = {
#define SEALS_WANTED (F_SEAL_SHRINK)
#define SEALS_DENIED (F_SEAL_WRITE)
-static long udmabuf_create(struct udmabuf_create_list *head,
- struct udmabuf_create_item *list)
+static long udmabuf_create(const struct udmabuf_create_list *head,
+ const struct udmabuf_create_item *list)
{
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
struct file *memfd = NULL;
struct udmabuf *ubuf;
struct dma_buf *buf;
- pgoff_t pgoff, pgcnt, pgidx, pgbuf;
+ pgoff_t pgoff, pgcnt, pgidx, pgbuf = 0, pglimit;
struct page *page;
int seals, ret = -EINVAL;
u32 i, flags;
- ubuf = kzalloc(sizeof(struct udmabuf), GFP_KERNEL);
+ ubuf = kzalloc(sizeof(*ubuf), GFP_KERNEL);
if (!ubuf)
return -ENOMEM;
+ pglimit = (size_limit_mb * 1024 * 1024) >> PAGE_SHIFT;
for (i = 0; i < head->count; i++) {
if (!IS_ALIGNED(list[i].offset, PAGE_SIZE))
- goto err_free_ubuf;
+ goto err;
if (!IS_ALIGNED(list[i].size, PAGE_SIZE))
- goto err_free_ubuf;
+ goto err;
ubuf->pagecount += list[i].size >> PAGE_SHIFT;
+ if (ubuf->pagecount > pglimit)
+ goto err;
}
- ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(struct page *),
+ ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(*ubuf->pages),
GFP_KERNEL);
if (!ubuf->pages) {
ret = -ENOMEM;
- goto err_free_ubuf;
+ goto err;
}
pgbuf = 0;
for (i = 0; i < head->count; i++) {
+ ret = -EBADFD;
memfd = fget(list[i].memfd);
if (!memfd)
- goto err_put_pages;
+ goto err;
if (!shmem_mapping(file_inode(memfd)->i_mapping))
- goto err_put_pages;
+ goto err;
seals = memfd_fcntl(memfd, F_GET_SEALS, 0);
- if (seals == -EINVAL ||
- (seals & SEALS_WANTED) != SEALS_WANTED ||
+ if (seals == -EINVAL)
+ goto err;
+ ret = -EINVAL;
+ if ((seals & SEALS_WANTED) != SEALS_WANTED ||
(seals & SEALS_DENIED) != 0)
- goto err_put_pages;
+ goto err;
pgoff = list[i].offset >> PAGE_SHIFT;
pgcnt = list[i].size >> PAGE_SHIFT;
for (pgidx = 0; pgidx < pgcnt; pgidx++) {
@@ -167,13 +171,13 @@ static long udmabuf_create(struct udmabuf_create_list *head,
file_inode(memfd)->i_mapping, pgoff + pgidx);
if (IS_ERR(page)) {
ret = PTR_ERR(page);
- goto err_put_pages;
+ goto err;
}
ubuf->pages[pgbuf++] = page;
}
fput(memfd);
+ memfd = NULL;
}
- memfd = NULL;
exp_info.ops = &udmabuf_ops;
exp_info.size = ubuf->pagecount << PAGE_SHIFT;
@@ -182,7 +186,7 @@ static long udmabuf_create(struct udmabuf_create_list *head,
buf = dma_buf_export(&exp_info);
if (IS_ERR(buf)) {
ret = PTR_ERR(buf);
- goto err_put_pages;
+ goto err;
}
flags = 0;
@@ -190,10 +194,9 @@ static long udmabuf_create(struct udmabuf_create_list *head,
flags |= O_CLOEXEC;
return dma_buf_fd(buf, flags);
-err_put_pages:
+err:
while (pgbuf > 0)
put_page(ubuf->pages[--pgbuf]);
-err_free_ubuf:
if (memfd)
fput(memfd);
kfree(ubuf->pages);
@@ -208,7 +211,7 @@ static long udmabuf_ioctl_create(struct file *filp, unsigned long arg)
struct udmabuf_create_item list;
if (copy_from_user(&create, (void __user *)arg,
- sizeof(struct udmabuf_create)))
+ sizeof(create)))
return -EFAULT;
head.flags = create.flags;
@@ -229,7 +232,7 @@ static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg)
if (copy_from_user(&head, (void __user *)arg, sizeof(head)))
return -EFAULT;
- if (head.count > 1024)
+ if (head.count > list_limit)
return -EINVAL;
lsize = sizeof(struct udmabuf_create_item) * head.count;
list = memdup_user((void __user *)(arg + sizeof(head)), lsize);
@@ -254,7 +257,7 @@ static long udmabuf_ioctl(struct file *filp, unsigned int ioctl,
ret = udmabuf_ioctl_create_list(filp, arg);
break;
default:
- ret = -EINVAL;
+ ret = -ENOTTY;
break;
}
return ret;
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index a6771cef85e2..bc6a16a3c36e 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -18,7 +18,8 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \
drm_encoder.o drm_mode_object.o drm_property.o \
drm_plane.o drm_color_mgmt.o drm_print.o \
drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \
- drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o
+ drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o \
+ drm_atomic_uapi.o
drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o
drm-$(CONFIG_DRM_VM) += drm_vm.o
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index b6e9df11115d..8f05e28607e9 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -1098,7 +1098,7 @@ static int amdgpu_syncobj_lookup_and_add_to_sync(struct amdgpu_cs_parser *p,
{
int r;
struct dma_fence *fence;
- r = drm_syncobj_find_fence(p->filp, handle, &fence);
+ r = drm_syncobj_find_fence(p->filp, handle, 0, &fence);
if (r)
return r;
@@ -1187,7 +1187,7 @@ static void amdgpu_cs_post_dependencies(struct amdgpu_cs_parser *p)
int i;
for (i = 0; i < p->num_post_dep_syncobjs; ++i)
- drm_syncobj_replace_fence(p->post_dep_syncobjs[i], p->fence);
+ drm_syncobj_replace_fence(p->post_dep_syncobjs[i], 0, p->fence);
}
static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c
index eb7dfb65ef47..8d770641fcc4 100644
--- a/drivers/gpu/drm/armada/armada_overlay.c
+++ b/drivers/gpu/drm/armada/armada_overlay.c
@@ -8,6 +8,7 @@
*/
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_uapi.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_plane_helper.h>
#include <drm/armada_drm.h>
diff --git a/drivers/gpu/drm/bochs/bochs.h b/drivers/gpu/drm/bochs/bochs.h
index 375bf92cd04f..b4f6bb521900 100644
--- a/drivers/gpu/drm/bochs/bochs.h
+++ b/drivers/gpu/drm/bochs/bochs.h
@@ -51,11 +51,6 @@ enum bochs_types {
BOCHS_UNKNOWN,
};
-struct bochs_framebuffer {
- struct drm_framebuffer base;
- struct drm_gem_object *obj;
-};
-
struct bochs_device {
/* hw */
void __iomem *mmio;
@@ -88,15 +83,11 @@ struct bochs_device {
/* fbdev */
struct {
- struct bochs_framebuffer gfb;
+ struct drm_framebuffer *fb;
struct drm_fb_helper helper;
- int size;
- bool initialized;
} fb;
};
-#define to_bochs_framebuffer(x) container_of(x, struct bochs_framebuffer, base)
-
struct bochs_bo {
struct ttm_buffer_object bo;
struct ttm_placement placement;
@@ -126,7 +117,7 @@ static inline u64 bochs_bo_mmap_offset(struct bochs_bo *bo)
/* ---------------------------------------------------------------------- */
/* bochs_hw.c */
-int bochs_hw_init(struct drm_device *dev, uint32_t flags);
+int bochs_hw_init(struct drm_device *dev);
void bochs_hw_fini(struct drm_device *dev);
void bochs_hw_setmode(struct bochs_device *bochs,
@@ -148,15 +139,9 @@ int bochs_dumb_create(struct drm_file *file, struct drm_device *dev,
int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
uint32_t handle, uint64_t *offset);
-int bochs_framebuffer_init(struct drm_device *dev,
- struct bochs_framebuffer *gfb,
- const struct drm_mode_fb_cmd2 *mode_cmd,
- struct drm_gem_object *obj);
int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag, u64 *gpu_addr);
int bochs_bo_unpin(struct bochs_bo *bo);
-extern const struct drm_mode_config_funcs bochs_mode_funcs;
-
/* bochs_kms.c */
int bochs_kms_init(struct bochs_device *bochs);
void bochs_kms_fini(struct bochs_device *bochs);
@@ -164,3 +149,5 @@ void bochs_kms_fini(struct bochs_device *bochs);
/* bochs_fbdev.c */
int bochs_fbdev_init(struct bochs_device *bochs);
void bochs_fbdev_fini(struct bochs_device *bochs);
+
+extern const struct drm_mode_config_funcs bochs_mode_funcs;
diff --git a/drivers/gpu/drm/bochs/bochs_drv.c b/drivers/gpu/drm/bochs/bochs_drv.c
index c61b40c72b62..f3dd66ae990a 100644
--- a/drivers/gpu/drm/bochs/bochs_drv.c
+++ b/drivers/gpu/drm/bochs/bochs_drv.c
@@ -35,7 +35,7 @@ static void bochs_unload(struct drm_device *dev)
dev->dev_private = NULL;
}
-static int bochs_load(struct drm_device *dev, unsigned long flags)
+static int bochs_load(struct drm_device *dev)
{
struct bochs_device *bochs;
int ret;
@@ -46,7 +46,7 @@ static int bochs_load(struct drm_device *dev, unsigned long flags)
dev->dev_private = bochs;
bochs->dev = dev;
- ret = bochs_hw_init(dev, flags);
+ ret = bochs_hw_init(dev);
if (ret)
goto err;
@@ -82,8 +82,6 @@ static const struct file_operations bochs_fops = {
static struct drm_driver bochs_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET,
- .load = bochs_load,
- .unload = bochs_unload,
.fops = &bochs_fops,
.name = "bochs-drm",
.desc = "bochs dispi vga interface (qemu stdvga)",
@@ -107,11 +105,7 @@ static int bochs_pm_suspend(struct device *dev)
drm_kms_helper_poll_disable(drm_dev);
- if (bochs->fb.initialized) {
- console_lock();
- drm_fb_helper_set_suspend(&bochs->fb.helper, 1);
- console_unlock();
- }
+ drm_fb_helper_set_suspend_unlocked(&bochs->fb.helper, 1);
return 0;
}
@@ -124,11 +118,7 @@ static int bochs_pm_resume(struct device *dev)
drm_helper_resume_force_mode(drm_dev);
- if (bochs->fb.initialized) {
- console_lock();
- drm_fb_helper_set_suspend(&bochs->fb.helper, 0);
- console_unlock();
- }
+ drm_fb_helper_set_suspend_unlocked(&bochs->fb.helper, 0);
drm_kms_helper_poll_enable(drm_dev);
return 0;
@@ -146,6 +136,7 @@ static const struct dev_pm_ops bochs_pm_ops = {
static int bochs_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
+ struct drm_device *dev;
unsigned long fbsize;
int ret;
@@ -159,14 +150,37 @@ static int bochs_pci_probe(struct pci_dev *pdev,
if (ret)
return ret;
- return drm_get_pci_dev(pdev, ent, &bochs_driver);
+ dev = drm_dev_alloc(&bochs_driver, &pdev->dev);
+ if (IS_ERR(dev))
+ return PTR_ERR(dev);
+
+ dev->pdev = pdev;
+ pci_set_drvdata(pdev, dev);
+
+ ret = bochs_load(dev);
+ if (ret)
+ goto err_free_dev;
+
+ ret = drm_dev_register(dev, 0);
+ if (ret)
+ goto err_unload;
+
+ return ret;
+
+err_unload:
+ bochs_unload(dev);
+err_free_dev:
+ drm_dev_put(dev);
+ return ret;
}
static void bochs_pci_remove(struct pci_dev *pdev)
{
struct drm_device *dev = pci_get_drvdata(pdev);
- drm_put_dev(dev);
+ drm_dev_unregister(dev);
+ bochs_unload(dev);
+ drm_dev_put(dev);
}
static const struct pci_device_id bochs_pci_tbl[] = {
diff --git a/drivers/gpu/drm/bochs/bochs_fbdev.c b/drivers/gpu/drm/bochs/bochs_fbdev.c
index 14eb8d0d5a00..8f4d6c052f7b 100644
--- a/drivers/gpu/drm/bochs/bochs_fbdev.c
+++ b/drivers/gpu/drm/bochs/bochs_fbdev.c
@@ -6,6 +6,7 @@
*/
#include "bochs.h"
+#include <drm/drm_gem_framebuffer_helper.h>
/* ---------------------------------------------------------------------- */
@@ -13,9 +14,7 @@ static int bochsfb_mmap(struct fb_info *info,
struct vm_area_struct *vma)
{
struct drm_fb_helper *fb_helper = info->par;
- struct bochs_device *bochs =
- container_of(fb_helper, struct bochs_device, fb.helper);
- struct bochs_bo *bo = gem_to_bochs_bo(bochs->fb.gfb.obj);
+ struct bochs_bo *bo = gem_to_bochs_bo(fb_helper->fb->obj[0]);
return ttm_fbdev_mmap(vma, &bo->bo);
}
@@ -101,19 +100,20 @@ static int bochsfb_create(struct drm_fb_helper *helper,
/* init fb device */
info = drm_fb_helper_alloc_fbi(helper);
- if (IS_ERR(info))
+ if (IS_ERR(info)) {
+ DRM_ERROR("Failed to allocate fbi: %ld\n", PTR_ERR(info));
return PTR_ERR(info);
+ }
info->par = &bochs->fb.helper;
- ret = bochs_framebuffer_init(bochs->dev, &bochs->fb.gfb, &mode_cmd, gobj);
- if (ret)
- return ret;
-
- bochs->fb.size = size;
+ fb = drm_gem_fbdev_fb_create(bochs->dev, sizes, 0, gobj, NULL);
+ if (IS_ERR(fb)) {
+ DRM_ERROR("Failed to create framebuffer: %ld\n", PTR_ERR(fb));
+ return PTR_ERR(fb);
+ }
/* setup helper */
- fb = &bochs->fb.gfb.base;
bochs->fb.helper.fb = fb;
strcpy(info->fix.id, "bochsdrmfb");
@@ -130,27 +130,6 @@ static int bochsfb_create(struct drm_fb_helper *helper,
drm_vma_offset_remove(&bo->bo.bdev->vma_manager, &bo->bo.vma_node);
info->fix.smem_start = 0;
info->fix.smem_len = size;
-
- bochs->fb.initialized = true;
- return 0;
-}
-
-static int bochs_fbdev_destroy(struct bochs_device *bochs)
-{
- struct bochs_framebuffer *gfb = &bochs->fb.gfb;
-
- DRM_DEBUG_DRIVER("\n");
-
- drm_fb_helper_unregister_fbi(&bochs->fb.helper);
-
- if (gfb->obj) {
- drm_gem_object_unreference_unlocked(gfb->obj);
- gfb->obj = NULL;
- }
-
- drm_framebuffer_unregister_private(&gfb->base);
- drm_framebuffer_cleanup(&gfb->base);
-
return 0;
}
@@ -158,41 +137,17 @@ static const struct drm_fb_helper_funcs bochs_fb_helper_funcs = {
.fb_probe = bochsfb_create,
};
+const struct drm_mode_config_funcs bochs_mode_funcs = {
+ .fb_create = drm_gem_fb_create,
+};
+
int bochs_fbdev_init(struct bochs_device *bochs)
{
- int ret;
-
- drm_fb_helper_prepare(bochs->dev, &bochs->fb.helper,
- &bochs_fb_helper_funcs);
-
- ret = drm_fb_helper_init(bochs->dev, &bochs->fb.helper, 1);
- if (ret)
- return ret;
-
- ret = drm_fb_helper_single_add_all_connectors(&bochs->fb.helper);
- if (ret)
- goto fini;
-
- drm_helper_disable_unused_functions(bochs->dev);
-
- ret = drm_fb_helper_initial_config(&bochs->fb.helper, 32);
- if (ret)
- goto fini;
-
- return 0;
-
-fini:
- drm_fb_helper_fini(&bochs->fb.helper);
- return ret;
+ return drm_fb_helper_fbdev_setup(bochs->dev, &bochs->fb.helper,
+ &bochs_fb_helper_funcs, 32, 1);
}
void bochs_fbdev_fini(struct bochs_device *bochs)
{
- if (bochs->fb.initialized)
- bochs_fbdev_destroy(bochs);
-
- if (bochs->fb.helper.fbdev)
- drm_fb_helper_fini(&bochs->fb.helper);
-
- bochs->fb.initialized = false;
+ drm_fb_helper_fbdev_teardown(bochs->dev);
}
diff --git a/drivers/gpu/drm/bochs/bochs_hw.c b/drivers/gpu/drm/bochs/bochs_hw.c
index a39b0343c197..16e4f1caccca 100644
--- a/drivers/gpu/drm/bochs/bochs_hw.c
+++ b/drivers/gpu/drm/bochs/bochs_hw.c
@@ -47,7 +47,7 @@ static void bochs_dispi_write(struct bochs_device *bochs, u16 reg, u16 val)
}
}
-int bochs_hw_init(struct drm_device *dev, uint32_t flags)
+int bochs_hw_init(struct drm_device *dev)
{
struct bochs_device *bochs = dev->dev_private;
struct pci_dev *pdev = dev->pdev;
diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c
index ca5a9afdd5cf..ea9a43d31bf1 100644
--- a/drivers/gpu/drm/bochs/bochs_kms.c
+++ b/drivers/gpu/drm/bochs/bochs_kms.c
@@ -35,14 +35,12 @@ static int bochs_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
{
struct bochs_device *bochs =
container_of(crtc, struct bochs_device, crtc);
- struct bochs_framebuffer *bochs_fb;
struct bochs_bo *bo;
u64 gpu_addr = 0;
int ret;
if (old_fb) {
- bochs_fb = to_bochs_framebuffer(old_fb);
- bo = gem_to_bochs_bo(bochs_fb->obj);
+ bo = gem_to_bochs_bo(old_fb->obj[0]);
ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
if (ret) {
DRM_ERROR("failed to reserve old_fb bo\n");
@@ -55,8 +53,7 @@ static int bochs_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
if (WARN_ON(crtc->primary->fb == NULL))
return -EINVAL;
- bochs_fb = to_bochs_framebuffer(crtc->primary->fb);
- bo = gem_to_bochs_bo(bochs_fb->obj);
+ bo = gem_to_bochs_bo(crtc->primary->fb->obj[0]);
ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c
index c9c7097030ca..a61c1ecb2bdc 100644
--- a/drivers/gpu/drm/bochs/bochs_mm.c
+++ b/drivers/gpu/drm/bochs/bochs_mm.c
@@ -457,77 +457,3 @@ int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
drm_gem_object_unreference_unlocked(obj);
return 0;
}
-
-/* ---------------------------------------------------------------------- */
-
-static void bochs_user_framebuffer_destroy(struct drm_framebuffer *fb)
-{
- struct bochs_framebuffer *bochs_fb = to_bochs_framebuffer(fb);
-
- drm_gem_object_unreference_unlocked(bochs_fb->obj);
- drm_framebuffer_cleanup(fb);
- kfree(fb);
-}
-
-static const struct drm_framebuffer_funcs bochs_fb_funcs = {
- .destroy = bochs_user_framebuffer_destroy,
-};
-
-int bochs_framebuffer_init(struct drm_device *dev,
- struct bochs_framebuffer *gfb,
- const struct drm_mode_fb_cmd2 *mode_cmd,
- struct drm_gem_object *obj)
-{
- int ret;
-
- drm_helper_mode_fill_fb_struct(dev, &gfb->base, mode_cmd);
- gfb->obj = obj;
- ret = drm_framebuffer_init(dev, &gfb->base, &bochs_fb_funcs);
- if (ret) {
- DRM_ERROR("drm_framebuffer_init failed: %d\n", ret);
- return ret;
- }
- return 0;
-}
-
-static struct drm_framebuffer *
-bochs_user_framebuffer_create(struct drm_device *dev,
- struct drm_file *filp,
- const struct drm_mode_fb_cmd2 *mode_cmd)
-{
- struct drm_gem_object *obj;
- struct bochs_framebuffer *bochs_fb;
- int ret;
-
- DRM_DEBUG_DRIVER("%dx%d, format %c%c%c%c\n",
- mode_cmd->width, mode_cmd->height,
- (mode_cmd->pixel_format) & 0xff,
- (mode_cmd->pixel_format >> 8) & 0xff,
- (mode_cmd->pixel_format >> 16) & 0xff,
- (mode_cmd->pixel_format >> 24) & 0xff);
-
- if (mode_cmd->pixel_format != DRM_FORMAT_XRGB8888)
- return ERR_PTR(-ENOENT);
-
- obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
- if (obj == NULL)
- return ERR_PTR(-ENOENT);
-
- bochs_fb = kzalloc(sizeof(*bochs_fb), GFP_KERNEL);
- if (!bochs_fb) {
- drm_gem_object_unreference_unlocked(obj);
- return ERR_PTR(-ENOMEM);
- }
-
- ret = bochs_framebuffer_init(dev, bochs_fb, mode_cmd, obj);
- if (ret) {
- drm_gem_object_unreference_unlocked(obj);
- kfree(bochs_fb);
- return ERR_PTR(ret);
- }
- return &bochs_fb->base;
-}
-
-const struct drm_mode_config_funcs bochs_mode_funcs = {
- .fb_create = bochs_user_framebuffer_create,
-};
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index d68986cea132..2f21d3b6850b 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -554,7 +554,7 @@ static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp)
if (retval < 0)
return retval;
- dev_info(dp->dev, "Link Training Clock Recovery success\n");
+ dev_dbg(dp->dev, "Link Training Clock Recovery success\n");
dp->link_train.lt_state = EQUALIZER_TRAINING;
} else {
for (lane = 0; lane < lane_count; lane++) {
@@ -634,7 +634,7 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
if (retval < 0)
return retval;
- dev_info(dp->dev, "Link Training success!\n");
+ dev_dbg(dp->dev, "Link Training success!\n");
analogix_dp_get_link_bandwidth(dp, &reg);
dp->link_train.link_rate = reg;
dev_dbg(dp->dev, "final bandwidth = %.2x\n",
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index d0478abc01bd..7ada75919756 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -28,6 +28,7 @@
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_uapi.h>
#include <drm/drm_mode.h>
#include <drm/drm_print.h>
#include <drm/drm_writeback.h>
@@ -309,350 +310,6 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state,
}
EXPORT_SYMBOL(drm_atomic_get_crtc_state);
-static void set_out_fence_for_crtc(struct drm_atomic_state *state,
- struct drm_crtc *crtc, s32 __user *fence_ptr)
-{
- state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = fence_ptr;
-}
-
-static s32 __user *get_out_fence_for_crtc(struct drm_atomic_state *state,
- struct drm_crtc *crtc)
-{
- s32 __user *fence_ptr;
-
- fence_ptr = state->crtcs[drm_crtc_index(crtc)].out_fence_ptr;
- state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = NULL;
-
- return fence_ptr;
-}
-
-static int set_out_fence_for_connector(struct drm_atomic_state *state,
- struct drm_connector *connector,
- s32 __user *fence_ptr)
-{
- unsigned int index = drm_connector_index(connector);
-
- if (!fence_ptr)
- return 0;
-
- if (put_user(-1, fence_ptr))
- return -EFAULT;
-
- state->connectors[index].out_fence_ptr = fence_ptr;
-
- return 0;
-}
-
-static s32 __user *get_out_fence_for_connector(struct drm_atomic_state *state,
- struct drm_connector *connector)
-{
- unsigned int index = drm_connector_index(connector);
- s32 __user *fence_ptr;
-
- fence_ptr = state->connectors[index].out_fence_ptr;
- state->connectors[index].out_fence_ptr = NULL;
-
- return fence_ptr;
-}
-
-/**
- * drm_atomic_set_mode_for_crtc - set mode for CRTC
- * @state: the CRTC whose incoming state to update
- * @mode: kernel-internal mode to use for the CRTC, or NULL to disable
- *
- * Set a mode (originating from the kernel) on the desired CRTC state and update
- * the enable property.
- *
- * RETURNS:
- * Zero on success, error code on failure. Cannot return -EDEADLK.
- */
-int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state,
- const struct drm_display_mode *mode)
-{
- struct drm_crtc *crtc = state->crtc;
- struct drm_mode_modeinfo umode;
-
- /* Early return for no change. */
- if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0)
- return 0;
-
- drm_property_blob_put(state->mode_blob);
- state->mode_blob = NULL;
-
- if (mode) {
- drm_mode_convert_to_umode(&umode, mode);
- state->mode_blob =
- drm_property_create_blob(state->crtc->dev,
- sizeof(umode),
- &umode);
- if (IS_ERR(state->mode_blob))
- return PTR_ERR(state->mode_blob);
-
- drm_mode_copy(&state->mode, mode);
- state->enable = true;
- DRM_DEBUG_ATOMIC("Set [MODE:%s] for [CRTC:%d:%s] state %p\n",
- mode->name, crtc->base.id, crtc->name, state);
- } else {
- memset(&state->mode, 0, sizeof(state->mode));
- state->enable = false;
- DRM_DEBUG_ATOMIC("Set [NOMODE] for [CRTC:%d:%s] state %p\n",
- crtc->base.id, crtc->name, state);
- }
-
- return 0;
-}
-EXPORT_SYMBOL(drm_atomic_set_mode_for_crtc);
-
-/**
- * drm_atomic_set_mode_prop_for_crtc - set mode for CRTC
- * @state: the CRTC whose incoming state to update
- * @blob: pointer to blob property to use for mode
- *
- * Set a mode (originating from a blob property) on the desired CRTC state.
- * This function will take a reference on the blob property for the CRTC state,
- * and release the reference held on the state's existing mode property, if any
- * was set.
- *
- * RETURNS:
- * Zero on success, error code on failure. Cannot return -EDEADLK.
- */
-int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
- struct drm_property_blob *blob)
-{
- struct drm_crtc *crtc = state->crtc;
-
- if (blob == state->mode_blob)
- return 0;
-
- drm_property_blob_put(state->mode_blob);
- state->mode_blob = NULL;
-
- memset(&state->mode, 0, sizeof(state->mode));
-
- if (blob) {
- int ret;
-
- if (blob->length != sizeof(struct drm_mode_modeinfo)) {
- DRM_DEBUG_ATOMIC("[CRTC:%d:%s] bad mode blob length: %zu\n",
- crtc->base.id, crtc->name,
- blob->length);
- return -EINVAL;
- }
-
- ret = drm_mode_convert_umode(crtc->dev,
- &state->mode, blob->data);
- if (ret) {
- DRM_DEBUG_ATOMIC("[CRTC:%d:%s] invalid mode (ret=%d, status=%s):\n",
- crtc->base.id, crtc->name,
- ret, drm_get_mode_status_name(state->mode.status));
- drm_mode_debug_printmodeline(&state->mode);
- return -EINVAL;
- }
-
- state->mode_blob = drm_property_blob_get(blob);
- state->enable = true;
- DRM_DEBUG_ATOMIC("Set [MODE:%s] for [CRTC:%d:%s] state %p\n",
- state->mode.name, crtc->base.id, crtc->name,
- state);
- } else {
- state->enable = false;
- DRM_DEBUG_ATOMIC("Set [NOMODE] for [CRTC:%d:%s] state %p\n",
- crtc->base.id, crtc->name, state);
- }
-
- return 0;
-}
-EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc);
-
-/**
- * drm_atomic_replace_property_blob_from_id - lookup the new blob and replace the old one with it
- * @dev: DRM device
- * @blob: a pointer to the member blob to be replaced
- * @blob_id: ID of the new blob
- * @expected_size: total expected size of the blob data (in bytes)
- * @expected_elem_size: expected element size of the blob data (in bytes)
- * @replaced: did the blob get replaced?
- *
- * Replace @blob with another blob with the ID @blob_id. If @blob_id is zero
- * @blob becomes NULL.
- *
- * If @expected_size is positive the new blob length is expected to be equal
- * to @expected_size bytes. If @expected_elem_size is positive the new blob
- * length is expected to be a multiple of @expected_elem_size bytes. Otherwise
- * an error is returned.
- *
- * @replaced will indicate to the caller whether the blob was replaced or not.
- * If the old and new blobs were in fact the same blob @replaced will be false
- * otherwise it will be true.
- *
- * RETURNS:
- * Zero on success, error code on failure.
- */
-static int
-drm_atomic_replace_property_blob_from_id(struct drm_device *dev,
- struct drm_property_blob **blob,
- uint64_t blob_id,
- ssize_t expected_size,
- ssize_t expected_elem_size,
- bool *replaced)
-{
- struct drm_property_blob *new_blob = NULL;
-
- if (blob_id != 0) {
- new_blob = drm_property_lookup_blob(dev, blob_id);
- if (new_blob == NULL)
- return -EINVAL;
-
- if (expected_size > 0 &&
- new_blob->length != expected_size) {
- drm_property_blob_put(new_blob);
- return -EINVAL;
- }
- if (expected_elem_size > 0 &&
- new_blob->length % expected_elem_size != 0) {
- drm_property_blob_put(new_blob);
- return -EINVAL;
- }
- }
-
- *replaced |= drm_property_replace_blob(blob, new_blob);
- drm_property_blob_put(new_blob);
-
- return 0;
-}
-
-/**
- * drm_atomic_crtc_set_property - set property on CRTC
- * @crtc: the drm CRTC to set a property on
- * @state: the state object to update with the new property value
- * @property: the property to set
- * @val: the new property value
- *
- * This function handles generic/core properties and calls out to driver's
- * &drm_crtc_funcs.atomic_set_property for driver properties. To ensure
- * consistent behavior you must call this function rather than the driver hook
- * directly.
- *
- * RETURNS:
- * Zero on success, error code on failure
- */
-int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
- struct drm_crtc_state *state, struct drm_property *property,
- uint64_t val)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_mode_config *config = &dev->mode_config;
- bool replaced = false;
- int ret;
-
- if (property == config->prop_active)
- state->active = val;
- else if (property == config->prop_mode_id) {
- struct drm_property_blob *mode =
- drm_property_lookup_blob(dev, val);
- ret = drm_atomic_set_mode_prop_for_crtc(state, mode);
- drm_property_blob_put(mode);
- return ret;
- } else if (property == config->degamma_lut_property) {
- ret = drm_atomic_replace_property_blob_from_id(dev,
- &state->degamma_lut,
- val,
- -1, sizeof(struct drm_color_lut),
- &replaced);
- state->color_mgmt_changed |= replaced;
- return ret;
- } else if (property == config->ctm_property) {
- ret = drm_atomic_replace_property_blob_from_id(dev,
- &state->ctm,
- val,
- sizeof(struct drm_color_ctm), -1,
- &replaced);
- state->color_mgmt_changed |= replaced;
- return ret;
- } else if (property == config->gamma_lut_property) {
- ret = drm_atomic_replace_property_blob_from_id(dev,
- &state->gamma_lut,
- val,
- -1, sizeof(struct drm_color_lut),
- &replaced);
- state->color_mgmt_changed |= replaced;
- return ret;
- } else if (property == config->prop_out_fence_ptr) {
- s32 __user *fence_ptr = u64_to_user_ptr(val);
-
- if (!fence_ptr)
- return 0;
-
- if (put_user(-1, fence_ptr))
- return -EFAULT;
-
- set_out_fence_for_crtc(state->state, crtc, fence_ptr);
- } else if (crtc->funcs->atomic_set_property) {
- return crtc->funcs->atomic_set_property(crtc, state, property, val);
- } else {
- DRM_DEBUG_ATOMIC("[CRTC:%d:%s] unknown property [PROP:%d:%s]]\n",
- crtc->base.id, crtc->name,
- property->base.id, property->name);
- return -EINVAL;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(drm_atomic_crtc_set_property);
-
-/**
- * drm_atomic_crtc_get_property - get property value from CRTC state
- * @crtc: the drm CRTC to set a property on
- * @state: the state object to get the property value from
- * @property: the property to set
- * @val: return location for the property value
- *
- * This function handles generic/core properties and calls out to driver's
- * &drm_crtc_funcs.atomic_get_property for driver properties. To ensure
- * consistent behavior you must call this function rather than the driver hook
- * directly.
- *
- * RETURNS:
- * Zero on success, error code on failure
- */
-static int
-drm_atomic_crtc_get_property(struct drm_crtc *crtc,
- const struct drm_crtc_state *state,
- struct drm_property *property, uint64_t *val)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_mode_config *config = &dev->mode_config;
-
- if (property == config->prop_active)
- *val = state->active;
- else if (property == config->prop_mode_id)
- *val = (state->mode_blob) ? state->mode_blob->base.id : 0;
- else if (property == config->degamma_lut_property)
- *val = (state->degamma_lut) ? state->degamma_lut->base.id : 0;
- else if (property == config->ctm_property)
- *val = (state->ctm) ? state->ctm->base.id : 0;
- else if (property == config->gamma_lut_property)
- *val = (state->gamma_lut) ? state->gamma_lut->base.id : 0;
- else if (property == config->prop_out_fence_ptr)
- *val = 0;
- else if (crtc->funcs->atomic_get_property)
- return crtc->funcs->atomic_get_property(crtc, state, property, val);
- else
- return -EINVAL;
-
- return 0;
-}
-
-/**
- * drm_atomic_crtc_check - check crtc state
- * @crtc: crtc to check
- * @state: crtc state to check
- *
- * Provides core sanity checks for crtc state.
- *
- * RETURNS:
- * Zero on success, error code on failure
- */
static int drm_atomic_crtc_check(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
@@ -728,16 +385,6 @@ static void drm_atomic_crtc_print_state(struct drm_printer *p,
crtc->funcs->atomic_print_state(p, state);
}
-/**
- * drm_atomic_connector_check - check connector state
- * @connector: connector to check
- * @state: connector state to check
- *
- * Provides core sanity checks for connector state.
- *
- * RETURNS:
- * Zero on success, error code on failure
- */
static int drm_atomic_connector_check(struct drm_connector *connector,
struct drm_connector_state *state)
{
@@ -836,159 +483,6 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state,
}
EXPORT_SYMBOL(drm_atomic_get_plane_state);
-/**
- * drm_atomic_plane_set_property - set property on plane
- * @plane: the drm plane to set a property on
- * @state: the state object to update with the new property value
- * @property: the property to set
- * @val: the new property value
- *
- * This function handles generic/core properties and calls out to driver's
- * &drm_plane_funcs.atomic_set_property for driver properties. To ensure
- * consistent behavior you must call this function rather than the driver hook
- * directly.
- *
- * RETURNS:
- * Zero on success, error code on failure
- */
-static int drm_atomic_plane_set_property(struct drm_plane *plane,
- struct drm_plane_state *state, struct drm_property *property,
- uint64_t val)
-{
- struct drm_device *dev = plane->dev;
- struct drm_mode_config *config = &dev->mode_config;
-
- if (property == config->prop_fb_id) {
- struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, NULL, val);
- drm_atomic_set_fb_for_plane(state, fb);
- if (fb)
- drm_framebuffer_put(fb);
- } else if (property == config->prop_in_fence_fd) {
- if (state->fence)
- return -EINVAL;
-
- if (U642I64(val) == -1)
- return 0;
-
- state->fence = sync_file_get_fence(val);
- if (!state->fence)
- return -EINVAL;
-
- } else if (property == config->prop_crtc_id) {
- struct drm_crtc *crtc = drm_crtc_find(dev, NULL, val);
- return drm_atomic_set_crtc_for_plane(state, crtc);
- } else if (property == config->prop_crtc_x) {
- state->crtc_x = U642I64(val);
- } else if (property == config->prop_crtc_y) {
- state->crtc_y = U642I64(val);
- } else if (property == config->prop_crtc_w) {
- state->crtc_w = val;
- } else if (property == config->prop_crtc_h) {
- state->crtc_h = val;
- } else if (property == config->prop_src_x) {
- state->src_x = val;
- } else if (property == config->prop_src_y) {
- state->src_y = val;
- } else if (property == config->prop_src_w) {
- state->src_w = val;
- } else if (property == config->prop_src_h) {
- state->src_h = val;
- } else if (property == plane->alpha_property) {
- state->alpha = val;
- } else if (property == plane->blend_mode_property) {
- state->pixel_blend_mode = val;
- } else if (property == plane->rotation_property) {
- if (!is_power_of_2(val & DRM_MODE_ROTATE_MASK)) {
- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] bad rotation bitmask: 0x%llx\n",
- plane->base.id, plane->name, val);
- return -EINVAL;
- }
- state->rotation = val;
- } else if (property == plane->zpos_property) {
- state->zpos = val;
- } else if (property == plane->color_encoding_property) {
- state->color_encoding = val;
- } else if (property == plane->color_range_property) {
- state->color_range = val;
- } else if (plane->funcs->atomic_set_property) {
- return plane->funcs->atomic_set_property(plane, state,
- property, val);
- } else {
- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] unknown property [PROP:%d:%s]]\n",
- plane->base.id, plane->name,
- property->base.id, property->name);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/**
- * drm_atomic_plane_get_property - get property value from plane state
- * @plane: the drm plane to set a property on
- * @state: the state object to get the property value from
- * @property: the property to set
- * @val: return location for the property value
- *
- * This function handles generic/core properties and calls out to driver's
- * &drm_plane_funcs.atomic_get_property for driver properties. To ensure
- * consistent behavior you must call this function rather than the driver hook
- * directly.
- *
- * RETURNS:
- * Zero on success, error code on failure
- */
-static int
-drm_atomic_plane_get_property(struct drm_plane *plane,
- const struct drm_plane_state *state,
- struct drm_property *property, uint64_t *val)
-{
- struct drm_device *dev = plane->dev;
- struct drm_mode_config *config = &dev->mode_config;
-
- if (property == config->prop_fb_id) {
- *val = (state->fb) ? state->fb->base.id : 0;
- } else if (property == config->prop_in_fence_fd) {
- *val = -1;
- } else if (property == config->prop_crtc_id) {
- *val = (state->crtc) ? state->crtc->base.id : 0;
- } else if (property == config->prop_crtc_x) {
- *val = I642U64(state->crtc_x);
- } else if (property == config->prop_crtc_y) {
- *val = I642U64(state->crtc_y);
- } else if (property == config->prop_crtc_w) {
- *val = state->crtc_w;
- } else if (property == config->prop_crtc_h) {
- *val = state->crtc_h;
- } else if (property == config->prop_src_x) {
- *val = state->src_x;
- } else if (property == config->prop_src_y) {
- *val = state->src_y;
- } else if (property == config->prop_src_w) {
- *val = state->src_w;
- } else if (property == config->prop_src_h) {
- *val = state->src_h;
- } else if (property == plane->alpha_property) {
- *val = state->alpha;
- } else if (property == plane->blend_mode_property) {
- *val = state->pixel_blend_mode;
- } else if (property == plane->rotation_property) {
- *val = state->rotation;
- } else if (property == plane->zpos_property) {
- *val = state->zpos;
- } else if (property == plane->color_encoding_property) {
- *val = state->color_encoding;
- } else if (property == plane->color_range_property) {
- *val = state->color_range;
- } else if (plane->funcs->atomic_get_property) {
- return plane->funcs->atomic_get_property(plane, state, property, val);
- } else {
- return -EINVAL;
- }
-
- return 0;
-}
-
static bool
plane_switching_crtc(struct drm_atomic_state *state,
struct drm_plane *plane,
@@ -1328,111 +822,6 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
}
EXPORT_SYMBOL(drm_atomic_get_connector_state);
-/**
- * drm_atomic_connector_set_property - set property on connector.
- * @connector: the drm connector to set a property on
- * @state: the state object to update with the new property value
- * @property: the property to set
- * @val: the new property value
- *
- * This function handles generic/core properties and calls out to driver's
- * &drm_connector_funcs.atomic_set_property for driver properties. To ensure
- * consistent behavior you must call this function rather than the driver hook
- * directly.
- *
- * RETURNS:
- * Zero on success, error code on failure
- */
-static int drm_atomic_connector_set_property(struct drm_connector *connector,
- struct drm_connector_state *state, struct drm_property *property,
- uint64_t val)
-{
- struct drm_device *dev = connector->dev;
- struct drm_mode_config *config = &dev->mode_config;
-
- if (property == config->prop_crtc_id) {
- struct drm_crtc *crtc = drm_crtc_find(dev, NULL, val);
- return drm_atomic_set_crtc_for_connector(state, crtc);
- } else if (property == config->dpms_property) {
- /* setting DPMS property requires special handling, which
- * is done in legacy setprop path for us. Disallow (for
- * now?) atomic writes to DPMS property:
- */
- return -EINVAL;
- } else if (property == config->tv_select_subconnector_property) {
- state->tv.subconnector = val;
- } else if (property == config->tv_left_margin_property) {
- state->tv.margins.left = val;
- } else if (property == config->tv_right_margin_property) {
- state->tv.margins.right = val;
- } else if (property == config->tv_top_margin_property) {
- state->tv.margins.top = val;
- } else if (property == config->tv_bottom_margin_property) {
- state->tv.margins.bottom = val;
- } else if (property == config->tv_mode_property) {
- state->tv.mode = val;
- } else if (property == config->tv_brightness_property) {
- state->tv.brightness = val;
- } else if (property == config->tv_contrast_property) {
- state->tv.contrast = val;
- } else if (property == config->tv_flicker_reduction_property) {
- state->tv.flicker_reduction = val;
- } else if (property == config->tv_overscan_property) {
- state->tv.overscan = val;
- } else if (property == config->tv_saturation_property) {
- state->tv.saturation = val;
- } else if (property == config->tv_hue_property) {
- state->tv.hue = val;
- } else if (property == config->link_status_property) {
- /* Never downgrade from GOOD to BAD on userspace's request here,
- * only hw issues can do that.
- *
- * For an atomic property the userspace doesn't need to be able
- * to understand all the properties, but needs to be able to
- * restore the state it wants on VT switch. So if the userspace
- * tries to change the link_status from GOOD to BAD, driver
- * silently rejects it and returns a 0. This prevents userspace
- * from accidently breaking the display when it restores the
- * state.
- */
- if (state->link_status != DRM_LINK_STATUS_GOOD)
- state->link_status = val;
- } else if (property == config->aspect_ratio_property) {
- state->picture_aspect_ratio = val;
- } else if (property == config->content_type_property) {
- state->content_type = val;
- } else if (property == connector->scaling_mode_property) {
- state->scaling_mode = val;
- } else if (property == connector->content_protection_property) {
- if (val == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
- DRM_DEBUG_KMS("only drivers can set CP Enabled\n");
- return -EINVAL;
- }
- state->content_protection = val;
- } else if (property == config->writeback_fb_id_property) {
- struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, NULL, val);
- int ret = drm_atomic_set_writeback_fb_for_connector(state, fb);
- if (fb)
- drm_framebuffer_put(fb);
- return ret;
- } else if (property == config->writeback_out_fence_ptr_property) {
- s32 __user *fence_ptr = u64_to_user_ptr(val);
-
- return set_out_fence_for_connector(state->state, connector,
- fence_ptr);
- } else if (connector->funcs->atomic_set_property) {
- return connector->funcs->atomic_set_property(connector,
- state, property, val);
- } else {
- DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] unknown property [PROP:%d:%s]]\n",
- connector->base.id, connector->name,
- property->base.id, property->name);
- return -EINVAL;
- }
-
- return 0;
-}
-
static void drm_atomic_connector_print_state(struct drm_printer *p,
const struct drm_connector_state *state)
{
@@ -1450,360 +839,6 @@ static void drm_atomic_connector_print_state(struct drm_printer *p,
}
/**
- * drm_atomic_connector_get_property - get property value from connector state
- * @connector: the drm connector to set a property on
- * @state: the state object to get the property value from
- * @property: the property to set
- * @val: return location for the property value
- *
- * This function handles generic/core properties and calls out to driver's
- * &drm_connector_funcs.atomic_get_property for driver properties. To ensure
- * consistent behavior you must call this function rather than the driver hook
- * directly.
- *
- * RETURNS:
- * Zero on success, error code on failure
- */
-static int
-drm_atomic_connector_get_property(struct drm_connector *connector,
- const struct drm_connector_state *state,
- struct drm_property *property, uint64_t *val)
-{
- struct drm_device *dev = connector->dev;
- struct drm_mode_config *config = &dev->mode_config;
-
- if (property == config->prop_crtc_id) {
- *val = (state->crtc) ? state->crtc->base.id : 0;
- } else if (property == config->dpms_property) {
- *val = connector->dpms;
- } else if (property == config->tv_select_subconnector_property) {
- *val = state->tv.subconnector;
- } else if (property == config->tv_left_margin_property) {
- *val = state->tv.margins.left;
- } else if (property == config->tv_right_margin_property) {
- *val = state->tv.margins.right;
- } else if (property == config->tv_top_margin_property) {
- *val = state->tv.margins.top;
- } else if (property == config->tv_bottom_margin_property) {
- *val = state->tv.margins.bottom;
- } else if (property == config->tv_mode_property) {
- *val = state->tv.mode;
- } else if (property == config->tv_brightness_property) {
- *val = state->tv.brightness;
- } else if (property == config->tv_contrast_property) {
- *val = state->tv.contrast;
- } else if (property == config->tv_flicker_reduction_property) {
- *val = state->tv.flicker_reduction;
- } else if (property == config->tv_overscan_property) {
- *val = state->tv.overscan;
- } else if (property == config->tv_saturation_property) {
- *val = state->tv.saturation;
- } else if (property == config->tv_hue_property) {
- *val = state->tv.hue;
- } else if (property == config->link_status_property) {
- *val = state->link_status;
- } else if (property == config->aspect_ratio_property) {
- *val = state->picture_aspect_ratio;
- } else if (property == config->content_type_property) {
- *val = state->content_type;
- } else if (property == connector->scaling_mode_property) {
- *val = state->scaling_mode;
- } else if (property == connector->content_protection_property) {
- *val = state->content_protection;
- } else if (property == config->writeback_fb_id_property) {
- /* Writeback framebuffer is one-shot, write and forget */
- *val = 0;
- } else if (property == config->writeback_out_fence_ptr_property) {
- *val = 0;
- } else if (connector->funcs->atomic_get_property) {
- return connector->funcs->atomic_get_property(connector,
- state, property, val);
- } else {
- return -EINVAL;
- }
-
- return 0;
-}
-
-int drm_atomic_get_property(struct drm_mode_object *obj,
- struct drm_property *property, uint64_t *val)
-{
- struct drm_device *dev = property->dev;
- int ret;
-
- switch (obj->type) {
- case DRM_MODE_OBJECT_CONNECTOR: {
- struct drm_connector *connector = obj_to_connector(obj);
- WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
- ret = drm_atomic_connector_get_property(connector,
- connector->state, property, val);
- break;
- }
- case DRM_MODE_OBJECT_CRTC: {
- struct drm_crtc *crtc = obj_to_crtc(obj);
- WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
- ret = drm_atomic_crtc_get_property(crtc,
- crtc->state, property, val);
- break;
- }
- case DRM_MODE_OBJECT_PLANE: {
- struct drm_plane *plane = obj_to_plane(obj);
- WARN_ON(!drm_modeset_is_locked(&plane->mutex));
- ret = drm_atomic_plane_get_property(plane,
- plane->state, property, val);
- break;
- }
- default:
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-/**
- * drm_atomic_set_crtc_for_plane - set crtc for plane
- * @plane_state: the plane whose incoming state to update
- * @crtc: crtc to use for the plane
- *
- * Changing the assigned crtc for a plane requires us to grab the lock and state
- * for the new crtc, as needed. This function takes care of all these details
- * besides updating the pointer in the state object itself.
- *
- * Returns:
- * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
- * then the w/w mutex code has detected a deadlock and the entire atomic
- * sequence must be restarted. All other errors are fatal.
- */
-int
-drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
- struct drm_crtc *crtc)
-{
- struct drm_plane *plane = plane_state->plane;
- struct drm_crtc_state *crtc_state;
- /* Nothing to do for same crtc*/
- if (plane_state->crtc == crtc)
- return 0;
- if (plane_state->crtc) {
- crtc_state = drm_atomic_get_crtc_state(plane_state->state,
- plane_state->crtc);
- if (WARN_ON(IS_ERR(crtc_state)))
- return PTR_ERR(crtc_state);
-
- crtc_state->plane_mask &= ~drm_plane_mask(plane);
- }
-
- plane_state->crtc = crtc;
-
- if (crtc) {
- crtc_state = drm_atomic_get_crtc_state(plane_state->state,
- crtc);
- if (IS_ERR(crtc_state))
- return PTR_ERR(crtc_state);
- crtc_state->plane_mask |= drm_plane_mask(plane);
- }
-
- if (crtc)
- DRM_DEBUG_ATOMIC("Link [PLANE:%d:%s] state %p to [CRTC:%d:%s]\n",
- plane->base.id, plane->name, plane_state,
- crtc->base.id, crtc->name);
- else
- DRM_DEBUG_ATOMIC("Link [PLANE:%d:%s] state %p to [NOCRTC]\n",
- plane->base.id, plane->name, plane_state);
-
- return 0;
-}
-EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane);
-
-/**
- * drm_atomic_set_fb_for_plane - set framebuffer for plane
- * @plane_state: atomic state object for the plane
- * @fb: fb to use for the plane
- *
- * Changing the assigned framebuffer for a plane requires us to grab a reference
- * to the new fb and drop the reference to the old fb, if there is one. This
- * function takes care of all these details besides updating the pointer in the
- * state object itself.
- */
-void
-drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
- struct drm_framebuffer *fb)
-{
- struct drm_plane *plane = plane_state->plane;
-
- if (fb)
- DRM_DEBUG_ATOMIC("Set [FB:%d] for [PLANE:%d:%s] state %p\n",
- fb->base.id, plane->base.id, plane->name,
- plane_state);
- else
- DRM_DEBUG_ATOMIC("Set [NOFB] for [PLANE:%d:%s] state %p\n",
- plane->base.id, plane->name, plane_state);
-
- drm_framebuffer_assign(&plane_state->fb, fb);
-}
-EXPORT_SYMBOL(drm_atomic_set_fb_for_plane);
-
-/**
- * drm_atomic_set_fence_for_plane - set fence for plane
- * @plane_state: atomic state object for the plane
- * @fence: dma_fence to use for the plane
- *
- * Helper to setup the plane_state fence in case it is not set yet.
- * By using this drivers doesn't need to worry if the user choose
- * implicit or explicit fencing.
- *
- * This function will not set the fence to the state if it was set
- * via explicit fencing interfaces on the atomic ioctl. In that case it will
- * drop the reference to the fence as we are not storing it anywhere.
- * Otherwise, if &drm_plane_state.fence is not set this function we just set it
- * with the received implicit fence. In both cases this function consumes a
- * reference for @fence.
- *
- * This way explicit fencing can be used to overrule implicit fencing, which is
- * important to make explicit fencing use-cases work: One example is using one
- * buffer for 2 screens with different refresh rates. Implicit fencing will
- * clamp rendering to the refresh rate of the slower screen, whereas explicit
- * fence allows 2 independent render and display loops on a single buffer. If a
- * driver allows obeys both implicit and explicit fences for plane updates, then
- * it will break all the benefits of explicit fencing.
- */
-void
-drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state,
- struct dma_fence *fence)
-{
- if (plane_state->fence) {
- dma_fence_put(fence);
- return;
- }
-
- plane_state->fence = fence;
-}
-EXPORT_SYMBOL(drm_atomic_set_fence_for_plane);
-
-/**
- * drm_atomic_set_crtc_for_connector - set crtc for connector
- * @conn_state: atomic state object for the connector
- * @crtc: crtc to use for the connector
- *
- * Changing the assigned crtc for a connector requires us to grab the lock and
- * state for the new crtc, as needed. This function takes care of all these
- * details besides updating the pointer in the state object itself.
- *
- * Returns:
- * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
- * then the w/w mutex code has detected a deadlock and the entire atomic
- * sequence must be restarted. All other errors are fatal.
- */
-int
-drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
- struct drm_crtc *crtc)
-{
- struct drm_connector *connector = conn_state->connector;
- struct drm_crtc_state *crtc_state;
-
- if (conn_state->crtc == crtc)
- return 0;
-
- if (conn_state->crtc) {
- crtc_state = drm_atomic_get_new_crtc_state(conn_state->state,
- conn_state->crtc);
-
- crtc_state->connector_mask &=
- ~drm_connector_mask(conn_state->connector);
-
- drm_connector_put(conn_state->connector);
- conn_state->crtc = NULL;
- }
-
- if (crtc) {
- crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc);
- if (IS_ERR(crtc_state))
- return PTR_ERR(crtc_state);
-
- crtc_state->connector_mask |=
- drm_connector_mask(conn_state->connector);
-
- drm_connector_get(conn_state->connector);
- conn_state->crtc = crtc;
-
- DRM_DEBUG_ATOMIC("Link [CONNECTOR:%d:%s] state %p to [CRTC:%d:%s]\n",
- connector->base.id, connector->name,
- conn_state, crtc->base.id, crtc->name);
- } else {
- DRM_DEBUG_ATOMIC("Link [CONNECTOR:%d:%s] state %p to [NOCRTC]\n",
- connector->base.id, connector->name,
- conn_state);
- }
-
- return 0;
-}
-EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector);
-
-/*
- * drm_atomic_get_writeback_job - return or allocate a writeback job
- * @conn_state: Connector state to get the job for
- *
- * Writeback jobs have a different lifetime to the atomic state they are
- * associated with. This convenience function takes care of allocating a job
- * if there isn't yet one associated with the connector state, otherwise
- * it just returns the existing job.
- *
- * Returns: The writeback job for the given connector state
- */
-static struct drm_writeback_job *
-drm_atomic_get_writeback_job(struct drm_connector_state *conn_state)
-{
- WARN_ON(conn_state->connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK);
-
- if (!conn_state->writeback_job)
- conn_state->writeback_job =
- kzalloc(sizeof(*conn_state->writeback_job), GFP_KERNEL);
-
- return conn_state->writeback_job;
-}
-
-/**
- * drm_atomic_set_writeback_fb_for_connector - set writeback framebuffer
- * @conn_state: atomic state object for the connector
- * @fb: fb to use for the connector
- *
- * This is used to set the framebuffer for a writeback connector, which outputs
- * to a buffer instead of an actual physical connector.
- * Changing the assigned framebuffer requires us to grab a reference to the new
- * fb and drop the reference to the old fb, if there is one. This function
- * takes care of all these details besides updating the pointer in the
- * state object itself.
- *
- * Note: The only way conn_state can already have an fb set is if the commit
- * sets the property more than once.
- *
- * See also: drm_writeback_connector_init()
- *
- * Returns: 0 on success
- */
-int drm_atomic_set_writeback_fb_for_connector(
- struct drm_connector_state *conn_state,
- struct drm_framebuffer *fb)
-{
- struct drm_writeback_job *job =
- drm_atomic_get_writeback_job(conn_state);
- if (!job)
- return -ENOMEM;
-
- drm_framebuffer_assign(&job->fb, fb);
-
- if (fb)
- DRM_DEBUG_ATOMIC("Set [FB:%d] for connector state %p\n",
- fb->base.id, conn_state);
- else
- DRM_DEBUG_ATOMIC("Set [NOFB] for connector state %p\n",
- conn_state);
-
- return 0;
-}
-EXPORT_SYMBOL(drm_atomic_set_writeback_fb_for_connector);
-
-/**
* drm_atomic_add_affected_connectors - add connectors for crtc
* @state: atomic state
* @crtc: DRM crtc
@@ -2039,7 +1074,7 @@ int drm_atomic_nonblocking_commit(struct drm_atomic_state *state)
}
EXPORT_SYMBOL(drm_atomic_nonblocking_commit);
-static void drm_atomic_print_state(const struct drm_atomic_state *state)
+void drm_atomic_print_state(const struct drm_atomic_state *state)
{
struct drm_printer p = drm_info_printer(state->dev->dev);
struct drm_plane *plane;
@@ -2146,544 +1181,3 @@ int drm_atomic_debugfs_init(struct drm_minor *minor)
}
#endif
-/*
- * The big monster ioctl
- */
-
-static struct drm_pending_vblank_event *create_vblank_event(
- struct drm_crtc *crtc, uint64_t user_data)
-{
- struct drm_pending_vblank_event *e = NULL;
-
- e = kzalloc(sizeof *e, GFP_KERNEL);
- if (!e)
- return NULL;
-
- e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
- e->event.base.length = sizeof(e->event);
- e->event.vbl.crtc_id = crtc->base.id;
- e->event.vbl.user_data = user_data;
-
- return e;
-}
-
-int drm_atomic_connector_commit_dpms(struct drm_atomic_state *state,
- struct drm_connector *connector,
- int mode)
-{
- struct drm_connector *tmp_connector;
- struct drm_connector_state *new_conn_state;
- struct drm_crtc *crtc;
- struct drm_crtc_state *crtc_state;
- int i, ret, old_mode = connector->dpms;
- bool active = false;
-
- ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
- state->acquire_ctx);
- if (ret)
- return ret;
-
- if (mode != DRM_MODE_DPMS_ON)
- mode = DRM_MODE_DPMS_OFF;
- connector->dpms = mode;
-
- crtc = connector->state->crtc;
- if (!crtc)
- goto out;
- ret = drm_atomic_add_affected_connectors(state, crtc);
- if (ret)
- goto out;
-
- crtc_state = drm_atomic_get_crtc_state(state, crtc);
- if (IS_ERR(crtc_state)) {
- ret = PTR_ERR(crtc_state);
- goto out;
- }
-
- for_each_new_connector_in_state(state, tmp_connector, new_conn_state, i) {
- if (new_conn_state->crtc != crtc)
- continue;
- if (tmp_connector->dpms == DRM_MODE_DPMS_ON) {
- active = true;
- break;
- }
- }
-
- crtc_state->active = active;
- ret = drm_atomic_commit(state);
-out:
- if (ret != 0)
- connector->dpms = old_mode;
- return ret;
-}
-
-int drm_atomic_set_property(struct drm_atomic_state *state,
- struct drm_mode_object *obj,
- struct drm_property *prop,
- uint64_t prop_value)
-{
- struct drm_mode_object *ref;
- int ret;
-
- if (!drm_property_change_valid_get(prop, prop_value, &ref))
- return -EINVAL;
-
- switch (obj->type) {
- case DRM_MODE_OBJECT_CONNECTOR: {
- struct drm_connector *connector = obj_to_connector(obj);
- struct drm_connector_state *connector_state;
-
- connector_state = drm_atomic_get_connector_state(state, connector);
- if (IS_ERR(connector_state)) {
- ret = PTR_ERR(connector_state);
- break;
- }
-
- ret = drm_atomic_connector_set_property(connector,
- connector_state, prop, prop_value);
- break;
- }
- case DRM_MODE_OBJECT_CRTC: {
- struct drm_crtc *crtc = obj_to_crtc(obj);
- struct drm_crtc_state *crtc_state;
-
- crtc_state = drm_atomic_get_crtc_state(state, crtc);
- if (IS_ERR(crtc_state)) {
- ret = PTR_ERR(crtc_state);
- break;
- }
-
- ret = drm_atomic_crtc_set_property(crtc,
- crtc_state, prop, prop_value);
- break;
- }
- case DRM_MODE_OBJECT_PLANE: {
- struct drm_plane *plane = obj_to_plane(obj);
- struct drm_plane_state *plane_state;
-
- plane_state = drm_atomic_get_plane_state(state, plane);
- if (IS_ERR(plane_state)) {
- ret = PTR_ERR(plane_state);
- break;
- }
-
- ret = drm_atomic_plane_set_property(plane,
- plane_state, prop, prop_value);
- break;
- }
- default:
- ret = -EINVAL;
- break;
- }
-
- drm_property_change_valid_put(prop, ref);
- return ret;
-}
-
-/**
- * DOC: explicit fencing properties
- *
- * Explicit fencing allows userspace to control the buffer synchronization
- * between devices. A Fence or a group of fences are transfered to/from
- * userspace using Sync File fds and there are two DRM properties for that.
- * IN_FENCE_FD on each DRM Plane to send fences to the kernel and
- * OUT_FENCE_PTR on each DRM CRTC to receive fences from the kernel.
- *
- * As a contrast, with implicit fencing the kernel keeps track of any
- * ongoing rendering, and automatically ensures that the atomic update waits
- * for any pending rendering to complete. For shared buffers represented with
- * a &struct dma_buf this is tracked in &struct reservation_object.
- * Implicit syncing is how Linux traditionally worked (e.g. DRI2/3 on X.org),
- * whereas explicit fencing is what Android wants.
- *
- * "IN_FENCE_FD”:
- * Use this property to pass a fence that DRM should wait on before
- * proceeding with the Atomic Commit request and show the framebuffer for
- * the plane on the screen. The fence can be either a normal fence or a
- * merged one, the sync_file framework will handle both cases and use a
- * fence_array if a merged fence is received. Passing -1 here means no
- * fences to wait on.
- *
- * If the Atomic Commit request has the DRM_MODE_ATOMIC_TEST_ONLY flag
- * it will only check if the Sync File is a valid one.
- *
- * On the driver side the fence is stored on the @fence parameter of
- * &struct drm_plane_state. Drivers which also support implicit fencing
- * should set the implicit fence using drm_atomic_set_fence_for_plane(),
- * to make sure there's consistent behaviour between drivers in precedence
- * of implicit vs. explicit fencing.
- *
- * "OUT_FENCE_PTR”:
- * Use this property to pass a file descriptor pointer to DRM. Once the
- * Atomic Commit request call returns OUT_FENCE_PTR will be filled with
- * the file descriptor number of a Sync File. This Sync File contains the
- * CRTC fence that will be signaled when all framebuffers present on the
- * Atomic Commit * request for that given CRTC are scanned out on the
- * screen.
- *
- * The Atomic Commit request fails if a invalid pointer is passed. If the
- * Atomic Commit request fails for any other reason the out fence fd
- * returned will be -1. On a Atomic Commit with the
- * DRM_MODE_ATOMIC_TEST_ONLY flag the out fence will also be set to -1.
- *
- * Note that out-fences don't have a special interface to drivers and are
- * internally represented by a &struct drm_pending_vblank_event in struct
- * &drm_crtc_state, which is also used by the nonblocking atomic commit
- * helpers and for the DRM event handling for existing userspace.
- */
-
-struct drm_out_fence_state {
- s32 __user *out_fence_ptr;
- struct sync_file *sync_file;
- int fd;
-};
-
-static int setup_out_fence(struct drm_out_fence_state *fence_state,
- struct dma_fence *fence)
-{
- fence_state->fd = get_unused_fd_flags(O_CLOEXEC);
- if (fence_state->fd < 0)
- return fence_state->fd;
-
- if (put_user(fence_state->fd, fence_state->out_fence_ptr))
- return -EFAULT;
-
- fence_state->sync_file = sync_file_create(fence);
- if (!fence_state->sync_file)
- return -ENOMEM;
-
- return 0;
-}
-
-static int prepare_signaling(struct drm_device *dev,
- struct drm_atomic_state *state,
- struct drm_mode_atomic *arg,
- struct drm_file *file_priv,
- struct drm_out_fence_state **fence_state,
- unsigned int *num_fences)
-{
- struct drm_crtc *crtc;
- struct drm_crtc_state *crtc_state;
- struct drm_connector *conn;
- struct drm_connector_state *conn_state;
- int i, c = 0, ret;
-
- if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
- return 0;
-
- for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
- s32 __user *fence_ptr;
-
- fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc);
-
- if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT || fence_ptr) {
- struct drm_pending_vblank_event *e;
-
- e = create_vblank_event(crtc, arg->user_data);
- if (!e)
- return -ENOMEM;
-
- crtc_state->event = e;
- }
-
- if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
- struct drm_pending_vblank_event *e = crtc_state->event;
-
- if (!file_priv)
- continue;
-
- ret = drm_event_reserve_init(dev, file_priv, &e->base,
- &e->event.base);
- if (ret) {
- kfree(e);
- crtc_state->event = NULL;
- return ret;
- }
- }
-
- if (fence_ptr) {
- struct dma_fence *fence;
- struct drm_out_fence_state *f;
-
- f = krealloc(*fence_state, sizeof(**fence_state) *
- (*num_fences + 1), GFP_KERNEL);
- if (!f)
- return -ENOMEM;
-
- memset(&f[*num_fences], 0, sizeof(*f));
-
- f[*num_fences].out_fence_ptr = fence_ptr;
- *fence_state = f;
-
- fence = drm_crtc_create_fence(crtc);
- if (!fence)
- return -ENOMEM;
-
- ret = setup_out_fence(&f[(*num_fences)++], fence);
- if (ret) {
- dma_fence_put(fence);
- return ret;
- }
-
- crtc_state->event->base.fence = fence;
- }
-
- c++;
- }
-
- for_each_new_connector_in_state(state, conn, conn_state, i) {
- struct drm_writeback_connector *wb_conn;
- struct drm_writeback_job *job;
- struct drm_out_fence_state *f;
- struct dma_fence *fence;
- s32 __user *fence_ptr;
-
- fence_ptr = get_out_fence_for_connector(state, conn);
- if (!fence_ptr)
- continue;
-
- job = drm_atomic_get_writeback_job(conn_state);
- if (!job)
- return -ENOMEM;
-
- f = krealloc(*fence_state, sizeof(**fence_state) *
- (*num_fences + 1), GFP_KERNEL);
- if (!f)
- return -ENOMEM;
-
- memset(&f[*num_fences], 0, sizeof(*f));
-
- f[*num_fences].out_fence_ptr = fence_ptr;
- *fence_state = f;
-
- wb_conn = drm_connector_to_writeback(conn);
- fence = drm_writeback_get_out_fence(wb_conn);
- if (!fence)
- return -ENOMEM;
-
- ret = setup_out_fence(&f[(*num_fences)++], fence);
- if (ret) {
- dma_fence_put(fence);
- return ret;
- }
-
- job->out_fence = fence;
- }
-
- /*
- * Having this flag means user mode pends on event which will never
- * reach due to lack of at least one CRTC for signaling
- */
- if (c == 0 && (arg->flags & DRM_MODE_PAGE_FLIP_EVENT))
- return -EINVAL;
-
- return 0;
-}
-
-static void complete_signaling(struct drm_device *dev,
- struct drm_atomic_state *state,
- struct drm_out_fence_state *fence_state,
- unsigned int num_fences,
- bool install_fds)
-{
- struct drm_crtc *crtc;
- struct drm_crtc_state *crtc_state;
- int i;
-
- if (install_fds) {
- for (i = 0; i < num_fences; i++)
- fd_install(fence_state[i].fd,
- fence_state[i].sync_file->file);
-
- kfree(fence_state);
- return;
- }
-
- for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
- struct drm_pending_vblank_event *event = crtc_state->event;
- /*
- * Free the allocated event. drm_atomic_helper_setup_commit
- * can allocate an event too, so only free it if it's ours
- * to prevent a double free in drm_atomic_state_clear.
- */
- if (event && (event->base.fence || event->base.file_priv)) {
- drm_event_cancel_free(dev, &event->base);
- crtc_state->event = NULL;
- }
- }
-
- if (!fence_state)
- return;
-
- for (i = 0; i < num_fences; i++) {
- if (fence_state[i].sync_file)
- fput(fence_state[i].sync_file->file);
- if (fence_state[i].fd >= 0)
- put_unused_fd(fence_state[i].fd);
-
- /* If this fails log error to the user */
- if (fence_state[i].out_fence_ptr &&
- put_user(-1, fence_state[i].out_fence_ptr))
- DRM_DEBUG_ATOMIC("Couldn't clear out_fence_ptr\n");
- }
-
- kfree(fence_state);
-}
-
-int drm_mode_atomic_ioctl(struct drm_device *dev,
- void *data, struct drm_file *file_priv)
-{
- struct drm_mode_atomic *arg = data;
- uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr);
- uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr);
- uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
- uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr);
- unsigned int copied_objs, copied_props;
- struct drm_atomic_state *state;
- struct drm_modeset_acquire_ctx ctx;
- struct drm_out_fence_state *fence_state;
- int ret = 0;
- unsigned int i, j, num_fences;
-
- /* disallow for drivers not supporting atomic: */
- if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
- return -EINVAL;
-
- /* disallow for userspace that has not enabled atomic cap (even
- * though this may be a bit overkill, since legacy userspace
- * wouldn't know how to call this ioctl)
- */
- if (!file_priv->atomic)
- return -EINVAL;
-
- if (arg->flags & ~DRM_MODE_ATOMIC_FLAGS)
- return -EINVAL;
-
- if (arg->reserved)
- return -EINVAL;
-
- if ((arg->flags & DRM_MODE_PAGE_FLIP_ASYNC) &&
- !dev->mode_config.async_page_flip)
- return -EINVAL;
-
- /* can't test and expect an event at the same time. */
- if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) &&
- (arg->flags & DRM_MODE_PAGE_FLIP_EVENT))
- return -EINVAL;
-
- drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
-
- state = drm_atomic_state_alloc(dev);
- if (!state)
- return -ENOMEM;
-
- state->acquire_ctx = &ctx;
- state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET);
-
-retry:
- copied_objs = 0;
- copied_props = 0;
- fence_state = NULL;
- num_fences = 0;
-
- for (i = 0; i < arg->count_objs; i++) {
- uint32_t obj_id, count_props;
- struct drm_mode_object *obj;
-
- if (get_user(obj_id, objs_ptr + copied_objs)) {
- ret = -EFAULT;
- goto out;
- }
-
- obj = drm_mode_object_find(dev, file_priv, obj_id, DRM_MODE_OBJECT_ANY);
- if (!obj) {
- ret = -ENOENT;
- goto out;
- }
-
- if (!obj->properties) {
- drm_mode_object_put(obj);
- ret = -ENOENT;
- goto out;
- }
-
- if (get_user(count_props, count_props_ptr + copied_objs)) {
- drm_mode_object_put(obj);
- ret = -EFAULT;
- goto out;
- }
-
- copied_objs++;
-
- for (j = 0; j < count_props; j++) {
- uint32_t prop_id;
- uint64_t prop_value;
- struct drm_property *prop;
-
- if (get_user(prop_id, props_ptr + copied_props)) {
- drm_mode_object_put(obj);
- ret = -EFAULT;
- goto out;
- }
-
- prop = drm_mode_obj_find_prop_id(obj, prop_id);
- if (!prop) {
- drm_mode_object_put(obj);
- ret = -ENOENT;
- goto out;
- }
-
- if (copy_from_user(&prop_value,
- prop_values_ptr + copied_props,
- sizeof(prop_value))) {
- drm_mode_object_put(obj);
- ret = -EFAULT;
- goto out;
- }
-
- ret = drm_atomic_set_property(state, obj, prop,
- prop_value);
- if (ret) {
- drm_mode_object_put(obj);
- goto out;
- }
-
- copied_props++;
- }
-
- drm_mode_object_put(obj);
- }
-
- ret = prepare_signaling(dev, state, arg, file_priv, &fence_state,
- &num_fences);
- if (ret)
- goto out;
-
- if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) {
- ret = drm_atomic_check_only(state);
- } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) {
- ret = drm_atomic_nonblocking_commit(state);
- } else {
- if (unlikely(drm_debug & DRM_UT_STATE))
- drm_atomic_print_state(state);
-
- ret = drm_atomic_commit(state);
- }
-
-out:
- complete_signaling(dev, state, fence_state, num_fences, !ret);
-
- if (ret == -EDEADLK) {
- drm_atomic_state_clear(state);
- ret = drm_modeset_backoff(&ctx);
- if (!ret)
- goto retry;
- }
-
- drm_atomic_state_put(state);
-
- drm_modeset_drop_locks(&ctx);
- drm_modeset_acquire_fini(&ctx);
-
- return ret;
-}
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 2c23a48482da..3cf1aa132778 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -27,6 +27,7 @@
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_uapi.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_atomic_helper.h>
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
new file mode 100644
index 000000000000..26690a664ec6
--- /dev/null
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -0,0 +1,1393 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Copyright (C) 2014 Intel Corp.
+ * Copyright (C) 2018 Intel Corp.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rob Clark <robdclark@gmail.com>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+#include <drm/drm_atomic_uapi.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_print.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_writeback.h>
+#include <drm/drm_vblank.h>
+
+#include <linux/dma-fence.h>
+#include <linux/uaccess.h>
+#include <linux/sync_file.h>
+#include <linux/file.h>
+
+#include "drm_crtc_internal.h"
+
+/**
+ * DOC: overview
+ *
+ * This file contains the marshalling and demarshalling glue for the atomic UAPI
+ * in all it's form: The monster ATOMIC IOCTL itself, code for GET_PROPERTY and
+ * SET_PROPERTY IOCTls. Plus interface functions for compatibility helpers and
+ * drivers which have special needs to construct their own atomic updates, e.g.
+ * for load detect or similiar.
+ */
+
+/**
+ * drm_atomic_set_mode_for_crtc - set mode for CRTC
+ * @state: the CRTC whose incoming state to update
+ * @mode: kernel-internal mode to use for the CRTC, or NULL to disable
+ *
+ * Set a mode (originating from the kernel) on the desired CRTC state and update
+ * the enable property.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure. Cannot return -EDEADLK.
+ */
+int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state,
+ const struct drm_display_mode *mode)
+{
+ struct drm_crtc *crtc = state->crtc;
+ struct drm_mode_modeinfo umode;
+
+ /* Early return for no change. */
+ if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0)
+ return 0;
+
+ drm_property_blob_put(state->mode_blob);
+ state->mode_blob = NULL;
+
+ if (mode) {
+ drm_mode_convert_to_umode(&umode, mode);
+ state->mode_blob =
+ drm_property_create_blob(state->crtc->dev,
+ sizeof(umode),
+ &umode);
+ if (IS_ERR(state->mode_blob))
+ return PTR_ERR(state->mode_blob);
+
+ drm_mode_copy(&state->mode, mode);
+ state->enable = true;
+ DRM_DEBUG_ATOMIC("Set [MODE:%s] for [CRTC:%d:%s] state %p\n",
+ mode->name, crtc->base.id, crtc->name, state);
+ } else {
+ memset(&state->mode, 0, sizeof(state->mode));
+ state->enable = false;
+ DRM_DEBUG_ATOMIC("Set [NOMODE] for [CRTC:%d:%s] state %p\n",
+ crtc->base.id, crtc->name, state);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_atomic_set_mode_for_crtc);
+
+/**
+ * drm_atomic_set_mode_prop_for_crtc - set mode for CRTC
+ * @state: the CRTC whose incoming state to update
+ * @blob: pointer to blob property to use for mode
+ *
+ * Set a mode (originating from a blob property) on the desired CRTC state.
+ * This function will take a reference on the blob property for the CRTC state,
+ * and release the reference held on the state's existing mode property, if any
+ * was set.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure. Cannot return -EDEADLK.
+ */
+int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
+ struct drm_property_blob *blob)
+{
+ struct drm_crtc *crtc = state->crtc;
+
+ if (blob == state->mode_blob)
+ return 0;
+
+ drm_property_blob_put(state->mode_blob);
+ state->mode_blob = NULL;
+
+ memset(&state->mode, 0, sizeof(state->mode));
+
+ if (blob) {
+ int ret;
+
+ if (blob->length != sizeof(struct drm_mode_modeinfo)) {
+ DRM_DEBUG_ATOMIC("[CRTC:%d:%s] bad mode blob length: %zu\n",
+ crtc->base.id, crtc->name,
+ blob->length);
+ return -EINVAL;
+ }
+
+ ret = drm_mode_convert_umode(crtc->dev,
+ &state->mode, blob->data);
+ if (ret) {
+ DRM_DEBUG_ATOMIC("[CRTC:%d:%s] invalid mode (ret=%d, status=%s):\n",
+ crtc->base.id, crtc->name,
+ ret, drm_get_mode_status_name(state->mode.status));
+ drm_mode_debug_printmodeline(&state->mode);
+ return -EINVAL;
+ }
+
+ state->mode_blob = drm_property_blob_get(blob);
+ state->enable = true;
+ DRM_DEBUG_ATOMIC("Set [MODE:%s] for [CRTC:%d:%s] state %p\n",
+ state->mode.name, crtc->base.id, crtc->name,
+ state);
+ } else {
+ state->enable = false;
+ DRM_DEBUG_ATOMIC("Set [NOMODE] for [CRTC:%d:%s] state %p\n",
+ crtc->base.id, crtc->name, state);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc);
+
+/**
+ * drm_atomic_set_crtc_for_plane - set crtc for plane
+ * @plane_state: the plane whose incoming state to update
+ * @crtc: crtc to use for the plane
+ *
+ * Changing the assigned crtc for a plane requires us to grab the lock and state
+ * for the new crtc, as needed. This function takes care of all these details
+ * besides updating the pointer in the state object itself.
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
+ * then the w/w mutex code has detected a deadlock and the entire atomic
+ * sequence must be restarted. All other errors are fatal.
+ */
+int
+drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
+ struct drm_crtc *crtc)
+{
+ struct drm_plane *plane = plane_state->plane;
+ struct drm_crtc_state *crtc_state;
+ /* Nothing to do for same crtc*/
+ if (plane_state->crtc == crtc)
+ return 0;
+ if (plane_state->crtc) {
+ crtc_state = drm_atomic_get_crtc_state(plane_state->state,
+ plane_state->crtc);
+ if (WARN_ON(IS_ERR(crtc_state)))
+ return PTR_ERR(crtc_state);
+
+ crtc_state->plane_mask &= ~drm_plane_mask(plane);
+ }
+
+ plane_state->crtc = crtc;
+
+ if (crtc) {
+ crtc_state = drm_atomic_get_crtc_state(plane_state->state,
+ crtc);
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
+ crtc_state->plane_mask |= drm_plane_mask(plane);
+ }
+
+ if (crtc)
+ DRM_DEBUG_ATOMIC("Link [PLANE:%d:%s] state %p to [CRTC:%d:%s]\n",
+ plane->base.id, plane->name, plane_state,
+ crtc->base.id, crtc->name);
+ else
+ DRM_DEBUG_ATOMIC("Link [PLANE:%d:%s] state %p to [NOCRTC]\n",
+ plane->base.id, plane->name, plane_state);
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane);
+
+/**
+ * drm_atomic_set_fb_for_plane - set framebuffer for plane
+ * @plane_state: atomic state object for the plane
+ * @fb: fb to use for the plane
+ *
+ * Changing the assigned framebuffer for a plane requires us to grab a reference
+ * to the new fb and drop the reference to the old fb, if there is one. This
+ * function takes care of all these details besides updating the pointer in the
+ * state object itself.
+ */
+void
+drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
+ struct drm_framebuffer *fb)
+{
+ struct drm_plane *plane = plane_state->plane;
+
+ if (fb)
+ DRM_DEBUG_ATOMIC("Set [FB:%d] for [PLANE:%d:%s] state %p\n",
+ fb->base.id, plane->base.id, plane->name,
+ plane_state);
+ else
+ DRM_DEBUG_ATOMIC("Set [NOFB] for [PLANE:%d:%s] state %p\n",
+ plane->base.id, plane->name, plane_state);
+
+ drm_framebuffer_assign(&plane_state->fb, fb);
+}
+EXPORT_SYMBOL(drm_atomic_set_fb_for_plane);
+
+/**
+ * drm_atomic_set_fence_for_plane - set fence for plane
+ * @plane_state: atomic state object for the plane
+ * @fence: dma_fence to use for the plane
+ *
+ * Helper to setup the plane_state fence in case it is not set yet.
+ * By using this drivers doesn't need to worry if the user choose
+ * implicit or explicit fencing.
+ *
+ * This function will not set the fence to the state if it was set
+ * via explicit fencing interfaces on the atomic ioctl. In that case it will
+ * drop the reference to the fence as we are not storing it anywhere.
+ * Otherwise, if &drm_plane_state.fence is not set this function we just set it
+ * with the received implicit fence. In both cases this function consumes a
+ * reference for @fence.
+ *
+ * This way explicit fencing can be used to overrule implicit fencing, which is
+ * important to make explicit fencing use-cases work: One example is using one
+ * buffer for 2 screens with different refresh rates. Implicit fencing will
+ * clamp rendering to the refresh rate of the slower screen, whereas explicit
+ * fence allows 2 independent render and display loops on a single buffer. If a
+ * driver allows obeys both implicit and explicit fences for plane updates, then
+ * it will break all the benefits of explicit fencing.
+ */
+void
+drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state,
+ struct dma_fence *fence)
+{
+ if (plane_state->fence) {
+ dma_fence_put(fence);
+ return;
+ }
+
+ plane_state->fence = fence;
+}
+EXPORT_SYMBOL(drm_atomic_set_fence_for_plane);
+
+/**
+ * drm_atomic_set_crtc_for_connector - set crtc for connector
+ * @conn_state: atomic state object for the connector
+ * @crtc: crtc to use for the connector
+ *
+ * Changing the assigned crtc for a connector requires us to grab the lock and
+ * state for the new crtc, as needed. This function takes care of all these
+ * details besides updating the pointer in the state object itself.
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
+ * then the w/w mutex code has detected a deadlock and the entire atomic
+ * sequence must be restarted. All other errors are fatal.
+ */
+int
+drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
+ struct drm_crtc *crtc)
+{
+ struct drm_connector *connector = conn_state->connector;
+ struct drm_crtc_state *crtc_state;
+
+ if (conn_state->crtc == crtc)
+ return 0;
+
+ if (conn_state->crtc) {
+ crtc_state = drm_atomic_get_new_crtc_state(conn_state->state,
+ conn_state->crtc);
+
+ crtc_state->connector_mask &=
+ ~drm_connector_mask(conn_state->connector);
+
+ drm_connector_put(conn_state->connector);
+ conn_state->crtc = NULL;
+ }
+
+ if (crtc) {
+ crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc);
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
+
+ crtc_state->connector_mask |=
+ drm_connector_mask(conn_state->connector);
+
+ drm_connector_get(conn_state->connector);
+ conn_state->crtc = crtc;
+
+ DRM_DEBUG_ATOMIC("Link [CONNECTOR:%d:%s] state %p to [CRTC:%d:%s]\n",
+ connector->base.id, connector->name,
+ conn_state, crtc->base.id, crtc->name);
+ } else {
+ DRM_DEBUG_ATOMIC("Link [CONNECTOR:%d:%s] state %p to [NOCRTC]\n",
+ connector->base.id, connector->name,
+ conn_state);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector);
+
+static void set_out_fence_for_crtc(struct drm_atomic_state *state,
+ struct drm_crtc *crtc, s32 __user *fence_ptr)
+{
+ state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = fence_ptr;
+}
+
+static s32 __user *get_out_fence_for_crtc(struct drm_atomic_state *state,
+ struct drm_crtc *crtc)
+{
+ s32 __user *fence_ptr;
+
+ fence_ptr = state->crtcs[drm_crtc_index(crtc)].out_fence_ptr;
+ state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = NULL;
+
+ return fence_ptr;
+}
+
+static int set_out_fence_for_connector(struct drm_atomic_state *state,
+ struct drm_connector *connector,
+ s32 __user *fence_ptr)
+{
+ unsigned int index = drm_connector_index(connector);
+
+ if (!fence_ptr)
+ return 0;
+
+ if (put_user(-1, fence_ptr))
+ return -EFAULT;
+
+ state->connectors[index].out_fence_ptr = fence_ptr;
+
+ return 0;
+}
+
+static s32 __user *get_out_fence_for_connector(struct drm_atomic_state *state,
+ struct drm_connector *connector)
+{
+ unsigned int index = drm_connector_index(connector);
+ s32 __user *fence_ptr;
+
+ fence_ptr = state->connectors[index].out_fence_ptr;
+ state->connectors[index].out_fence_ptr = NULL;
+
+ return fence_ptr;
+}
+
+static int
+drm_atomic_replace_property_blob_from_id(struct drm_device *dev,
+ struct drm_property_blob **blob,
+ uint64_t blob_id,
+ ssize_t expected_size,
+ ssize_t expected_elem_size,
+ bool *replaced)
+{
+ struct drm_property_blob *new_blob = NULL;
+
+ if (blob_id != 0) {
+ new_blob = drm_property_lookup_blob(dev, blob_id);
+ if (new_blob == NULL)
+ return -EINVAL;
+
+ if (expected_size > 0 &&
+ new_blob->length != expected_size) {
+ drm_property_blob_put(new_blob);
+ return -EINVAL;
+ }
+ if (expected_elem_size > 0 &&
+ new_blob->length % expected_elem_size != 0) {
+ drm_property_blob_put(new_blob);
+ return -EINVAL;
+ }
+ }
+
+ *replaced |= drm_property_replace_blob(blob, new_blob);
+ drm_property_blob_put(new_blob);
+
+ return 0;
+}
+
+static int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
+ struct drm_crtc_state *state, struct drm_property *property,
+ uint64_t val)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_mode_config *config = &dev->mode_config;
+ bool replaced = false;
+ int ret;
+
+ if (property == config->prop_active)
+ state->active = val;
+ else if (property == config->prop_mode_id) {
+ struct drm_property_blob *mode =
+ drm_property_lookup_blob(dev, val);
+ ret = drm_atomic_set_mode_prop_for_crtc(state, mode);
+ drm_property_blob_put(mode);
+ return ret;
+ } else if (property == config->degamma_lut_property) {
+ ret = drm_atomic_replace_property_blob_from_id(dev,
+ &state->degamma_lut,
+ val,
+ -1, sizeof(struct drm_color_lut),
+ &replaced);
+ state->color_mgmt_changed |= replaced;
+ return ret;
+ } else if (property == config->ctm_property) {
+ ret = drm_atomic_replace_property_blob_from_id(dev,
+ &state->ctm,
+ val,
+ sizeof(struct drm_color_ctm), -1,
+ &replaced);
+ state->color_mgmt_changed |= replaced;
+ return ret;
+ } else if (property == config->gamma_lut_property) {
+ ret = drm_atomic_replace_property_blob_from_id(dev,
+ &state->gamma_lut,
+ val,
+ -1, sizeof(struct drm_color_lut),
+ &replaced);
+ state->color_mgmt_changed |= replaced;
+ return ret;
+ } else if (property == config->prop_out_fence_ptr) {
+ s32 __user *fence_ptr = u64_to_user_ptr(val);
+
+ if (!fence_ptr)
+ return 0;
+
+ if (put_user(-1, fence_ptr))
+ return -EFAULT;
+
+ set_out_fence_for_crtc(state->state, crtc, fence_ptr);
+ } else if (crtc->funcs->atomic_set_property) {
+ return crtc->funcs->atomic_set_property(crtc, state, property, val);
+ } else {
+ DRM_DEBUG_ATOMIC("[CRTC:%d:%s] unknown property [PROP:%d:%s]]\n",
+ crtc->base.id, crtc->name,
+ property->base.id, property->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+drm_atomic_crtc_get_property(struct drm_crtc *crtc,
+ const struct drm_crtc_state *state,
+ struct drm_property *property, uint64_t *val)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_mode_config *config = &dev->mode_config;
+
+ if (property == config->prop_active)
+ *val = state->active;
+ else if (property == config->prop_mode_id)
+ *val = (state->mode_blob) ? state->mode_blob->base.id : 0;
+ else if (property == config->degamma_lut_property)
+ *val = (state->degamma_lut) ? state->degamma_lut->base.id : 0;
+ else if (property == config->ctm_property)
+ *val = (state->ctm) ? state->ctm->base.id : 0;
+ else if (property == config->gamma_lut_property)
+ *val = (state->gamma_lut) ? state->gamma_lut->base.id : 0;
+ else if (property == config->prop_out_fence_ptr)
+ *val = 0;
+ else if (crtc->funcs->atomic_get_property)
+ return crtc->funcs->atomic_get_property(crtc, state, property, val);
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static int drm_atomic_plane_set_property(struct drm_plane *plane,
+ struct drm_plane_state *state, struct drm_property *property,
+ uint64_t val)
+{
+ struct drm_device *dev = plane->dev;
+ struct drm_mode_config *config = &dev->mode_config;
+
+ if (property == config->prop_fb_id) {
+ struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, NULL, val);
+ drm_atomic_set_fb_for_plane(state, fb);
+ if (fb)
+ drm_framebuffer_put(fb);
+ } else if (property == config->prop_in_fence_fd) {
+ if (state->fence)
+ return -EINVAL;
+
+ if (U642I64(val) == -1)
+ return 0;
+
+ state->fence = sync_file_get_fence(val);
+ if (!state->fence)
+ return -EINVAL;
+
+ } else if (property == config->prop_crtc_id) {
+ struct drm_crtc *crtc = drm_crtc_find(dev, NULL, val);
+ return drm_atomic_set_crtc_for_plane(state, crtc);
+ } else if (property == config->prop_crtc_x) {
+ state->crtc_x = U642I64(val);
+ } else if (property == config->prop_crtc_y) {
+ state->crtc_y = U642I64(val);
+ } else if (property == config->prop_crtc_w) {
+ state->crtc_w = val;
+ } else if (property == config->prop_crtc_h) {
+ state->crtc_h = val;
+ } else if (property == config->prop_src_x) {
+ state->src_x = val;
+ } else if (property == config->prop_src_y) {
+ state->src_y = val;
+ } else if (property == config->prop_src_w) {
+ state->src_w = val;
+ } else if (property == config->prop_src_h) {
+ state->src_h = val;
+ } else if (property == plane->alpha_property) {
+ state->alpha = val;
+ } else if (property == plane->blend_mode_property) {
+ state->pixel_blend_mode = val;
+ } else if (property == plane->rotation_property) {
+ if (!is_power_of_2(val & DRM_MODE_ROTATE_MASK)) {
+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] bad rotation bitmask: 0x%llx\n",
+ plane->base.id, plane->name, val);
+ return -EINVAL;
+ }
+ state->rotation = val;
+ } else if (property == plane->zpos_property) {
+ state->zpos = val;
+ } else if (property == plane->color_encoding_property) {
+ state->color_encoding = val;
+ } else if (property == plane->color_range_property) {
+ state->color_range = val;
+ } else if (plane->funcs->atomic_set_property) {
+ return plane->funcs->atomic_set_property(plane, state,
+ property, val);
+ } else {
+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] unknown property [PROP:%d:%s]]\n",
+ plane->base.id, plane->name,
+ property->base.id, property->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+drm_atomic_plane_get_property(struct drm_plane *plane,
+ const struct drm_plane_state *state,
+ struct drm_property *property, uint64_t *val)
+{
+ struct drm_device *dev = plane->dev;
+ struct drm_mode_config *config = &dev->mode_config;
+
+ if (property == config->prop_fb_id) {
+ *val = (state->fb) ? state->fb->base.id : 0;
+ } else if (property == config->prop_in_fence_fd) {
+ *val = -1;
+ } else if (property == config->prop_crtc_id) {
+ *val = (state->crtc) ? state->crtc->base.id : 0;
+ } else if (property == config->prop_crtc_x) {
+ *val = I642U64(state->crtc_x);
+ } else if (property == config->prop_crtc_y) {
+ *val = I642U64(state->crtc_y);
+ } else if (property == config->prop_crtc_w) {
+ *val = state->crtc_w;
+ } else if (property == config->prop_crtc_h) {
+ *val = state->crtc_h;
+ } else if (property == config->prop_src_x) {
+ *val = state->src_x;
+ } else if (property == config->prop_src_y) {
+ *val = state->src_y;
+ } else if (property == config->prop_src_w) {
+ *val = state->src_w;
+ } else if (property == config->prop_src_h) {
+ *val = state->src_h;
+ } else if (property == plane->alpha_property) {
+ *val = state->alpha;
+ } else if (property == plane->blend_mode_property) {
+ *val = state->pixel_blend_mode;
+ } else if (property == plane->rotation_property) {
+ *val = state->rotation;
+ } else if (property == plane->zpos_property) {
+ *val = state->zpos;
+ } else if (property == plane->color_encoding_property) {
+ *val = state->color_encoding;
+ } else if (property == plane->color_range_property) {
+ *val = state->color_range;
+ } else if (plane->funcs->atomic_get_property) {
+ return plane->funcs->atomic_get_property(plane, state, property, val);
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct drm_writeback_job *
+drm_atomic_get_writeback_job(struct drm_connector_state *conn_state)
+{
+ WARN_ON(conn_state->connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK);
+
+ if (!conn_state->writeback_job)
+ conn_state->writeback_job =
+ kzalloc(sizeof(*conn_state->writeback_job), GFP_KERNEL);
+
+ return conn_state->writeback_job;
+}
+
+static int drm_atomic_set_writeback_fb_for_connector(
+ struct drm_connector_state *conn_state,
+ struct drm_framebuffer *fb)
+{
+ struct drm_writeback_job *job =
+ drm_atomic_get_writeback_job(conn_state);
+ if (!job)
+ return -ENOMEM;
+
+ drm_framebuffer_assign(&job->fb, fb);
+
+ if (fb)
+ DRM_DEBUG_ATOMIC("Set [FB:%d] for connector state %p\n",
+ fb->base.id, conn_state);
+ else
+ DRM_DEBUG_ATOMIC("Set [NOFB] for connector state %p\n",
+ conn_state);
+
+ return 0;
+}
+
+static int drm_atomic_connector_set_property(struct drm_connector *connector,
+ struct drm_connector_state *state, struct drm_property *property,
+ uint64_t val)
+{
+ struct drm_device *dev = connector->dev;
+ struct drm_mode_config *config = &dev->mode_config;
+
+ if (property == config->prop_crtc_id) {
+ struct drm_crtc *crtc = drm_crtc_find(dev, NULL, val);
+ return drm_atomic_set_crtc_for_connector(state, crtc);
+ } else if (property == config->dpms_property) {
+ /* setting DPMS property requires special handling, which
+ * is done in legacy setprop path for us. Disallow (for
+ * now?) atomic writes to DPMS property:
+ */
+ return -EINVAL;
+ } else if (property == config->tv_select_subconnector_property) {
+ state->tv.subconnector = val;
+ } else if (property == config->tv_left_margin_property) {
+ state->tv.margins.left = val;
+ } else if (property == config->tv_right_margin_property) {
+ state->tv.margins.right = val;
+ } else if (property == config->tv_top_margin_property) {
+ state->tv.margins.top = val;
+ } else if (property == config->tv_bottom_margin_property) {
+ state->tv.margins.bottom = val;
+ } else if (property == config->tv_mode_property) {
+ state->tv.mode = val;
+ } else if (property == config->tv_brightness_property) {
+ state->tv.brightness = val;
+ } else if (property == config->tv_contrast_property) {
+ state->tv.contrast = val;
+ } else if (property == config->tv_flicker_reduction_property) {
+ state->tv.flicker_reduction = val;
+ } else if (property == config->tv_overscan_property) {
+ state->tv.overscan = val;
+ } else if (property == config->tv_saturation_property) {
+ state->tv.saturation = val;
+ } else if (property == config->tv_hue_property) {
+ state->tv.hue = val;
+ } else if (property == config->link_status_property) {
+ /* Never downgrade from GOOD to BAD on userspace's request here,
+ * only hw issues can do that.
+ *
+ * For an atomic property the userspace doesn't need to be able
+ * to understand all the properties, but needs to be able to
+ * restore the state it wants on VT switch. So if the userspace
+ * tries to change the link_status from GOOD to BAD, driver
+ * silently rejects it and returns a 0. This prevents userspace
+ * from accidently breaking the display when it restores the
+ * state.
+ */
+ if (state->link_status != DRM_LINK_STATUS_GOOD)
+ state->link_status = val;
+ } else if (property == config->aspect_ratio_property) {
+ state->picture_aspect_ratio = val;
+ } else if (property == config->content_type_property) {
+ state->content_type = val;
+ } else if (property == connector->scaling_mode_property) {
+ state->scaling_mode = val;
+ } else if (property == connector->content_protection_property) {
+ if (val == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
+ DRM_DEBUG_KMS("only drivers can set CP Enabled\n");
+ return -EINVAL;
+ }
+ state->content_protection = val;
+ } else if (property == config->writeback_fb_id_property) {
+ struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, NULL, val);
+ int ret = drm_atomic_set_writeback_fb_for_connector(state, fb);
+ if (fb)
+ drm_framebuffer_put(fb);
+ return ret;
+ } else if (property == config->writeback_out_fence_ptr_property) {
+ s32 __user *fence_ptr = u64_to_user_ptr(val);
+
+ return set_out_fence_for_connector(state->state, connector,
+ fence_ptr);
+ } else if (connector->funcs->atomic_set_property) {
+ return connector->funcs->atomic_set_property(connector,
+ state, property, val);
+ } else {
+ DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] unknown property [PROP:%d:%s]]\n",
+ connector->base.id, connector->name,
+ property->base.id, property->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+drm_atomic_connector_get_property(struct drm_connector *connector,
+ const struct drm_connector_state *state,
+ struct drm_property *property, uint64_t *val)
+{
+ struct drm_device *dev = connector->dev;
+ struct drm_mode_config *config = &dev->mode_config;
+
+ if (property == config->prop_crtc_id) {
+ *val = (state->crtc) ? state->crtc->base.id : 0;
+ } else if (property == config->dpms_property) {
+ *val = connector->dpms;
+ } else if (property == config->tv_select_subconnector_property) {
+ *val = state->tv.subconnector;
+ } else if (property == config->tv_left_margin_property) {
+ *val = state->tv.margins.left;
+ } else if (property == config->tv_right_margin_property) {
+ *val = state->tv.margins.right;
+ } else if (property == config->tv_top_margin_property) {
+ *val = state->tv.margins.top;
+ } else if (property == config->tv_bottom_margin_property) {
+ *val = state->tv.margins.bottom;
+ } else if (property == config->tv_mode_property) {
+ *val = state->tv.mode;
+ } else if (property == config->tv_brightness_property) {
+ *val = state->tv.brightness;
+ } else if (property == config->tv_contrast_property) {
+ *val = state->tv.contrast;
+ } else if (property == config->tv_flicker_reduction_property) {
+ *val = state->tv.flicker_reduction;
+ } else if (property == config->tv_overscan_property) {
+ *val = state->tv.overscan;
+ } else if (property == config->tv_saturation_property) {
+ *val = state->tv.saturation;
+ } else if (property == config->tv_hue_property) {
+ *val = state->tv.hue;
+ } else if (property == config->link_status_property) {
+ *val = state->link_status;
+ } else if (property == config->aspect_ratio_property) {
+ *val = state->picture_aspect_ratio;
+ } else if (property == config->content_type_property) {
+ *val = state->content_type;
+ } else if (property == connector->scaling_mode_property) {
+ *val = state->scaling_mode;
+ } else if (property == connector->content_protection_property) {
+ *val = state->content_protection;
+ } else if (property == config->writeback_fb_id_property) {
+ /* Writeback framebuffer is one-shot, write and forget */
+ *val = 0;
+ } else if (property == config->writeback_out_fence_ptr_property) {
+ *val = 0;
+ } else if (connector->funcs->atomic_get_property) {
+ return connector->funcs->atomic_get_property(connector,
+ state, property, val);
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int drm_atomic_get_property(struct drm_mode_object *obj,
+ struct drm_property *property, uint64_t *val)
+{
+ struct drm_device *dev = property->dev;
+ int ret;
+
+ switch (obj->type) {
+ case DRM_MODE_OBJECT_CONNECTOR: {
+ struct drm_connector *connector = obj_to_connector(obj);
+ WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
+ ret = drm_atomic_connector_get_property(connector,
+ connector->state, property, val);
+ break;
+ }
+ case DRM_MODE_OBJECT_CRTC: {
+ struct drm_crtc *crtc = obj_to_crtc(obj);
+ WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
+ ret = drm_atomic_crtc_get_property(crtc,
+ crtc->state, property, val);
+ break;
+ }
+ case DRM_MODE_OBJECT_PLANE: {
+ struct drm_plane *plane = obj_to_plane(obj);
+ WARN_ON(!drm_modeset_is_locked(&plane->mutex));
+ ret = drm_atomic_plane_get_property(plane,
+ plane->state, property, val);
+ break;
+ }
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * The big monster ioctl
+ */
+
+static struct drm_pending_vblank_event *create_vblank_event(
+ struct drm_crtc *crtc, uint64_t user_data)
+{
+ struct drm_pending_vblank_event *e = NULL;
+
+ e = kzalloc(sizeof *e, GFP_KERNEL);
+ if (!e)
+ return NULL;
+
+ e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
+ e->event.base.length = sizeof(e->event);
+ e->event.vbl.crtc_id = crtc->base.id;
+ e->event.vbl.user_data = user_data;
+
+ return e;
+}
+
+int drm_atomic_connector_commit_dpms(struct drm_atomic_state *state,
+ struct drm_connector *connector,
+ int mode)
+{
+ struct drm_connector *tmp_connector;
+ struct drm_connector_state *new_conn_state;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *crtc_state;
+ int i, ret, old_mode = connector->dpms;
+ bool active = false;
+
+ ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
+ state->acquire_ctx);
+ if (ret)
+ return ret;
+
+ if (mode != DRM_MODE_DPMS_ON)
+ mode = DRM_MODE_DPMS_OFF;
+ connector->dpms = mode;
+
+ crtc = connector->state->crtc;
+ if (!crtc)
+ goto out;
+ ret = drm_atomic_add_affected_connectors(state, crtc);
+ if (ret)
+ goto out;
+
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ if (IS_ERR(crtc_state)) {
+ ret = PTR_ERR(crtc_state);
+ goto out;
+ }
+
+ for_each_new_connector_in_state(state, tmp_connector, new_conn_state, i) {
+ if (new_conn_state->crtc != crtc)
+ continue;
+ if (tmp_connector->dpms == DRM_MODE_DPMS_ON) {
+ active = true;
+ break;
+ }
+ }
+
+ crtc_state->active = active;
+ ret = drm_atomic_commit(state);
+out:
+ if (ret != 0)
+ connector->dpms = old_mode;
+ return ret;
+}
+
+int drm_atomic_set_property(struct drm_atomic_state *state,
+ struct drm_mode_object *obj,
+ struct drm_property *prop,
+ uint64_t prop_value)
+{
+ struct drm_mode_object *ref;
+ int ret;
+
+ if (!drm_property_change_valid_get(prop, prop_value, &ref))
+ return -EINVAL;
+
+ switch (obj->type) {
+ case DRM_MODE_OBJECT_CONNECTOR: {
+ struct drm_connector *connector = obj_to_connector(obj);
+ struct drm_connector_state *connector_state;
+
+ connector_state = drm_atomic_get_connector_state(state, connector);
+ if (IS_ERR(connector_state)) {
+ ret = PTR_ERR(connector_state);
+ break;
+ }
+
+ ret = drm_atomic_connector_set_property(connector,
+ connector_state, prop, prop_value);
+ break;
+ }
+ case DRM_MODE_OBJECT_CRTC: {
+ struct drm_crtc *crtc = obj_to_crtc(obj);
+ struct drm_crtc_state *crtc_state;
+
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ if (IS_ERR(crtc_state)) {
+ ret = PTR_ERR(crtc_state);
+ break;
+ }
+
+ ret = drm_atomic_crtc_set_property(crtc,
+ crtc_state, prop, prop_value);
+ break;
+ }
+ case DRM_MODE_OBJECT_PLANE: {
+ struct drm_plane *plane = obj_to_plane(obj);
+ struct drm_plane_state *plane_state;
+
+ plane_state = drm_atomic_get_plane_state(state, plane);
+ if (IS_ERR(plane_state)) {
+ ret = PTR_ERR(plane_state);
+ break;
+ }
+
+ ret = drm_atomic_plane_set_property(plane,
+ plane_state, prop, prop_value);
+ break;
+ }
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ drm_property_change_valid_put(prop, ref);
+ return ret;
+}
+
+/**
+ * DOC: explicit fencing properties
+ *
+ * Explicit fencing allows userspace to control the buffer synchronization
+ * between devices. A Fence or a group of fences are transfered to/from
+ * userspace using Sync File fds and there are two DRM properties for that.
+ * IN_FENCE_FD on each DRM Plane to send fences to the kernel and
+ * OUT_FENCE_PTR on each DRM CRTC to receive fences from the kernel.
+ *
+ * As a contrast, with implicit fencing the kernel keeps track of any
+ * ongoing rendering, and automatically ensures that the atomic update waits
+ * for any pending rendering to complete. For shared buffers represented with
+ * a &struct dma_buf this is tracked in &struct reservation_object.
+ * Implicit syncing is how Linux traditionally worked (e.g. DRI2/3 on X.org),
+ * whereas explicit fencing is what Android wants.
+ *
+ * "IN_FENCE_FD”:
+ * Use this property to pass a fence that DRM should wait on before
+ * proceeding with the Atomic Commit request and show the framebuffer for
+ * the plane on the screen. The fence can be either a normal fence or a
+ * merged one, the sync_file framework will handle both cases and use a
+ * fence_array if a merged fence is received. Passing -1 here means no
+ * fences to wait on.
+ *
+ * If the Atomic Commit request has the DRM_MODE_ATOMIC_TEST_ONLY flag
+ * it will only check if the Sync File is a valid one.
+ *
+ * On the driver side the fence is stored on the @fence parameter of
+ * &struct drm_plane_state. Drivers which also support implicit fencing
+ * should set the implicit fence using drm_atomic_set_fence_for_plane(),
+ * to make sure there's consistent behaviour between drivers in precedence
+ * of implicit vs. explicit fencing.
+ *
+ * "OUT_FENCE_PTR”:
+ * Use this property to pass a file descriptor pointer to DRM. Once the
+ * Atomic Commit request call returns OUT_FENCE_PTR will be filled with
+ * the file descriptor number of a Sync File. This Sync File contains the
+ * CRTC fence that will be signaled when all framebuffers present on the
+ * Atomic Commit * request for that given CRTC are scanned out on the
+ * screen.
+ *
+ * The Atomic Commit request fails if a invalid pointer is passed. If the
+ * Atomic Commit request fails for any other reason the out fence fd
+ * returned will be -1. On a Atomic Commit with the
+ * DRM_MODE_ATOMIC_TEST_ONLY flag the out fence will also be set to -1.
+ *
+ * Note that out-fences don't have a special interface to drivers and are
+ * internally represented by a &struct drm_pending_vblank_event in struct
+ * &drm_crtc_state, which is also used by the nonblocking atomic commit
+ * helpers and for the DRM event handling for existing userspace.
+ */
+
+struct drm_out_fence_state {
+ s32 __user *out_fence_ptr;
+ struct sync_file *sync_file;
+ int fd;
+};
+
+static int setup_out_fence(struct drm_out_fence_state *fence_state,
+ struct dma_fence *fence)
+{
+ fence_state->fd = get_unused_fd_flags(O_CLOEXEC);
+ if (fence_state->fd < 0)
+ return fence_state->fd;
+
+ if (put_user(fence_state->fd, fence_state->out_fence_ptr))
+ return -EFAULT;
+
+ fence_state->sync_file = sync_file_create(fence);
+ if (!fence_state->sync_file)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int prepare_signaling(struct drm_device *dev,
+ struct drm_atomic_state *state,
+ struct drm_mode_atomic *arg,
+ struct drm_file *file_priv,
+ struct drm_out_fence_state **fence_state,
+ unsigned int *num_fences)
+{
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *crtc_state;
+ struct drm_connector *conn;
+ struct drm_connector_state *conn_state;
+ int i, c = 0, ret;
+
+ if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
+ return 0;
+
+ for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
+ s32 __user *fence_ptr;
+
+ fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc);
+
+ if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT || fence_ptr) {
+ struct drm_pending_vblank_event *e;
+
+ e = create_vblank_event(crtc, arg->user_data);
+ if (!e)
+ return -ENOMEM;
+
+ crtc_state->event = e;
+ }
+
+ if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
+ struct drm_pending_vblank_event *e = crtc_state->event;
+
+ if (!file_priv)
+ continue;
+
+ ret = drm_event_reserve_init(dev, file_priv, &e->base,
+ &e->event.base);
+ if (ret) {
+ kfree(e);
+ crtc_state->event = NULL;
+ return ret;
+ }
+ }
+
+ if (fence_ptr) {
+ struct dma_fence *fence;
+ struct drm_out_fence_state *f;
+
+ f = krealloc(*fence_state, sizeof(**fence_state) *
+ (*num_fences + 1), GFP_KERNEL);
+ if (!f)
+ return -ENOMEM;
+
+ memset(&f[*num_fences], 0, sizeof(*f));
+
+ f[*num_fences].out_fence_ptr = fence_ptr;
+ *fence_state = f;
+
+ fence = drm_crtc_create_fence(crtc);
+ if (!fence)
+ return -ENOMEM;
+
+ ret = setup_out_fence(&f[(*num_fences)++], fence);
+ if (ret) {
+ dma_fence_put(fence);
+ return ret;
+ }
+
+ crtc_state->event->base.fence = fence;
+ }
+
+ c++;
+ }
+
+ for_each_new_connector_in_state(state, conn, conn_state, i) {
+ struct drm_writeback_connector *wb_conn;
+ struct drm_writeback_job *job;
+ struct drm_out_fence_state *f;
+ struct dma_fence *fence;
+ s32 __user *fence_ptr;
+
+ fence_ptr = get_out_fence_for_connector(state, conn);
+ if (!fence_ptr)
+ continue;
+
+ job = drm_atomic_get_writeback_job(conn_state);
+ if (!job)
+ return -ENOMEM;
+
+ f = krealloc(*fence_state, sizeof(**fence_state) *
+ (*num_fences + 1), GFP_KERNEL);
+ if (!f)
+ return -ENOMEM;
+
+ memset(&f[*num_fences], 0, sizeof(*f));
+
+ f[*num_fences].out_fence_ptr = fence_ptr;
+ *fence_state = f;
+
+ wb_conn = drm_connector_to_writeback(conn);
+ fence = drm_writeback_get_out_fence(wb_conn);
+ if (!fence)
+ return -ENOMEM;
+
+ ret = setup_out_fence(&f[(*num_fences)++], fence);
+ if (ret) {
+ dma_fence_put(fence);
+ return ret;
+ }
+
+ job->out_fence = fence;
+ }
+
+ /*
+ * Having this flag means user mode pends on event which will never
+ * reach due to lack of at least one CRTC for signaling
+ */
+ if (c == 0 && (arg->flags & DRM_MODE_PAGE_FLIP_EVENT))
+ return -EINVAL;
+
+ return 0;
+}
+
+static void complete_signaling(struct drm_device *dev,
+ struct drm_atomic_state *state,
+ struct drm_out_fence_state *fence_state,
+ unsigned int num_fences,
+ bool install_fds)
+{
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *crtc_state;
+ int i;
+
+ if (install_fds) {
+ for (i = 0; i < num_fences; i++)
+ fd_install(fence_state[i].fd,
+ fence_state[i].sync_file->file);
+
+ kfree(fence_state);
+ return;
+ }
+
+ for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
+ struct drm_pending_vblank_event *event = crtc_state->event;
+ /*
+ * Free the allocated event. drm_atomic_helper_setup_commit
+ * can allocate an event too, so only free it if it's ours
+ * to prevent a double free in drm_atomic_state_clear.
+ */
+ if (event && (event->base.fence || event->base.file_priv)) {
+ drm_event_cancel_free(dev, &event->base);
+ crtc_state->event = NULL;
+ }
+ }
+
+ if (!fence_state)
+ return;
+
+ for (i = 0; i < num_fences; i++) {
+ if (fence_state[i].sync_file)
+ fput(fence_state[i].sync_file->file);
+ if (fence_state[i].fd >= 0)
+ put_unused_fd(fence_state[i].fd);
+
+ /* If this fails log error to the user */
+ if (fence_state[i].out_fence_ptr &&
+ put_user(-1, fence_state[i].out_fence_ptr))
+ DRM_DEBUG_ATOMIC("Couldn't clear out_fence_ptr\n");
+ }
+
+ kfree(fence_state);
+}
+
+int drm_mode_atomic_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv)
+{
+ struct drm_mode_atomic *arg = data;
+ uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr);
+ uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr);
+ uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
+ uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr);
+ unsigned int copied_objs, copied_props;
+ struct drm_atomic_state *state;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_out_fence_state *fence_state;
+ int ret = 0;
+ unsigned int i, j, num_fences;
+
+ /* disallow for drivers not supporting atomic: */
+ if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
+ return -EINVAL;
+
+ /* disallow for userspace that has not enabled atomic cap (even
+ * though this may be a bit overkill, since legacy userspace
+ * wouldn't know how to call this ioctl)
+ */
+ if (!file_priv->atomic)
+ return -EINVAL;
+
+ if (arg->flags & ~DRM_MODE_ATOMIC_FLAGS)
+ return -EINVAL;
+
+ if (arg->reserved)
+ return -EINVAL;
+
+ if ((arg->flags & DRM_MODE_PAGE_FLIP_ASYNC) &&
+ !dev->mode_config.async_page_flip)
+ return -EINVAL;
+
+ /* can't test and expect an event at the same time. */
+ if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) &&
+ (arg->flags & DRM_MODE_PAGE_FLIP_EVENT))
+ return -EINVAL;
+
+ drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
+
+ state = drm_atomic_state_alloc(dev);
+ if (!state)
+ return -ENOMEM;
+
+ state->acquire_ctx = &ctx;
+ state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET);
+
+retry:
+ copied_objs = 0;
+ copied_props = 0;
+ fence_state = NULL;
+ num_fences = 0;
+
+ for (i = 0; i < arg->count_objs; i++) {
+ uint32_t obj_id, count_props;
+ struct drm_mode_object *obj;
+
+ if (get_user(obj_id, objs_ptr + copied_objs)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ obj = drm_mode_object_find(dev, file_priv, obj_id, DRM_MODE_OBJECT_ANY);
+ if (!obj) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ if (!obj->properties) {
+ drm_mode_object_put(obj);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ if (get_user(count_props, count_props_ptr + copied_objs)) {
+ drm_mode_object_put(obj);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ copied_objs++;
+
+ for (j = 0; j < count_props; j++) {
+ uint32_t prop_id;
+ uint64_t prop_value;
+ struct drm_property *prop;
+
+ if (get_user(prop_id, props_ptr + copied_props)) {
+ drm_mode_object_put(obj);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ prop = drm_mode_obj_find_prop_id(obj, prop_id);
+ if (!prop) {
+ drm_mode_object_put(obj);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ if (copy_from_user(&prop_value,
+ prop_values_ptr + copied_props,
+ sizeof(prop_value))) {
+ drm_mode_object_put(obj);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ret = drm_atomic_set_property(state, obj, prop,
+ prop_value);
+ if (ret) {
+ drm_mode_object_put(obj);
+ goto out;
+ }
+
+ copied_props++;
+ }
+
+ drm_mode_object_put(obj);
+ }
+
+ ret = prepare_signaling(dev, state, arg, file_priv, &fence_state,
+ &num_fences);
+ if (ret)
+ goto out;
+
+ if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) {
+ ret = drm_atomic_check_only(state);
+ } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) {
+ ret = drm_atomic_nonblocking_commit(state);
+ } else {
+ if (unlikely(drm_debug & DRM_UT_STATE))
+ drm_atomic_print_state(state);
+
+ ret = drm_atomic_commit(state);
+ }
+
+out:
+ complete_signaling(dev, state, fence_state, num_fences, !ret);
+
+ if (ret == -EDEADLK) {
+ drm_atomic_state_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry;
+ }
+
+ drm_atomic_state_put(state);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c
index 402b62d3f072..0c78ca386cbe 100644
--- a/drivers/gpu/drm/drm_blend.c
+++ b/drivers/gpu/drm/drm_blend.c
@@ -101,6 +101,28 @@
* Without this property the rectangle is only scaled, but not rotated or
* reflected.
*
+ * Possbile values:
+ *
+ * "rotate-<degrees>":
+ * Signals that a drm plane is rotated <degrees> degrees in counter
+ * clockwise direction.
+ *
+ * "reflect-<axis>":
+ * Signals that the contents of a drm plane is reflected along the
+ * <axis> axis, in the same way as mirroring.
+ *
+ * reflect-x::
+ *
+ * |o | | o|
+ * | | -> | |
+ * | v| |v |
+ *
+ * reflect-y::
+ *
+ * |o | | ^|
+ * | | -> | |
+ * | v| |o |
+ *
* zpos:
* Z position is set up with drm_plane_create_zpos_immutable_property() and
* drm_plane_create_zpos_property(). It controls the visibility of overlapping
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 1638bfe9627c..ba7025041e46 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -104,6 +104,10 @@ EXPORT_SYMBOL(drm_bridge_remove);
* If non-NULL the previous bridge must be already attached by a call to this
* function.
*
+ * Note that bridges attached to encoders are auto-detached during encoder
+ * cleanup in drm_encoder_cleanup(), so drm_bridge_attach() should generally
+ * *not* be balanced with a drm_bridge_detach() in driver code.
+ *
* RETURNS:
* Zero on success, error code on failure
*/
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 6011d769d50b..526619f963e5 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -20,11 +20,15 @@
* OF THIS SOFTWARE.
*/
-#include <drm/drmP.h>
#include <drm/drm_connector.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder.h>
#include <drm/drm_utils.h>
+#include <drm/drm_print.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_file.h>
+
+#include <linux/uaccess.h>
#include "drm_crtc_internal.h"
#include "drm_internal.h"
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index bae43938c8f6..2f6c877299e4 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -34,7 +34,7 @@
#include <linux/slab.h>
#include <linux/export.h>
#include <linux/dma-fence.h>
-#include <drm/drmP.h>
+#include <linux/uaccess.h>
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include <drm/drm_fourcc.h>
@@ -42,6 +42,9 @@
#include <drm/drm_atomic.h>
#include <drm/drm_auth.h>
#include <drm/drm_debugfs_crc.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_print.h>
+#include <drm/drm_file.h>
#include "drm_crtc_internal.h"
#include "drm_internal.h"
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 5a84c3bc915d..ce75e9506e85 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -35,6 +35,7 @@
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_uapi.h>
#include <drm/drm_crtc.h>
#include <drm/drm_encoder.h>
#include <drm/drm_fourcc.h>
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
index b61322763394..86893448f486 100644
--- a/drivers/gpu/drm/drm_crtc_internal.h
+++ b/drivers/gpu/drm/drm_crtc_internal.h
@@ -31,6 +31,14 @@
* and are not exported to drivers.
*/
+enum drm_mode_status;
+enum drm_connector_force;
+
+struct drm_display_mode;
+struct work_struct;
+struct drm_connector;
+struct drm_bridge;
+struct edid;
/* drm_crtc.c */
int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
@@ -174,6 +182,8 @@ void drm_fb_release(struct drm_file *file_priv);
int drm_mode_addfb(struct drm_device *dev, struct drm_mode_fb_cmd *or,
struct drm_file *file_priv);
+int drm_mode_addfb2(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
int drm_mode_rmfb(struct drm_device *dev, u32 fb_id,
struct drm_file *file_priv);
@@ -181,8 +191,8 @@ int drm_mode_rmfb(struct drm_device *dev, u32 fb_id,
/* IOCTL */
int drm_mode_addfb_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv);
-int drm_mode_addfb2(struct drm_device *dev,
- void *data, struct drm_file *file_priv);
+int drm_mode_addfb2_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
int drm_mode_rmfb_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv);
int drm_mode_getfb(struct drm_device *dev,
@@ -196,6 +206,9 @@ struct drm_minor;
int drm_atomic_debugfs_init(struct drm_minor *minor);
#endif
+void drm_atomic_print_state(const struct drm_atomic_state *state);
+
+/* drm_atomic_uapi.c */
int drm_atomic_connector_commit_dpms(struct drm_atomic_state *state,
struct drm_connector *connector,
int mode);
@@ -205,6 +218,8 @@ int drm_atomic_set_property(struct drm_atomic_state *state,
uint64_t prop_value);
int drm_atomic_get_property(struct drm_mode_object *obj,
struct drm_property *property, uint64_t *val);
+
+/* IOCTL */
int drm_mode_atomic_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 4b0dd20bccb8..8e95d0f7c71d 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -2673,6 +2673,8 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper,
info = fb_helper->fbdev;
info->var.pixclock = 0;
+ /* don't leak any physical addresses to userspace */
+ info->flags |= FBINFO_HIDE_SMEM_START;
/* Need to drop locks to avoid recursive deadlock in
* register_framebuffer. This is ok because the only thing left to do is
@@ -2821,7 +2823,9 @@ EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
* The caller must to provide a &drm_fb_helper_funcs->fb_probe callback
* function.
*
- * See also: drm_fb_helper_initial_config()
+ * Use drm_fb_helper_fbdev_teardown() to destroy the fbdev.
+ *
+ * See also: drm_fb_helper_initial_config(), drm_fbdev_generic_setup().
*
* Returns:
* Zero on success or negative error code on failure.
@@ -3037,7 +3041,7 @@ static struct fb_deferred_io drm_fbdev_defio = {
* @fb_helper: fbdev helper structure
* @sizes: describes fbdev size and scanout surface size
*
- * This function uses the client API to crate a framebuffer backed by a dumb buffer.
+ * This function uses the client API to create a framebuffer backed by a dumb buffer.
*
* The _sys_ versions are used for &fb_ops.fb_read, fb_write, fb_fillrect,
* fb_copyarea, fb_imageblit.
@@ -3165,8 +3169,10 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
if (dev->fb_helper)
return drm_fb_helper_hotplug_event(dev->fb_helper);
- if (!dev->mode_config.num_connector)
+ if (!dev->mode_config.num_connector) {
+ DRM_DEV_DEBUG(dev->dev, "No connectors found, will not create framebuffer!\n");
return 0;
+ }
ret = drm_fb_helper_fbdev_setup(dev, fb_helper, &drm_fb_helper_generic_funcs,
fb_helper->preferred_bpp, 0);
@@ -3187,13 +3193,14 @@ static const struct drm_client_funcs drm_fbdev_client_funcs = {
};
/**
- * drm_fb_helper_generic_fbdev_setup() - Setup generic fbdev emulation
+ * drm_fbdev_generic_setup() - Setup generic fbdev emulation
* @dev: DRM device
* @preferred_bpp: Preferred bits per pixel for the device.
* @dev->mode_config.preferred_depth is used if this is zero.
*
* This function sets up generic fbdev emulation for drivers that supports
- * dumb buffers with a virtual address and that can be mmap'ed.
+ * dumb buffers with a virtual address and that can be mmap'ed. If the driver
+ * does not support these functions, it could use drm_fb_helper_fbdev_setup().
*
* Restore, hotplug events and teardown are all taken care of. Drivers that do
* suspend/resume need to call drm_fb_helper_set_suspend_unlocked() themselves.
@@ -3206,6 +3213,8 @@ static const struct drm_client_funcs drm_fbdev_client_funcs = {
* This function is safe to call even when there are no connectors present.
* Setup will be retried on the next hotplug event.
*
+ * The fbdev is destroyed by drm_dev_unregister().
+ *
* Returns:
* Zero on success or negative error code on failure.
*/
@@ -3214,6 +3223,8 @@ int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
struct drm_fb_helper *fb_helper;
int ret;
+ WARN(dev->fb_helper, "fb_helper is already set!\n");
+
if (!drm_fbdev_emulation)
return 0;
@@ -3224,12 +3235,15 @@ int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
ret = drm_client_new(dev, &fb_helper->client, "fbdev", &drm_fbdev_client_funcs);
if (ret) {
kfree(fb_helper);
+ DRM_DEV_ERROR(dev->dev, "Failed to register client: %d\n", ret);
return ret;
}
fb_helper->preferred_bpp = preferred_bpp;
- drm_fbdev_client_hotplug(&fb_helper->client);
+ ret = drm_fbdev_client_hotplug(&fb_helper->client);
+ if (ret)
+ DRM_DEV_DEBUG(dev->dev, "client hotplug ret=%d\n", ret);
return 0;
}
diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index 35c1e2742c27..be1d6aaef651 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -45,32 +45,49 @@ static char printable_char(int c)
*/
uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
{
- uint32_t fmt;
+ uint32_t fmt = DRM_FORMAT_INVALID;
switch (bpp) {
case 8:
- fmt = DRM_FORMAT_C8;
+ if (depth == 8)
+ fmt = DRM_FORMAT_C8;
break;
+
case 16:
- if (depth == 15)
+ switch (depth) {
+ case 15:
fmt = DRM_FORMAT_XRGB1555;
- else
+ break;
+ case 16:
fmt = DRM_FORMAT_RGB565;
+ break;
+ default:
+ break;
+ }
break;
+
case 24:
- fmt = DRM_FORMAT_RGB888;
+ if (depth == 24)
+ fmt = DRM_FORMAT_RGB888;
break;
+
case 32:
- if (depth == 24)
+ switch (depth) {
+ case 24:
fmt = DRM_FORMAT_XRGB8888;
- else if (depth == 30)
+ break;
+ case 30:
fmt = DRM_FORMAT_XRGB2101010;
- else
+ break;
+ case 32:
fmt = DRM_FORMAT_ARGB8888;
+ break;
+ default:
+ break;
+ }
break;
+
default:
- DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n");
- fmt = DRM_FORMAT_XRGB8888;
break;
}
diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
index 781af1d42d76..6eaacd4eb8cc 100644
--- a/drivers/gpu/drm/drm_framebuffer.c
+++ b/drivers/gpu/drm/drm_framebuffer.c
@@ -25,6 +25,7 @@
#include <drm/drm_auth.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_uapi.h>
#include <drm/drm_print.h>
#include "drm_internal.h"
@@ -112,18 +113,34 @@ int drm_mode_addfb(struct drm_device *dev, struct drm_mode_fb_cmd *or,
struct drm_mode_fb_cmd2 r = {};
int ret;
+ r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth);
+ if (r.pixel_format == DRM_FORMAT_INVALID) {
+ DRM_DEBUG("bad {bpp:%d, depth:%d}\n", or->bpp, or->depth);
+ return -EINVAL;
+ }
+
/* convert to new format and call new ioctl */
r.fb_id = or->fb_id;
r.width = or->width;
r.height = or->height;
r.pitches[0] = or->pitch;
- r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth);
r.handles[0] = or->handle;
- if (r.pixel_format == DRM_FORMAT_XRGB2101010 &&
- dev->driver->driver_features & DRIVER_PREFER_XBGR_30BPP)
+ if (dev->mode_config.quirk_addfb_prefer_xbgr_30bpp &&
+ r.pixel_format == DRM_FORMAT_XRGB2101010)
r.pixel_format = DRM_FORMAT_XBGR2101010;
+ if (dev->mode_config.quirk_addfb_prefer_host_byte_order) {
+ if (r.pixel_format == DRM_FORMAT_XRGB8888)
+ r.pixel_format = DRM_FORMAT_HOST_XRGB8888;
+ if (r.pixel_format == DRM_FORMAT_ARGB8888)
+ r.pixel_format = DRM_FORMAT_HOST_ARGB8888;
+ if (r.pixel_format == DRM_FORMAT_RGB565)
+ r.pixel_format = DRM_FORMAT_HOST_RGB565;
+ if (r.pixel_format == DRM_FORMAT_XRGB1555)
+ r.pixel_format = DRM_FORMAT_HOST_XRGB1555;
+ }
+
ret = drm_mode_addfb2(dev, &r, file_priv);
if (ret)
return ret;
@@ -164,7 +181,7 @@ static int framebuffer_check(struct drm_device *dev,
int i;
/* check if the format is supported at all */
- info = __drm_format_info(r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN);
+ info = __drm_format_info(r->pixel_format);
if (!info) {
struct drm_format_name_buf format_name;
@@ -352,6 +369,30 @@ int drm_mode_addfb2(struct drm_device *dev,
return 0;
}
+int drm_mode_addfb2_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv)
+{
+#ifdef __BIG_ENDIAN
+ if (!dev->mode_config.quirk_addfb_prefer_host_byte_order) {
+ /*
+ * Drivers must set the
+ * quirk_addfb_prefer_host_byte_order quirk to make
+ * the drm_mode_addfb() compat code work correctly on
+ * bigendian machines.
+ *
+ * If they don't they interpret pixel_format values
+ * incorrectly for bug compatibility, which in turn
+ * implies the ADDFB2 ioctl does not work correctly
+ * then. So block it to make userspace fallback to
+ * ADDFB.
+ */
+ DRM_DEBUG_KMS("addfb2 broken on bigendian");
+ return -EINVAL;
+ }
+#endif
+ return drm_mode_addfb2(dev, data, file_priv);
+}
+
struct drm_mode_rmfb_work {
struct work_struct work;
struct list_head fbs;
diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
index 2810d4131411..7607f9cd6f77 100644
--- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c
+++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
@@ -16,6 +16,7 @@
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_uapi.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
index 40179c5fc6b8..0c4eb4a9ab31 100644
--- a/drivers/gpu/drm/drm_internal.h
+++ b/drivers/gpu/drm/drm_internal.h
@@ -21,9 +21,14 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <drm/drm_ioctl.h>
+
#define DRM_IF_MAJOR 1
#define DRM_IF_MINOR 4
+struct drm_prime_file_private;
+struct dma_buf;
+
/* drm_file.c */
extern struct mutex drm_global_mutex;
struct drm_file *drm_file_alloc(struct drm_minor *minor);
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index ea10e9a26aad..6b4a633b4240 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -645,7 +645,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb_ioctl, DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2_ioctl, DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb_ioctl, DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_UNLOCKED),
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
index 6153cbda239f..4a72c6829d73 100644
--- a/drivers/gpu/drm/drm_plane.c
+++ b/drivers/gpu/drm/drm_plane.c
@@ -20,8 +20,17 @@
* OF THIS SOFTWARE.
*/
-#include <drm/drmP.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
#include <drm/drm_plane.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_print.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_file.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_vblank.h>
#include "drm_crtc_internal.h"
@@ -463,7 +472,6 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_mode_get_plane_res *plane_resp = data;
- struct drm_mode_config *config;
struct drm_plane *plane;
uint32_t __user *plane_ptr;
int count = 0;
@@ -471,7 +479,6 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
- config = &dev->mode_config;
plane_ptr = u64_to_user_ptr(plane_resp->plane_id_ptr);
/*
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index 621f17643bb0..a393756b664e 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -28,6 +28,7 @@
#include <drm/drm_plane_helper.h>
#include <drm/drm_rect.h>
#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_uapi.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_encoder.h>
#include <drm/drm_atomic_helper.h>
diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 3a8837c49639..e9ce623d049e 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -56,6 +56,33 @@
#include "drm_internal.h"
#include <drm/drm_syncobj.h>
+struct drm_syncobj_stub_fence {
+ struct dma_fence base;
+ spinlock_t lock;
+};
+
+static const char *drm_syncobj_stub_fence_get_name(struct dma_fence *fence)
+{
+ return "syncobjstub";
+}
+
+static bool drm_syncobj_stub_fence_enable_signaling(struct dma_fence *fence)
+{
+ return !dma_fence_is_signaled(fence);
+}
+
+static void drm_syncobj_stub_fence_release(struct dma_fence *f)
+{
+ kfree(f);
+}
+static const struct dma_fence_ops drm_syncobj_stub_fence_ops = {
+ .get_driver_name = drm_syncobj_stub_fence_get_name,
+ .get_timeline_name = drm_syncobj_stub_fence_get_name,
+ .enable_signaling = drm_syncobj_stub_fence_enable_signaling,
+ .release = drm_syncobj_stub_fence_release,
+};
+
+
/**
* drm_syncobj_find - lookup and reference a sync object.
* @file_private: drm file private pointer
@@ -140,11 +167,13 @@ void drm_syncobj_remove_callback(struct drm_syncobj *syncobj,
/**
* drm_syncobj_replace_fence - replace fence in a sync object.
* @syncobj: Sync object to replace fence in
+ * @point: timeline point
* @fence: fence to install in sync file.
*
- * This replaces the fence on a sync object.
+ * This replaces the fence on a sync object, or a timeline point fence.
*/
void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
+ u64 point,
struct dma_fence *fence)
{
struct dma_fence *old_fence;
@@ -172,42 +201,19 @@ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
}
EXPORT_SYMBOL(drm_syncobj_replace_fence);
-struct drm_syncobj_null_fence {
- struct dma_fence base;
- spinlock_t lock;
-};
-
-static const char *drm_syncobj_null_fence_get_name(struct dma_fence *fence)
-{
- return "syncobjnull";
-}
-
-static bool drm_syncobj_null_fence_enable_signaling(struct dma_fence *fence)
-{
- dma_fence_enable_sw_signaling(fence);
- return !dma_fence_is_signaled(fence);
-}
-
-static const struct dma_fence_ops drm_syncobj_null_fence_ops = {
- .get_driver_name = drm_syncobj_null_fence_get_name,
- .get_timeline_name = drm_syncobj_null_fence_get_name,
- .enable_signaling = drm_syncobj_null_fence_enable_signaling,
- .release = NULL,
-};
-
static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
{
- struct drm_syncobj_null_fence *fence;
+ struct drm_syncobj_stub_fence *fence;
fence = kzalloc(sizeof(*fence), GFP_KERNEL);
if (fence == NULL)
return -ENOMEM;
spin_lock_init(&fence->lock);
- dma_fence_init(&fence->base, &drm_syncobj_null_fence_ops,
+ dma_fence_init(&fence->base, &drm_syncobj_stub_fence_ops,
&fence->lock, 0, 0);
dma_fence_signal(&fence->base);
- drm_syncobj_replace_fence(syncobj, &fence->base);
+ drm_syncobj_replace_fence(syncobj, 0, &fence->base);
dma_fence_put(&fence->base);
@@ -218,6 +224,7 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
* drm_syncobj_find_fence - lookup and reference the fence in a sync object
* @file_private: drm file private pointer
* @handle: sync object handle to lookup.
+ * @point: timeline point
* @fence: out parameter for the fence
*
* This is just a convenience function that combines drm_syncobj_find() and
@@ -228,7 +235,7 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
* dma_fence_put().
*/
int drm_syncobj_find_fence(struct drm_file *file_private,
- u32 handle,
+ u32 handle, u64 point,
struct dma_fence **fence)
{
struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
@@ -257,7 +264,7 @@ void drm_syncobj_free(struct kref *kref)
struct drm_syncobj *syncobj = container_of(kref,
struct drm_syncobj,
refcount);
- drm_syncobj_replace_fence(syncobj, NULL);
+ drm_syncobj_replace_fence(syncobj, 0, NULL);
kfree(syncobj);
}
EXPORT_SYMBOL(drm_syncobj_free);
@@ -297,7 +304,7 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
}
if (fence)
- drm_syncobj_replace_fence(syncobj, fence);
+ drm_syncobj_replace_fence(syncobj, 0, fence);
*out_syncobj = syncobj;
return 0;
@@ -482,7 +489,7 @@ static int drm_syncobj_import_sync_file_fence(struct drm_file *file_private,
return -ENOENT;
}
- drm_syncobj_replace_fence(syncobj, fence);
+ drm_syncobj_replace_fence(syncobj, 0, fence);
dma_fence_put(fence);
drm_syncobj_put(syncobj);
return 0;
@@ -499,7 +506,7 @@ static int drm_syncobj_export_sync_file(struct drm_file *file_private,
if (fd < 0)
return fd;
- ret = drm_syncobj_find_fence(file_private, handle, &fence);
+ ret = drm_syncobj_find_fence(file_private, handle, 0, &fence);
if (ret)
goto err_put_fd;
@@ -964,7 +971,7 @@ drm_syncobj_reset_ioctl(struct drm_device *dev, void *data,
return ret;
for (i = 0; i < args->count_handles; i++)
- drm_syncobj_replace_fence(syncobjs[i], NULL);
+ drm_syncobj_replace_fence(syncobjs[i], 0, NULL);
drm_syncobj_array_free(syncobjs, args->count_handles);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 2ccb982a5dba..7ea442033a57 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -52,6 +52,7 @@
#include <drm/drm_gem.h>
#include <drm/drm_auth.h>
#include <drm/drm_cache.h>
+#include <drm/drm_util.h>
#include "i915_params.h"
#include "i915_reg.h"
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 7d0b3a2c30e2..22b4cb775576 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -2181,7 +2181,7 @@ signal_fence_array(struct i915_execbuffer *eb,
if (!(flags & I915_EXEC_FENCE_SIGNAL))
continue;
- drm_syncobj_replace_fence(syncobj, fence);
+ drm_syncobj_replace_fence(syncobj, 0, fence);
}
}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 1bd14c61dab5..b2bab57cd113 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -46,6 +46,7 @@
#include <drm/drm_crtc_helper.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_rect.h>
+#include <drm/drm_atomic_uapi.h>
#include <linux/dma_remapping.h>
#include <linux/reservation.h>
diff --git a/drivers/gpu/drm/i915/intel_display.h b/drivers/gpu/drm/i915/intel_display.h
index e20e6a36a748..ed474da6c200 100644
--- a/drivers/gpu/drm/i915/intel_display.h
+++ b/drivers/gpu/drm/i915/intel_display.h
@@ -25,6 +25,8 @@
#ifndef _INTEL_DISPLAY_H_
#define _INTEL_DISPLAY_H_
+#include <drm/drm_util.h>
+
enum i915_gpio {
GPIOA,
GPIOB,
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 3f6920dd7880..2dfa585712c2 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -2,6 +2,8 @@
#ifndef _INTEL_RINGBUFFER_H_
#define _INTEL_RINGBUFFER_H_
+#include <drm/drm_util.h>
+
#include <linux/hashtable.h>
#include <linux/seqlock.h>
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index b640e39ebaca..015341e2dd4c 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -21,6 +21,8 @@
#include <linux/debugfs.h>
#include <linux/dma-buf.h>
+#include <drm/drm_atomic_uapi.h>
+
#include "msm_drv.h"
#include "dpu_kms.h"
#include "dpu_formats.h"
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
index c1f1779c980f..4bcdeca7479d 100644
--- a/drivers/gpu/drm/msm/msm_atomic.c
+++ b/drivers/gpu/drm/msm/msm_atomic.c
@@ -15,6 +15,8 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <drm/drm_atomic_uapi.h>
+
#include "msm_drv.h"
#include "msm_gem.h"
#include "msm_kms.h"
diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
index 8412119bd940..a9bb656058e5 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -2174,7 +2174,7 @@ nv50_display_create(struct drm_device *dev)
nouveau_display(dev)->fini = nv50_display_fini;
disp->disp = &nouveau_display(dev)->disp;
dev->mode_config.funcs = &nv50_disp_func;
- dev->driver->driver_features |= DRIVER_PREFER_XBGR_30BPP;
+ dev->mode_config.quirk_addfb_prefer_xbgr_30bpp = true;
/* small shared memory area we use for notifiers and semaphores */
ret = nouveau_bo_new(&drm->client, 4096, 0x1000, TTM_PL_FLAG_VRAM,
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h
index dc7454e7f19a..0acc07555bcd 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.h
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.h
@@ -32,6 +32,8 @@
#include <drm/drm_edid.h>
#include <drm/drm_encoder.h>
#include <drm/drm_dp_helper.h>
+#include <drm/drm_util.h>
+
#include "nouveau_crtc.h"
#include "nouveau_encoder.h"
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 844498c4267c..20a260887be3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -379,7 +379,6 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
FBINFO_HWACCEL_FILLRECT |
FBINFO_HWACCEL_IMAGEBLIT;
- info->flags |= FBINFO_CAN_FORCE_OUTPUT;
info->fbops = &nouveau_fbcon_sw_ops;
info->fix.smem_start = fb->nvbo->bo.mem.bus.base +
fb->nvbo->bo.mem.bus.offset;
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 01704a7f07cb..87d16a0ce01e 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -28,6 +28,7 @@
#include <drm/drm_plane_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic.h>
+#include <drm/drm_gem_framebuffer_helper.h>
#include "qxl_drv.h"
#include "qxl_object.h"
@@ -388,17 +389,6 @@ static const struct drm_crtc_funcs qxl_crtc_funcs = {
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
};
-void qxl_user_framebuffer_destroy(struct drm_framebuffer *fb)
-{
- struct qxl_framebuffer *qxl_fb = to_qxl_framebuffer(fb);
- struct qxl_bo *bo = gem_to_qxl_bo(qxl_fb->obj);
-
- WARN_ON(bo->shadow);
- drm_gem_object_put_unlocked(qxl_fb->obj);
- drm_framebuffer_cleanup(fb);
- kfree(qxl_fb);
-}
-
static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb,
struct drm_file *file_priv,
unsigned flags, unsigned color,
@@ -406,15 +396,14 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb,
unsigned num_clips)
{
/* TODO: vmwgfx where this was cribbed from had locking. Why? */
- struct qxl_framebuffer *qxl_fb = to_qxl_framebuffer(fb);
- struct qxl_device *qdev = qxl_fb->base.dev->dev_private;
+ struct qxl_device *qdev = fb->dev->dev_private;
struct drm_clip_rect norect;
struct qxl_bo *qobj;
int inc = 1;
drm_modeset_lock_all(fb->dev);
- qobj = gem_to_qxl_bo(qxl_fb->obj);
+ qobj = gem_to_qxl_bo(fb->obj[0]);
/* if we aren't primary surface ignore this */
if (!qobj->is_primary) {
drm_modeset_unlock_all(fb->dev);
@@ -432,7 +421,7 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb,
inc = 2; /* skip source rects */
}
- qxl_draw_dirty_fb(qdev, qxl_fb, qobj, flags, color,
+ qxl_draw_dirty_fb(qdev, fb, qobj, flags, color,
clips, num_clips, inc);
drm_modeset_unlock_all(fb->dev);
@@ -441,31 +430,11 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb,
}
static const struct drm_framebuffer_funcs qxl_fb_funcs = {
- .destroy = qxl_user_framebuffer_destroy,
+ .destroy = drm_gem_fb_destroy,
.dirty = qxl_framebuffer_surface_dirty,
-/* TODO?
- * .create_handle = qxl_user_framebuffer_create_handle, */
+ .create_handle = drm_gem_fb_create_handle,
};
-int
-qxl_framebuffer_init(struct drm_device *dev,
- struct qxl_framebuffer *qfb,
- const struct drm_mode_fb_cmd2 *mode_cmd,
- struct drm_gem_object *obj,
- const struct drm_framebuffer_funcs *funcs)
-{
- int ret;
-
- qfb->obj = obj;
- drm_helper_mode_fill_fb_struct(dev, &qfb->base, mode_cmd);
- ret = drm_framebuffer_init(dev, &qfb->base, funcs);
- if (ret) {
- qfb->obj = NULL;
- return ret;
- }
- return 0;
-}
-
static void qxl_crtc_atomic_enable(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
@@ -488,14 +457,12 @@ static int qxl_primary_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state)
{
struct qxl_device *qdev = plane->dev->dev_private;
- struct qxl_framebuffer *qfb;
struct qxl_bo *bo;
if (!state->crtc || !state->fb)
return 0;
- qfb = to_qxl_framebuffer(state->fb);
- bo = gem_to_qxl_bo(qfb->obj);
+ bo = gem_to_qxl_bo(state->fb->obj[0]);
if (bo->surf.stride * bo->surf.height > qdev->vram_size) {
DRM_ERROR("Mode doesn't fit in vram size (vgamem)");
@@ -556,23 +523,19 @@ static void qxl_primary_atomic_update(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
struct qxl_device *qdev = plane->dev->dev_private;
- struct qxl_framebuffer *qfb =
- to_qxl_framebuffer(plane->state->fb);
- struct qxl_framebuffer *qfb_old;
- struct qxl_bo *bo = gem_to_qxl_bo(qfb->obj);
+ struct qxl_bo *bo = gem_to_qxl_bo(plane->state->fb->obj[0]);
struct qxl_bo *bo_old;
struct drm_clip_rect norect = {
.x1 = 0,
.y1 = 0,
- .x2 = qfb->base.width,
- .y2 = qfb->base.height
+ .x2 = plane->state->fb->width,
+ .y2 = plane->state->fb->height
};
int ret;
bool same_shadow = false;
if (old_state->fb) {
- qfb_old = to_qxl_framebuffer(old_state->fb);
- bo_old = gem_to_qxl_bo(qfb_old->obj);
+ bo_old = gem_to_qxl_bo(old_state->fb->obj[0]);
} else {
bo_old = NULL;
}
@@ -602,7 +565,7 @@ static void qxl_primary_atomic_update(struct drm_plane *plane,
bo->is_primary = true;
}
- qxl_draw_dirty_fb(qdev, qfb, bo, 0, 0, &norect, 1, 1);
+ qxl_draw_dirty_fb(qdev, plane->state->fb, bo, 0, 0, &norect, 1, 1);
}
static void qxl_primary_atomic_disable(struct drm_plane *plane,
@@ -611,9 +574,7 @@ static void qxl_primary_atomic_disable(struct drm_plane *plane,
struct qxl_device *qdev = plane->dev->dev_private;
if (old_state->fb) {
- struct qxl_framebuffer *qfb =
- to_qxl_framebuffer(old_state->fb);
- struct qxl_bo *bo = gem_to_qxl_bo(qfb->obj);
+ struct qxl_bo *bo = gem_to_qxl_bo(old_state->fb->obj[0]);
if (bo->is_primary) {
qxl_io_destroy_primary(qdev);
@@ -645,7 +606,7 @@ static void qxl_cursor_atomic_update(struct drm_plane *plane,
return;
if (fb != old_state->fb) {
- obj = to_qxl_framebuffer(fb)->obj;
+ obj = fb->obj[0];
user_bo = gem_to_qxl_bo(obj);
/* pinning is done in the prepare/cleanup framevbuffer */
@@ -765,13 +726,13 @@ static int qxl_plane_prepare_fb(struct drm_plane *plane,
if (!new_state->fb)
return 0;
- obj = to_qxl_framebuffer(new_state->fb)->obj;
+ obj = new_state->fb->obj[0];
user_bo = gem_to_qxl_bo(obj);
if (plane->type == DRM_PLANE_TYPE_PRIMARY &&
user_bo->is_dumb && !user_bo->shadow) {
if (plane->state->fb) {
- obj = to_qxl_framebuffer(plane->state->fb)->obj;
+ obj = plane->state->fb->obj[0];
old_bo = gem_to_qxl_bo(obj);
}
if (old_bo && old_bo->shadow &&
@@ -815,7 +776,7 @@ static void qxl_plane_cleanup_fb(struct drm_plane *plane,
return;
}
- obj = to_qxl_framebuffer(old_state->fb)->obj;
+ obj = old_state->fb->obj[0];
user_bo = gem_to_qxl_bo(obj);
qxl_bo_unpin(user_bo);
@@ -1115,26 +1076,8 @@ qxl_user_framebuffer_create(struct drm_device *dev,
struct drm_file *file_priv,
const struct drm_mode_fb_cmd2 *mode_cmd)
{
- struct drm_gem_object *obj;
- struct qxl_framebuffer *qxl_fb;
- int ret;
-
- obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[0]);
- if (!obj)
- return NULL;
-
- qxl_fb = kzalloc(sizeof(*qxl_fb), GFP_KERNEL);
- if (qxl_fb == NULL)
- return NULL;
-
- ret = qxl_framebuffer_init(dev, qxl_fb, mode_cmd, obj, &qxl_fb_funcs);
- if (ret) {
- kfree(qxl_fb);
- drm_gem_object_put_unlocked(obj);
- return NULL;
- }
-
- return &qxl_fb->base;
+ return drm_gem_fb_create_with_funcs(dev, file_priv, mode_cmd,
+ &qxl_fb_funcs);
}
static const struct drm_mode_config_funcs qxl_mode_funcs = {
@@ -1221,7 +1164,6 @@ int qxl_modeset_init(struct qxl_device *qdev)
}
qxl_display_read_client_monitors_config(qdev);
- qdev->mode_info.mode_config_initialized = true;
drm_mode_config_reset(&qdev->ddev);
@@ -1237,8 +1179,5 @@ void qxl_modeset_fini(struct qxl_device *qdev)
qxl_fbdev_fini(qdev);
qxl_destroy_monitors_object(qdev);
- if (qdev->mode_info.mode_config_initialized) {
- drm_mode_config_cleanup(&qdev->ddev);
- qdev->mode_info.mode_config_initialized = false;
- }
+ drm_mode_config_cleanup(&qdev->ddev);
}
diff --git a/drivers/gpu/drm/qxl/qxl_draw.c b/drivers/gpu/drm/qxl/qxl_draw.c
index 4d8681e84e68..cc5b32e749ce 100644
--- a/drivers/gpu/drm/qxl/qxl_draw.c
+++ b/drivers/gpu/drm/qxl/qxl_draw.c
@@ -262,7 +262,7 @@ out_free_drawable:
* by treating them differently in the server.
*/
void qxl_draw_dirty_fb(struct qxl_device *qdev,
- struct qxl_framebuffer *qxl_fb,
+ struct drm_framebuffer *fb,
struct qxl_bo *bo,
unsigned flags, unsigned color,
struct drm_clip_rect *clips,
@@ -281,9 +281,9 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
struct qxl_drawable *drawable;
struct qxl_rect drawable_rect;
struct qxl_rect *rects;
- int stride = qxl_fb->base.pitches[0];
+ int stride = fb->pitches[0];
/* depth is not actually interesting, we don't mask with it */
- int depth = qxl_fb->base.format->cpp[0] * 8;
+ int depth = fb->format->cpp[0] * 8;
uint8_t *surface_base;
struct qxl_release *release;
struct qxl_bo *clips_bo;
diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h
index 01220d386b0a..8ff70a7281a7 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.h
+++ b/drivers/gpu/drm/qxl/qxl_drv.h
@@ -38,6 +38,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_encoder.h>
+#include <drm/drm_fb_helper.h>
#include <drm/drm_gem.h>
#include <drm/drmP.h>
#include <drm/ttm/ttm_bo_api.h>
@@ -121,15 +122,9 @@ struct qxl_output {
struct drm_encoder enc;
};
-struct qxl_framebuffer {
- struct drm_framebuffer base;
- struct drm_gem_object *obj;
-};
-
#define to_qxl_crtc(x) container_of(x, struct qxl_crtc, base)
#define drm_connector_to_qxl_output(x) container_of(x, struct qxl_output, base)
#define drm_encoder_to_qxl_output(x) container_of(x, struct qxl_output, enc)
-#define to_qxl_framebuffer(x) container_of(x, struct qxl_framebuffer, base)
struct qxl_mman {
struct ttm_bo_global_ref bo_global_ref;
@@ -138,13 +133,6 @@ struct qxl_mman {
struct ttm_bo_device bdev;
};
-struct qxl_mode_info {
- bool mode_config_initialized;
-
- /* pointer to fbdev info structure */
- struct qxl_fbdev *qfbdev;
-};
-
struct qxl_memslot {
uint8_t generation;
@@ -232,10 +220,9 @@ struct qxl_device {
void *ram;
struct qxl_mman mman;
struct qxl_gem gem;
- struct qxl_mode_info mode_info;
- struct fb_info *fbdev_info;
- struct qxl_framebuffer *fbdev_qfb;
+ struct drm_fb_helper fb_helper;
+
void *ram_physical;
struct qxl_ring *release_ring;
@@ -349,19 +336,8 @@ qxl_bo_physical_address(struct qxl_device *qdev, struct qxl_bo *bo,
int qxl_fbdev_init(struct qxl_device *qdev);
void qxl_fbdev_fini(struct qxl_device *qdev);
-int qxl_get_handle_for_primary_fb(struct qxl_device *qdev,
- struct drm_file *file_priv,
- uint32_t *handle);
-void qxl_fbdev_set_suspend(struct qxl_device *qdev, int state);
/* qxl_display.c */
-void qxl_user_framebuffer_destroy(struct drm_framebuffer *fb);
-int
-qxl_framebuffer_init(struct drm_device *dev,
- struct qxl_framebuffer *rfb,
- const struct drm_mode_fb_cmd2 *mode_cmd,
- struct drm_gem_object *obj,
- const struct drm_framebuffer_funcs *funcs);
void qxl_display_read_client_monitors_config(struct qxl_device *qdev);
int qxl_create_monitors_object(struct qxl_device *qdev);
int qxl_destroy_monitors_object(struct qxl_device *qdev);
@@ -471,7 +447,7 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,
int stride /* filled in if 0 */);
void qxl_draw_dirty_fb(struct qxl_device *qdev,
- struct qxl_framebuffer *qxl_fb,
+ struct drm_framebuffer *fb,
struct qxl_bo *bo,
unsigned flags, unsigned color,
struct drm_clip_rect *clips,
diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c
index ca465c0d49fa..2294b7f14fdf 100644
--- a/drivers/gpu/drm/qxl/qxl_fb.c
+++ b/drivers/gpu/drm/qxl/qxl_fb.c
@@ -30,24 +30,12 @@
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
#include "qxl_drv.h"
#include "qxl_object.h"
-#define QXL_DIRTY_DELAY (HZ / 30)
-
-struct qxl_fbdev {
- struct drm_fb_helper helper;
- struct qxl_framebuffer qfb;
- struct qxl_device *qdev;
-
- spinlock_t delayed_ops_lock;
- struct list_head delayed_ops;
- void *shadow;
- int size;
-};
-
static void qxl_fb_image_init(struct qxl_fb_image *qxl_fb_image,
struct qxl_device *qdev, struct fb_info *info,
const struct fb_image *image)
@@ -73,13 +61,6 @@ static void qxl_fb_image_init(struct qxl_fb_image *qxl_fb_image,
}
}
-#ifdef CONFIG_DRM_FBDEV_EMULATION
-static struct fb_deferred_io qxl_defio = {
- .delay = QXL_DIRTY_DELAY,
- .deferred_io = drm_fb_helper_deferred_io,
-};
-#endif
-
static struct fb_ops qxlfb_ops = {
.owner = THIS_MODULE,
DRM_FB_HELPER_DEFAULT_OPS,
@@ -98,26 +79,10 @@ static void qxlfb_destroy_pinned_object(struct drm_gem_object *gobj)
drm_gem_object_put_unlocked(gobj);
}
-int qxl_get_handle_for_primary_fb(struct qxl_device *qdev,
- struct drm_file *file_priv,
- uint32_t *handle)
-{
- int r;
- struct drm_gem_object *gobj = qdev->fbdev_qfb->obj;
-
- BUG_ON(!gobj);
- /* drm_get_handle_create adds a reference - good */
- r = drm_gem_handle_create(file_priv, gobj, handle);
- if (r)
- return r;
- return 0;
-}
-
-static int qxlfb_create_pinned_object(struct qxl_fbdev *qfbdev,
+static int qxlfb_create_pinned_object(struct qxl_device *qdev,
const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object **gobj_p)
{
- struct qxl_device *qdev = qfbdev->qdev;
struct drm_gem_object *gobj = NULL;
struct qxl_bo *qbo = NULL;
int ret;
@@ -174,13 +139,12 @@ static int qxlfb_framebuffer_dirty(struct drm_framebuffer *fb,
unsigned num_clips)
{
struct qxl_device *qdev = fb->dev->dev_private;
- struct fb_info *info = qdev->fbdev_info;
- struct qxl_fbdev *qfbdev = info->par;
+ struct fb_info *info = qdev->fb_helper.fbdev;
struct qxl_fb_image qxl_fb_image;
struct fb_image *image = &qxl_fb_image.fb_image;
/* TODO: hard coding 32 bpp */
- int stride = qfbdev->qfb.base.pitches[0];
+ int stride = fb->pitches[0];
/*
* we are using a shadow draw buffer, at qdev->surface0_shadow
@@ -199,7 +163,7 @@ static int qxlfb_framebuffer_dirty(struct drm_framebuffer *fb,
image->cmap.green = NULL;
image->cmap.blue = NULL;
image->cmap.transp = NULL;
- image->data = qfbdev->shadow + (clips->x1 * 4) + (stride * clips->y1);
+ image->data = info->screen_base + (clips->x1 * 4) + (stride * clips->y1);
qxl_fb_image_init(&qxl_fb_image, qdev, info, NULL);
qxl_draw_opaque_fb(&qxl_fb_image, stride);
@@ -208,21 +172,22 @@ static int qxlfb_framebuffer_dirty(struct drm_framebuffer *fb,
}
static const struct drm_framebuffer_funcs qxlfb_fb_funcs = {
- .destroy = qxl_user_framebuffer_destroy,
+ .destroy = drm_gem_fb_destroy,
+ .create_handle = drm_gem_fb_create_handle,
.dirty = qxlfb_framebuffer_dirty,
};
-static int qxlfb_create(struct qxl_fbdev *qfbdev,
+static int qxlfb_create(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes)
{
- struct qxl_device *qdev = qfbdev->qdev;
+ struct qxl_device *qdev =
+ container_of(helper, struct qxl_device, fb_helper);
struct fb_info *info;
struct drm_framebuffer *fb = NULL;
struct drm_mode_fb_cmd2 mode_cmd;
struct drm_gem_object *gobj = NULL;
struct qxl_bo *qbo = NULL;
int ret;
- int size;
int bpp = sizes->surface_bpp;
int depth = sizes->surface_depth;
void *shadow;
@@ -233,7 +198,7 @@ static int qxlfb_create(struct qxl_fbdev *qfbdev,
mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((bpp + 1) / 8), 64);
mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth);
- ret = qxlfb_create_pinned_object(qfbdev, &mode_cmd, &gobj);
+ ret = qxlfb_create_pinned_object(qdev, &mode_cmd, &gobj);
if (ret < 0)
return ret;
@@ -247,25 +212,26 @@ static int qxlfb_create(struct qxl_fbdev *qfbdev,
DRM_DEBUG_DRIVER("surface0 at gpu offset %lld, mmap_offset %lld (virt %p, shadow %p)\n",
qxl_bo_gpu_offset(qbo), qxl_bo_mmap_offset(qbo),
qbo->kptr, shadow);
- size = mode_cmd.pitches[0] * mode_cmd.height;
- info = drm_fb_helper_alloc_fbi(&qfbdev->helper);
+ info = drm_fb_helper_alloc_fbi(helper);
if (IS_ERR(info)) {
ret = PTR_ERR(info);
goto out_unref;
}
- info->par = qfbdev;
-
- qxl_framebuffer_init(&qdev->ddev, &qfbdev->qfb, &mode_cmd, gobj,
- &qxlfb_fb_funcs);
+ info->par = helper;
- fb = &qfbdev->qfb.base;
+ fb = drm_gem_fbdev_fb_create(&qdev->ddev, sizes, 64, gobj,
+ &qxlfb_fb_funcs);
+ if (IS_ERR(fb)) {
+ DRM_ERROR("Failed to create framebuffer: %ld\n", PTR_ERR(fb));
+ ret = PTR_ERR(fb);
+ goto out_unref;
+ }
/* setup helper with fb data */
- qfbdev->helper.fb = fb;
+ qdev->fb_helper.fb = fb;
- qfbdev->shadow = shadow;
strcpy(info->fix.id, "qxldrmfb");
drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
@@ -278,10 +244,10 @@ static int qxlfb_create(struct qxl_fbdev *qfbdev,
*/
info->fix.smem_start = qdev->vram_base; /* TODO - correct? */
info->fix.smem_len = gobj->size;
- info->screen_base = qfbdev->shadow;
+ info->screen_base = shadow;
info->screen_size = gobj->size;
- drm_fb_helper_fill_var(info, &qfbdev->helper, sizes->fb_width,
+ drm_fb_helper_fill_var(info, &qdev->fb_helper, sizes->fb_width,
sizes->fb_height);
/* setup aperture base/size for vesafb takeover */
@@ -296,13 +262,9 @@ static int qxlfb_create(struct qxl_fbdev *qfbdev,
goto out_unref;
}
-#ifdef CONFIG_DRM_FBDEV_EMULATION
- info->fbdefio = &qxl_defio;
- fb_deferred_io_init(info);
-#endif
+ /* XXX error handling. */
+ drm_fb_helper_defio_init(helper);
- qdev->fbdev_info = info;
- qdev->fbdev_qfb = &qfbdev->qfb;
DRM_INFO("fb mappable at 0x%lX, size %lu\n", info->fix.smem_start, (unsigned long)info->screen_size);
DRM_INFO("fb: depth %d, pitch %d, width %d, height %d\n",
fb->format->depth, fb->pitches[0], fb->width, fb->height);
@@ -313,119 +275,26 @@ out_unref:
qxl_bo_kunmap(qbo);
qxl_bo_unpin(qbo);
}
- if (fb && ret) {
- drm_gem_object_put_unlocked(gobj);
- drm_framebuffer_cleanup(fb);
- kfree(fb);
- }
drm_gem_object_put_unlocked(gobj);
return ret;
}
-static int qxl_fb_find_or_create_single(
- struct drm_fb_helper *helper,
- struct drm_fb_helper_surface_size *sizes)
-{
- struct qxl_fbdev *qfbdev =
- container_of(helper, struct qxl_fbdev, helper);
- int new_fb = 0;
- int ret;
-
- if (!helper->fb) {
- ret = qxlfb_create(qfbdev, sizes);
- if (ret)
- return ret;
- new_fb = 1;
- }
- return new_fb;
-}
-
-static int qxl_fbdev_destroy(struct drm_device *dev, struct qxl_fbdev *qfbdev)
-{
- struct qxl_framebuffer *qfb = &qfbdev->qfb;
-
- drm_fb_helper_unregister_fbi(&qfbdev->helper);
-
- if (qfb->obj) {
- qxlfb_destroy_pinned_object(qfb->obj);
- qfb->obj = NULL;
- }
- drm_fb_helper_fini(&qfbdev->helper);
- vfree(qfbdev->shadow);
- drm_framebuffer_cleanup(&qfb->base);
-
- return 0;
-}
-
static const struct drm_fb_helper_funcs qxl_fb_helper_funcs = {
- .fb_probe = qxl_fb_find_or_create_single,
+ .fb_probe = qxlfb_create,
};
int qxl_fbdev_init(struct qxl_device *qdev)
{
- int ret = 0;
-
-#ifdef CONFIG_DRM_FBDEV_EMULATION
- struct qxl_fbdev *qfbdev;
- int bpp_sel = 32; /* TODO: parameter from somewhere? */
-
- qfbdev = kzalloc(sizeof(struct qxl_fbdev), GFP_KERNEL);
- if (!qfbdev)
- return -ENOMEM;
-
- qfbdev->qdev = qdev;
- qdev->mode_info.qfbdev = qfbdev;
- spin_lock_init(&qfbdev->delayed_ops_lock);
- INIT_LIST_HEAD(&qfbdev->delayed_ops);
-
- drm_fb_helper_prepare(&qdev->ddev, &qfbdev->helper,
- &qxl_fb_helper_funcs);
-
- ret = drm_fb_helper_init(&qdev->ddev, &qfbdev->helper,
- QXLFB_CONN_LIMIT);
- if (ret)
- goto free;
-
- ret = drm_fb_helper_single_add_all_connectors(&qfbdev->helper);
- if (ret)
- goto fini;
-
- ret = drm_fb_helper_initial_config(&qfbdev->helper, bpp_sel);
- if (ret)
- goto fini;
-
- return 0;
-
-fini:
- drm_fb_helper_fini(&qfbdev->helper);
-free:
- kfree(qfbdev);
-#endif
-
- return ret;
+ return drm_fb_helper_fbdev_setup(&qdev->ddev, &qdev->fb_helper,
+ &qxl_fb_helper_funcs, 32,
+ QXLFB_CONN_LIMIT);
}
void qxl_fbdev_fini(struct qxl_device *qdev)
{
- if (!qdev->mode_info.qfbdev)
- return;
+ struct fb_info *fbi = qdev->fb_helper.fbdev;
+ void *shadow = fbi ? fbi->screen_buffer : NULL;
- qxl_fbdev_destroy(&qdev->ddev, qdev->mode_info.qfbdev);
- kfree(qdev->mode_info.qfbdev);
- qdev->mode_info.qfbdev = NULL;
-}
-
-void qxl_fbdev_set_suspend(struct qxl_device *qdev, int state)
-{
- if (!qdev->mode_info.qfbdev)
- return;
-
- drm_fb_helper_set_suspend(&qdev->mode_info.qfbdev->helper, state);
-}
-
-bool qxl_fbdev_qobj_is_fb(struct qxl_device *qdev, struct qxl_bo *qobj)
-{
- if (qobj == gem_to_qxl_bo(qdev->mode_info.qfbdev->qfb.obj))
- return true;
- return false;
+ drm_fb_helper_fbdev_teardown(&qdev->ddev);
+ vfree(shadow);
}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index 5864cb452c5c..941f35233b1f 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -448,6 +448,11 @@ static int rockchip_drm_platform_remove(struct platform_device *pdev)
return 0;
}
+static void rockchip_drm_platform_shutdown(struct platform_device *pdev)
+{
+ rockchip_drm_platform_remove(pdev);
+}
+
static const struct of_device_id rockchip_drm_dt_ids[] = {
{ .compatible = "rockchip,display-subsystem", },
{ /* sentinel */ },
@@ -457,6 +462,7 @@ MODULE_DEVICE_TABLE(of, rockchip_drm_dt_ids);
static struct platform_driver rockchip_drm_platform_driver = {
.probe = rockchip_drm_platform_probe,
.remove = rockchip_drm_platform_remove,
+ .shutdown = rockchip_drm_platform_shutdown,
.driver = {
.name = "rockchip-drm",
.of_match_table = rockchip_drm_dt_ids,
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index 0cebb2db5b99..c78cd35a1294 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -12,6 +12,7 @@
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_encoder.h>
@@ -277,10 +278,64 @@ static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon,
SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
}
+static void sun4i_tcon0_mode_set_dithering(struct sun4i_tcon *tcon,
+ const struct drm_connector *connector)
+{
+ u32 bus_format = 0;
+ u32 val = 0;
+
+ /* XXX Would this ever happen? */
+ if (!connector)
+ return;
+
+ /*
+ * FIXME: Undocumented bits
+ *
+ * The whole dithering process and these parameters are not
+ * explained in the vendor documents or BSP kernel code.
+ */
+ regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_PR_REG, 0x11111111);
+ regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_PG_REG, 0x11111111);
+ regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_PB_REG, 0x11111111);
+ regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_LR_REG, 0x11111111);
+ regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_LG_REG, 0x11111111);
+ regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_LB_REG, 0x11111111);
+ regmap_write(tcon->regs, SUN4I_TCON0_FRM_TBL0_REG, 0x01010000);
+ regmap_write(tcon->regs, SUN4I_TCON0_FRM_TBL1_REG, 0x15151111);
+ regmap_write(tcon->regs, SUN4I_TCON0_FRM_TBL2_REG, 0x57575555);
+ regmap_write(tcon->regs, SUN4I_TCON0_FRM_TBL3_REG, 0x7f7f7777);
+
+ /* Do dithering if panel only supports 6 bits per color */
+ if (connector->display_info.bpc == 6)
+ val |= SUN4I_TCON0_FRM_CTL_EN;
+
+ if (connector->display_info.num_bus_formats == 1)
+ bus_format = connector->display_info.bus_formats[0];
+
+ /* Check the connection format */
+ switch (bus_format) {
+ case MEDIA_BUS_FMT_RGB565_1X16:
+ /* R and B components are only 5 bits deep */
+ val |= SUN4I_TCON0_FRM_CTL_MODE_R;
+ val |= SUN4I_TCON0_FRM_CTL_MODE_B;
+ case MEDIA_BUS_FMT_RGB666_1X18:
+ case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
+ /* Fall through: enable dithering */
+ val |= SUN4I_TCON0_FRM_CTL_EN;
+ break;
+ }
+
+ /* Write dithering settings */
+ regmap_write(tcon->regs, SUN4I_TCON_FRM_CTL_REG, val);
+}
+
static void sun4i_tcon0_mode_set_cpu(struct sun4i_tcon *tcon,
- struct mipi_dsi_device *device,
+ const struct drm_encoder *encoder,
const struct drm_display_mode *mode)
{
+ /* TODO support normal CPU interface modes */
+ struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
+ struct mipi_dsi_device *device = dsi->device;
u8 bpp = mipi_dsi_pixel_format_to_bpp(device->format);
u8 lanes = device->lanes;
u32 block_space, start_delay;
@@ -291,6 +346,9 @@ static void sun4i_tcon0_mode_set_cpu(struct sun4i_tcon *tcon,
sun4i_tcon0_mode_set_common(tcon, mode);
+ /* Set dithering if needed */
+ sun4i_tcon0_mode_set_dithering(tcon, sun4i_tcon_get_connector(encoder));
+
regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
SUN4I_TCON0_CTL_IF_MASK,
SUN4I_TCON0_CTL_IF_8080);
@@ -356,6 +414,9 @@ static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon,
tcon->dclk_max_div = 7;
sun4i_tcon0_mode_set_common(tcon, mode);
+ /* Set dithering if needed */
+ sun4i_tcon0_mode_set_dithering(tcon, sun4i_tcon_get_connector(encoder));
+
/* Adjust clock delay */
clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
@@ -429,6 +490,9 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
tcon->dclk_max_div = 127;
sun4i_tcon0_mode_set_common(tcon, mode);
+ /* Set dithering if needed */
+ sun4i_tcon0_mode_set_dithering(tcon, tcon->panel->connector);
+
/* Adjust clock delay */
clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
@@ -610,16 +674,10 @@ void sun4i_tcon_mode_set(struct sun4i_tcon *tcon,
const struct drm_encoder *encoder,
const struct drm_display_mode *mode)
{
- struct sun6i_dsi *dsi;
-
switch (encoder->encoder_type) {
case DRM_MODE_ENCODER_DSI:
- /*
- * This is not really elegant, but it's the "cleaner"
- * way I could think of...
- */
- dsi = encoder_to_sun6i_dsi(encoder);
- sun4i_tcon0_mode_set_cpu(tcon, dsi->device, mode);
+ /* DSI is tied to special case of CPU interface */
+ sun4i_tcon0_mode_set_cpu(tcon, encoder, mode);
break;
case DRM_MODE_ENCODER_LVDS:
sun4i_tcon0_mode_set_lvds(tcon, encoder, mode);
@@ -916,7 +974,8 @@ static bool sun4i_tcon_connected_to_tcon_top(struct device_node *node)
remote = of_graph_get_remote_node(node, 0, -1);
if (remote) {
- ret = !!of_match_node(sun8i_tcon_top_of_table, remote);
+ ret = !!(IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP) &&
+ of_match_node(sun8i_tcon_top_of_table, remote));
of_node_put(remote);
}
@@ -1344,13 +1403,20 @@ static int sun8i_r40_tcon_tv_set_mux(struct sun4i_tcon *tcon,
if (!pdev)
return -EINVAL;
- if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS) {
+ if (IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP) &&
+ encoder->encoder_type == DRM_MODE_ENCODER_TMDS) {
ret = sun8i_tcon_top_set_hdmi_src(&pdev->dev, id);
if (ret)
return ret;
}
- return sun8i_tcon_top_de_config(&pdev->dev, tcon->id, id);
+ if (IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP)) {
+ ret = sun8i_tcon_top_de_config(&pdev->dev, tcon->id, id);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
static const struct sun4i_tcon_quirks sun4i_a10_quirks = {
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
index f6a071cd5a6f..3d492c8be1fc 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -37,18 +37,21 @@
#define SUN4I_TCON_GINT1_REG 0x8
#define SUN4I_TCON_FRM_CTL_REG 0x10
-#define SUN4I_TCON_FRM_CTL_EN BIT(31)
-
-#define SUN4I_TCON_FRM_SEED_PR_REG 0x14
-#define SUN4I_TCON_FRM_SEED_PG_REG 0x18
-#define SUN4I_TCON_FRM_SEED_PB_REG 0x1c
-#define SUN4I_TCON_FRM_SEED_LR_REG 0x20
-#define SUN4I_TCON_FRM_SEED_LG_REG 0x24
-#define SUN4I_TCON_FRM_SEED_LB_REG 0x28
-#define SUN4I_TCON_FRM_TBL0_REG 0x2c
-#define SUN4I_TCON_FRM_TBL1_REG 0x30
-#define SUN4I_TCON_FRM_TBL2_REG 0x34
-#define SUN4I_TCON_FRM_TBL3_REG 0x38
+#define SUN4I_TCON0_FRM_CTL_EN BIT(31)
+#define SUN4I_TCON0_FRM_CTL_MODE_R BIT(6)
+#define SUN4I_TCON0_FRM_CTL_MODE_G BIT(5)
+#define SUN4I_TCON0_FRM_CTL_MODE_B BIT(4)
+
+#define SUN4I_TCON0_FRM_SEED_PR_REG 0x14
+#define SUN4I_TCON0_FRM_SEED_PG_REG 0x18
+#define SUN4I_TCON0_FRM_SEED_PB_REG 0x1c
+#define SUN4I_TCON0_FRM_SEED_LR_REG 0x20
+#define SUN4I_TCON0_FRM_SEED_LG_REG 0x24
+#define SUN4I_TCON0_FRM_SEED_LB_REG 0x28
+#define SUN4I_TCON0_FRM_TBL0_REG 0x2c
+#define SUN4I_TCON0_FRM_TBL1_REG 0x30
+#define SUN4I_TCON0_FRM_TBL2_REG 0x34
+#define SUN4I_TCON0_FRM_TBL3_REG 0x38
#define SUN4I_TCON0_CTL_REG 0x40
#define SUN4I_TCON0_CTL_TCON_ENABLE BIT(31)
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
index 5ce24098a5fd..70c54774400b 100644
--- a/drivers/gpu/drm/v3d/v3d_gem.c
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
@@ -521,12 +521,12 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
kref_init(&exec->refcount);
ret = drm_syncobj_find_fence(file_priv, args->in_sync_bcl,
- &exec->bin.in_fence);
+ 0, &exec->bin.in_fence);
if (ret == -EINVAL)
goto fail;
ret = drm_syncobj_find_fence(file_priv, args->in_sync_rcl,
- &exec->render.in_fence);
+ 0, &exec->render.in_fence);
if (ret == -EINVAL)
goto fail;
@@ -584,7 +584,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
/* Update the return sync object for the */
sync_out = drm_syncobj_find(file_priv, args->out_sync);
if (sync_out) {
- drm_syncobj_replace_fence(sync_out,
+ drm_syncobj_replace_fence(sync_out, 0,
&exec->render.base.s_fence->finished);
drm_syncobj_put(sync_out);
}
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 0e6a121858d1..3ce136ba8791 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -35,6 +35,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_uapi.h>
#include <linux/clk.h>
#include <drm/drm_fb_cma_helper.h>
#include <linux/component.h>
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
index 7910b9acedd6..5b22e996af6c 100644
--- a/drivers/gpu/drm/vc4/vc4_gem.c
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
@@ -681,7 +681,7 @@ vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec,
exec->fence = &fence->base;
if (out_sync)
- drm_syncobj_replace_fence(out_sync, exec->fence);
+ drm_syncobj_replace_fence(out_sync, 0, exec->fence);
vc4_update_bo_seqnos(exec, seqno);
@@ -1173,7 +1173,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
if (args->in_sync) {
ret = drm_syncobj_find_fence(file_priv, args->in_sync,
- &in_fence);
+ 0, &in_fence);
if (ret)
goto fail;
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index cf78f74bb87f..f39ee212412d 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -22,6 +22,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_atomic_uapi.h>
#include "uapi/drm/vc4_drm.h"
#include "vc4_drv.h"
diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c
index 9f1e0a669d4c..0379d6897659 100644
--- a/drivers/gpu/drm/virtio/virtgpu_display.c
+++ b/drivers/gpu/drm/virtio/virtgpu_display.c
@@ -75,12 +75,9 @@ virtio_gpu_framebuffer_init(struct drm_device *dev,
struct drm_gem_object *obj)
{
int ret;
- struct virtio_gpu_object *bo;
vgfb->base.obj[0] = obj;
- bo = gem_to_virtio_gpu_obj(obj);
-
drm_helper_mode_fill_fb_struct(dev, &vgfb->base, mode_cmd);
ret = drm_framebuffer_init(dev, &vgfb->base, &virtio_gpu_fb_funcs);
diff --git a/drivers/gpu/drm/vkms/vkms_crc.c b/drivers/gpu/drm/vkms/vkms_crc.c
index 68db42f15086..0a2745646dfa 100644
--- a/drivers/gpu/drm/vkms/vkms_crc.c
+++ b/drivers/gpu/drm/vkms/vkms_crc.c
@@ -1,36 +1,143 @@
// SPDX-License-Identifier: GPL-2.0
#include "vkms_drv.h"
#include <linux/crc32.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
-static uint32_t _vkms_get_crc(struct vkms_crc_data *crc_data)
+/**
+ * compute_crc - Compute CRC value on output frame
+ *
+ * @vaddr_out: address to final framebuffer
+ * @crc_out: framebuffer's metadata
+ *
+ * returns CRC value computed using crc32 on the visible portion of
+ * the final framebuffer at vaddr_out
+ */
+static uint32_t compute_crc(void *vaddr_out, struct vkms_crc_data *crc_out)
+{
+ int i, j, src_offset;
+ int x_src = crc_out->src.x1 >> 16;
+ int y_src = crc_out->src.y1 >> 16;
+ int h_src = drm_rect_height(&crc_out->src) >> 16;
+ int w_src = drm_rect_width(&crc_out->src) >> 16;
+ u32 crc = 0;
+
+ for (i = y_src; i < y_src + h_src; ++i) {
+ for (j = x_src; j < x_src + w_src; ++j) {
+ src_offset = crc_out->offset
+ + (i * crc_out->pitch)
+ + (j * crc_out->cpp);
+ /* XRGB format ignores Alpha channel */
+ memset(vaddr_out + src_offset + 24, 0, 8);
+ crc = crc32_le(crc, vaddr_out + src_offset,
+ sizeof(u32));
+ }
+ }
+
+ return crc;
+}
+
+/**
+ * blend - belnd value at vaddr_src with value at vaddr_dst
+ * @vaddr_dst: destination address
+ * @vaddr_src: source address
+ * @crc_dst: destination framebuffer's metadata
+ * @crc_src: source framebuffer's metadata
+ *
+ * Blend value at vaddr_src with value at vaddr_dst.
+ * Currently, this function write value at vaddr_src on value
+ * at vaddr_dst using buffer's metadata to locate the new values
+ * from vaddr_src and their distenation at vaddr_dst.
+ *
+ * Todo: Use the alpha value to blend vaddr_src with vaddr_dst
+ * instead of overwriting it.
+ */
+static void blend(void *vaddr_dst, void *vaddr_src,
+ struct vkms_crc_data *crc_dst,
+ struct vkms_crc_data *crc_src)
{
- struct drm_framebuffer *fb = &crc_data->fb;
+ int i, j, j_dst, i_dst;
+ int offset_src, offset_dst;
+
+ int x_src = crc_src->src.x1 >> 16;
+ int y_src = crc_src->src.y1 >> 16;
+
+ int x_dst = crc_src->dst.x1;
+ int y_dst = crc_src->dst.y1;
+ int h_dst = drm_rect_height(&crc_src->dst);
+ int w_dst = drm_rect_width(&crc_src->dst);
+
+ int y_limit = y_src + h_dst;
+ int x_limit = x_src + w_dst;
+
+ for (i = y_src, i_dst = y_dst; i < y_limit; ++i) {
+ for (j = x_src, j_dst = x_dst; j < x_limit; ++j) {
+ offset_dst = crc_dst->offset
+ + (i_dst * crc_dst->pitch)
+ + (j_dst++ * crc_dst->cpp);
+ offset_src = crc_src->offset
+ + (i * crc_src->pitch)
+ + (j * crc_src->cpp);
+
+ memcpy(vaddr_dst + offset_dst,
+ vaddr_src + offset_src, sizeof(u32));
+ }
+ i_dst++;
+ }
+}
+
+static void compose_cursor(struct vkms_crc_data *cursor_crc,
+ struct vkms_crc_data *primary_crc, void *vaddr_out)
+{
+ struct drm_gem_object *cursor_obj;
+ struct vkms_gem_object *cursor_vkms_obj;
+
+ cursor_obj = drm_gem_fb_get_obj(&cursor_crc->fb, 0);
+ cursor_vkms_obj = drm_gem_to_vkms_gem(cursor_obj);
+
+ mutex_lock(&cursor_vkms_obj->pages_lock);
+ if (!cursor_vkms_obj->vaddr) {
+ DRM_WARN("cursor plane vaddr is NULL");
+ goto out;
+ }
+
+ blend(vaddr_out, cursor_vkms_obj->vaddr, primary_crc, cursor_crc);
+
+out:
+ mutex_unlock(&cursor_vkms_obj->pages_lock);
+}
+
+static uint32_t _vkms_get_crc(struct vkms_crc_data *primary_crc,
+ struct vkms_crc_data *cursor_crc)
+{
+ struct drm_framebuffer *fb = &primary_crc->fb;
struct drm_gem_object *gem_obj = drm_gem_fb_get_obj(fb, 0);
struct vkms_gem_object *vkms_obj = drm_gem_to_vkms_gem(gem_obj);
+ void *vaddr_out = kzalloc(vkms_obj->gem.size, GFP_KERNEL);
u32 crc = 0;
- int i = 0;
- unsigned int x = crc_data->src.x1 >> 16;
- unsigned int y = crc_data->src.y1 >> 16;
- unsigned int height = drm_rect_height(&crc_data->src) >> 16;
- unsigned int width = drm_rect_width(&crc_data->src) >> 16;
- unsigned int cpp = fb->format->cpp[0];
- unsigned int src_offset;
- unsigned int size_byte = width * cpp;
- void *vaddr;
- mutex_lock(&vkms_obj->pages_lock);
- vaddr = vkms_obj->vaddr;
- if (WARN_ON(!vaddr))
- goto out;
+ if (!vaddr_out) {
+ DRM_ERROR("Failed to allocate memory for output frame.");
+ return 0;
+ }
- for (i = y; i < y + height; i++) {
- src_offset = fb->offsets[0] + (i * fb->pitches[0]) + (x * cpp);
- crc = crc32_le(crc, vaddr + src_offset, size_byte);
+ mutex_lock(&vkms_obj->pages_lock);
+ if (WARN_ON(!vkms_obj->vaddr)) {
+ mutex_unlock(&vkms_obj->pages_lock);
+ return crc;
}
-out:
+ memcpy(vaddr_out, vkms_obj->vaddr, vkms_obj->gem.size);
mutex_unlock(&vkms_obj->pages_lock);
+
+ if (cursor_crc)
+ compose_cursor(cursor_crc, primary_crc, vaddr_out);
+
+ crc = compute_crc(vaddr_out, primary_crc);
+
+ kfree(vaddr_out);
+
return crc;
}
@@ -53,6 +160,7 @@ void vkms_crc_work_handle(struct work_struct *work)
struct vkms_device *vdev = container_of(out, struct vkms_device,
output);
struct vkms_crc_data *primary_crc = NULL;
+ struct vkms_crc_data *cursor_crc = NULL;
struct drm_plane *plane;
u32 crc32 = 0;
u64 frame_start, frame_end;
@@ -77,14 +185,14 @@ void vkms_crc_work_handle(struct work_struct *work)
if (drm_framebuffer_read_refcount(&crc_data->fb) == 0)
continue;
- if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
+ if (plane->type == DRM_PLANE_TYPE_PRIMARY)
primary_crc = crc_data;
- break;
- }
+ else
+ cursor_crc = crc_data;
}
if (primary_crc)
- crc32 = _vkms_get_crc(primary_crc);
+ crc32 = _vkms_get_crc(primary_crc, cursor_crc);
frame_end = drm_crtc_accurate_vblank_count(crtc);
diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index bd9d4b2389bd..07cfde1b4132 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -5,6 +5,15 @@
* (at your option) any later version.
*/
+/**
+ * DOC: vkms (Virtual Kernel Modesetting)
+ *
+ * vkms is a software-only model of a kms driver that is useful for testing,
+ * or for running X (or similar) on headless machines and be able to still
+ * use the GPU. vkms aims to enable a virtual display without the need for
+ * a hardware display capability.
+ */
+
#include <linux/module.h>
#include <drm/drm_gem.h>
#include <drm/drm_crtc_helper.h>
@@ -21,6 +30,10 @@
static struct vkms_device *vkms_device;
+bool enable_cursor;
+module_param_named(enable_cursor, enable_cursor, bool, 0444);
+MODULE_PARM_DESC(enable_cursor, "Enable/Disable cursor support");
+
static const struct file_operations vkms_driver_fops = {
.owner = THIS_MODULE,
.open = drm_open,
diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index 80af6d3a65e7..1c93990693e3 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -7,8 +7,8 @@
#include <drm/drm_encoder.h>
#include <linux/hrtimer.h>
-#define XRES_MIN 32
-#define YRES_MIN 32
+#define XRES_MIN 20
+#define YRES_MIN 20
#define XRES_DEF 1024
#define YRES_DEF 768
@@ -16,13 +16,22 @@
#define XRES_MAX 8192
#define YRES_MAX 8192
+extern bool enable_cursor;
+
static const u32 vkms_formats[] = {
DRM_FORMAT_XRGB8888,
};
+static const u32 vkms_cursor_formats[] = {
+ DRM_FORMAT_ARGB8888,
+};
+
struct vkms_crc_data {
- struct drm_rect src;
struct drm_framebuffer fb;
+ struct drm_rect src, dst;
+ unsigned int offset;
+ unsigned int pitch;
+ unsigned int cpp;
};
/**
@@ -104,7 +113,8 @@ bool vkms_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe,
int vkms_output_init(struct vkms_device *vkmsdev);
-struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev);
+struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev,
+ enum drm_plane_type type);
/* Gem stuff */
struct drm_gem_object *vkms_gem_create(struct drm_device *dev,
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index 901012cb1af1..271a0eb9042c 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -49,14 +49,22 @@ int vkms_output_init(struct vkms_device *vkmsdev)
struct drm_connector *connector = &output->connector;
struct drm_encoder *encoder = &output->encoder;
struct drm_crtc *crtc = &output->crtc;
- struct drm_plane *primary;
+ struct drm_plane *primary, *cursor = NULL;
int ret;
- primary = vkms_plane_init(vkmsdev);
+ primary = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_PRIMARY);
if (IS_ERR(primary))
return PTR_ERR(primary);
- ret = vkms_crtc_init(dev, crtc, primary, NULL);
+ if (enable_cursor) {
+ cursor = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_CURSOR);
+ if (IS_ERR(cursor)) {
+ ret = PTR_ERR(cursor);
+ goto err_cursor;
+ }
+ }
+
+ ret = vkms_crtc_init(dev, crtc, primary, cursor);
if (ret)
goto err_crtc;
@@ -106,6 +114,11 @@ err_connector:
drm_crtc_cleanup(crtc);
err_crtc:
+ if (enable_cursor)
+ drm_plane_cleanup(cursor);
+
+err_cursor:
drm_plane_cleanup(primary);
+
return ret;
}
diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
index c91661631c76..7041007396ae 100644
--- a/drivers/gpu/drm/vkms/vkms_plane.c
+++ b/drivers/gpu/drm/vkms/vkms_plane.c
@@ -81,26 +81,33 @@ static const struct drm_plane_funcs vkms_plane_funcs = {
.atomic_destroy_state = vkms_plane_destroy_state,
};
-static void vkms_primary_plane_update(struct drm_plane *plane,
- struct drm_plane_state *old_state)
+static void vkms_plane_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
{
struct vkms_plane_state *vkms_plane_state;
+ struct drm_framebuffer *fb = plane->state->fb;
struct vkms_crc_data *crc_data;
- if (!plane->state->crtc || !plane->state->fb)
+ if (!plane->state->crtc || !fb)
return;
vkms_plane_state = to_vkms_plane_state(plane->state);
+
crc_data = vkms_plane_state->crc_data;
memcpy(&crc_data->src, &plane->state->src, sizeof(struct drm_rect));
- memcpy(&crc_data->fb, plane->state->fb, sizeof(struct drm_framebuffer));
+ memcpy(&crc_data->dst, &plane->state->dst, sizeof(struct drm_rect));
+ memcpy(&crc_data->fb, fb, sizeof(struct drm_framebuffer));
drm_framebuffer_get(&crc_data->fb);
+ crc_data->offset = fb->offsets[0];
+ crc_data->pitch = fb->pitches[0];
+ crc_data->cpp = fb->format->cpp[0];
}
static int vkms_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state)
{
struct drm_crtc_state *crtc_state;
+ bool can_position = false;
int ret;
if (!state->fb | !state->crtc)
@@ -110,15 +117,18 @@ static int vkms_plane_atomic_check(struct drm_plane *plane,
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
+ if (plane->type == DRM_PLANE_TYPE_CURSOR)
+ can_position = true;
+
ret = drm_atomic_helper_check_plane_state(state, crtc_state,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
- false, true);
+ can_position, true);
if (ret != 0)
return ret;
/* for now primary plane must be visible and full screen */
- if (!state->visible)
+ if (!state->visible && !can_position)
return -EINVAL;
return 0;
@@ -156,15 +166,17 @@ static void vkms_cleanup_fb(struct drm_plane *plane,
}
static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = {
- .atomic_update = vkms_primary_plane_update,
+ .atomic_update = vkms_plane_atomic_update,
.atomic_check = vkms_plane_atomic_check,
.prepare_fb = vkms_prepare_fb,
.cleanup_fb = vkms_cleanup_fb,
};
-struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev)
+struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev,
+ enum drm_plane_type type)
{
struct drm_device *dev = &vkmsdev->drm;
+ const struct drm_plane_helper_funcs *funcs;
struct drm_plane *plane;
const u32 *formats;
int ret, nformats;
@@ -173,19 +185,26 @@ struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev)
if (!plane)
return ERR_PTR(-ENOMEM);
- formats = vkms_formats;
- nformats = ARRAY_SIZE(vkms_formats);
+ if (type == DRM_PLANE_TYPE_CURSOR) {
+ formats = vkms_cursor_formats;
+ nformats = ARRAY_SIZE(vkms_cursor_formats);
+ funcs = &vkms_primary_helper_funcs;
+ } else {
+ formats = vkms_formats;
+ nformats = ARRAY_SIZE(vkms_formats);
+ funcs = &vkms_primary_helper_funcs;
+ }
ret = drm_universal_plane_init(dev, plane, 0,
&vkms_plane_funcs,
formats, nformats,
- NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
+ NULL, type, NULL);
if (ret) {
kfree(plane);
return ERR_PTR(ret);
}
- drm_plane_helper_add(plane, &vkms_primary_helper_funcs);
+ drm_plane_helper_add(plane, funcs);
return plane;
}
diff --git a/drivers/staging/vboxvideo/vbox_fb.c b/drivers/staging/vboxvideo/vbox_fb.c
index 43c39eca4ae1..034f8ffa8f20 100644
--- a/drivers/staging/vboxvideo/vbox_fb.c
+++ b/drivers/staging/vboxvideo/vbox_fb.c
@@ -155,8 +155,7 @@ static int vboxfb_create(struct drm_fb_helper *helper,
* The last flag forces a mode set on VT switches even if the kernel
* does not think it is needed.
*/
- info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT |
- FBINFO_MISC_ALWAYS_SETPAR;
+ info->flags = FBINFO_DEFAULT | FBINFO_MISC_ALWAYS_SETPAR;
info->fbops = &vboxfb_ops;
/*
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 5f1183b0b89d..55370e651db3 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -1004,9 +1004,7 @@ void redraw_screen(struct vc_data *vc, int is_switch)
clear_buffer_attributes(vc);
}
- /* Forcibly update if we're panicing */
- if ((update && vc->vc_mode != KD_GRAPHICS) ||
- vt_force_oops_output(vc))
+ if (update && vc->vc_mode != KD_GRAPHICS)
do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
}
set_cursor(vc);
@@ -1046,7 +1044,6 @@ static void visual_init(struct vc_data *vc, int num, int init)
vc->vc_hi_font_mask = 0;
vc->vc_complement_mask = 0;
vc->vc_can_do_color = 0;
- vc->vc_panic_force_write = false;
vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS;
vc->vc_sw->con_init(vc, init);
if (!vc->vc_complement_mask)
@@ -2911,7 +2908,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
goto quit;
}
- if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc))
+ if (vc->vc_mode != KD_TEXT)
goto quit;
/* undraw cursor first */
@@ -4229,8 +4226,7 @@ void do_unblank_screen(int leaving_gfx)
return;
}
vc = vc_cons[fg_console].d;
- /* Try to unblank in oops case too */
- if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc))
+ if (vc->vc_mode != KD_TEXT)
return; /* but leave console_blanked != 0 */
if (blankinterval) {
@@ -4239,7 +4235,7 @@ void do_unblank_screen(int leaving_gfx)
}
console_blanked = 0;
- if (vc->vc_sw->con_blank(vc, 0, leaving_gfx) || vt_force_oops_output(vc))
+ if (vc->vc_sw->con_blank(vc, 0, leaving_gfx))
/* Low-level driver cannot restore -> do it ourselves */
update_screen(vc);
if (console_blank_hook)
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 75ebbbf0a1fb..8958ccc8b1ac 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -284,8 +284,7 @@ static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info)
struct fbcon_ops *ops = info->fbcon_par;
return (info->state != FBINFO_STATE_RUNNING ||
- vc->vc_mode != KD_TEXT || ops->graphics) &&
- !vt_force_oops_output(vc);
+ vc->vc_mode != KD_TEXT || ops->graphics);
}
static int get_color(struct vc_data *vc, struct fb_info *info,
@@ -1104,7 +1103,6 @@ static void fbcon_init(struct vc_data *vc, int init)
if (p->userfont)
charcnt = FNTCHARCNT(p->fontdata);
- vc->vc_panic_force_write = !!(info->flags & FBINFO_CAN_FORCE_OUTPUT);
vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
if (charcnt == 256) {
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 5ffadc8e681d..861bf8081619 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -1117,6 +1117,8 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
if (!lock_fb_info(info))
return -ENODEV;
fix = info->fix;
+ if (info->flags & FBINFO_HIDE_SMEM_START)
+ fix.smem_start = 0;
unlock_fb_info(info);
ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;
@@ -1327,6 +1329,8 @@ static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd,
if (!lock_fb_info(info))
return -ENODEV;
fix = info->fix;
+ if (info->flags & FBINFO_HIDE_SMEM_START)
+ fix.smem_start = 0;
unlock_fb_info(info);
return do_fscreeninfo_to_user(&fix, compat_ptr(arg));
}
@@ -1834,11 +1838,11 @@ EXPORT_SYMBOL(remove_conflicting_framebuffers);
/**
* remove_conflicting_pci_framebuffers - remove firmware-configured framebuffers for PCI devices
* @pdev: PCI device
- * @resource_id: index of PCI BAR configuring framebuffer memory
+ * @res_id: index of PCI BAR configuring framebuffer memory
* @name: requesting driver name
*
* This function removes framebuffer devices (eg. initialized by firmware)
- * using memory range configured for @pdev's BAR @resource_id.
+ * using memory range configured for @pdev's BAR @res_id.
*
* The function assumes that PCI device with shadowed ROM drives a primary
* display and so kicks out vga16fb.
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index f7a19c2a7a80..05350424a4d3 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -110,7 +110,4 @@ static inline bool drm_can_sleep(void)
return true;
}
-/* helper for handling conditionals in various for_each macros */
-#define for_each_if(condition) if (!(condition)) {} else
-
#endif
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index da9d95a19580..d6adebcd6ea4 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -29,6 +29,7 @@
#define DRM_ATOMIC_H_
#include <drm/drm_crtc.h>
+#include <drm/drm_util.h>
/**
* struct drm_crtc_commit - track modeset commits on a CRTC
@@ -373,9 +374,6 @@ void drm_atomic_state_default_release(struct drm_atomic_state *state);
struct drm_crtc_state * __must_check
drm_atomic_get_crtc_state(struct drm_atomic_state *state,
struct drm_crtc *crtc);
-int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
- struct drm_crtc_state *state, struct drm_property *property,
- uint64_t val);
struct drm_plane_state * __must_check
drm_atomic_get_plane_state(struct drm_atomic_state *state,
struct drm_plane *plane);
@@ -587,25 +585,6 @@ __drm_atomic_get_current_plane_state(struct drm_atomic_state *state,
}
int __must_check
-drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state,
- const struct drm_display_mode *mode);
-int __must_check
-drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
- struct drm_property_blob *blob);
-int __must_check
-drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
- struct drm_crtc *crtc);
-void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
- struct drm_framebuffer *fb);
-void drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state,
- struct dma_fence *fence);
-int __must_check
-drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
- struct drm_crtc *crtc);
-int drm_atomic_set_writeback_fb_for_connector(
- struct drm_connector_state *conn_state,
- struct drm_framebuffer *fb);
-int __must_check
drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
struct drm_crtc *crtc);
int __must_check
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index f4c7ed876c97..657af7b39379 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -31,6 +31,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_modeset_helper.h>
+#include <drm/drm_util.h>
struct drm_atomic_state;
struct drm_private_obj;
diff --git a/include/drm/drm_atomic_uapi.h b/include/drm/drm_atomic_uapi.h
new file mode 100644
index 000000000000..8cec52ad1277
--- /dev/null
+++ b/include/drm/drm_atomic_uapi.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Copyright (C) 2014 Intel Corp.
+ * Copyright (C) 2018 Intel Corp.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rob Clark <robdclark@gmail.com>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+#ifndef DRM_ATOMIC_UAPI_H_
+#define DRM_ATOMIC_UAPI_H_
+
+struct drm_crtc_state;
+struct drm_display_mode;
+struct drm_property_blob;
+struct drm_plane_state;
+struct drm_crtc;
+struct drm_connector_state;
+struct dma_fence;
+struct drm_framebuffer;
+
+int __must_check
+drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state,
+ const struct drm_display_mode *mode);
+int __must_check
+drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
+ struct drm_property_blob *blob);
+int __must_check
+drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
+ struct drm_crtc *crtc);
+void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
+ struct drm_framebuffer *fb);
+void drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state,
+ struct dma_fence *fence);
+int __must_check
+drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
+ struct drm_crtc *crtc);
+
+#endif
diff --git a/include/drm/drm_color_mgmt.h b/include/drm/drm_color_mgmt.h
index 44f04233e3db..90ef9996d9a4 100644
--- a/include/drm/drm_color_mgmt.h
+++ b/include/drm/drm_color_mgmt.h
@@ -24,6 +24,7 @@
#define __DRM_COLOR_MGMT_H__
#include <linux/ctype.h>
+#include <drm/drm_property.h>
struct drm_crtc;
struct drm_plane;
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 97ea41dc678f..91a877fa00cb 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -28,6 +28,7 @@
#include <linux/ctype.h>
#include <linux/hdmi.h>
#include <drm/drm_mode_object.h>
+#include <drm/drm_util.h>
#include <uapi/drm/drm_mode.h>
diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
index 46a8009784df..23b9678137a6 100644
--- a/include/drm/drm_drv.h
+++ b/include/drm/drm_drv.h
@@ -56,7 +56,6 @@ struct drm_printer;
#define DRIVER_ATOMIC 0x10000
#define DRIVER_KMS_LEGACY_CONTEXT 0x20000
#define DRIVER_SYNCOBJ 0x40000
-#define DRIVER_PREFER_XBGR_30BPP 0x80000
/**
* struct drm_driver - DRM driver structure
diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h
index 4f597c0730b4..70cfca03d812 100644
--- a/include/drm/drm_encoder.h
+++ b/include/drm/drm_encoder.h
@@ -28,6 +28,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_mode.h>
#include <drm/drm_mode_object.h>
+#include <drm/drm_util.h>
struct drm_encoder;
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 8b6ab3200a2c..bb9acea61369 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -604,6 +604,16 @@ drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
#endif
+/**
+ * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
+ * @a: memory range, users of which are to be removed
+ * @name: requesting driver name
+ * @primary: also kick vga16fb if present
+ *
+ * This function removes framebuffer devices (initialized by firmware/bootloader)
+ * which use memory range described by @a. If @a is NULL all such devices are
+ * removed.
+ */
static inline int
drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
const char *name, bool primary)
@@ -615,6 +625,18 @@ drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
#endif
}
+/**
+ * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured framebuffers for PCI devices
+ * @pdev: PCI device
+ * @resource_id: index of PCI BAR configuring framebuffer memory
+ * @name: requesting driver name
+ *
+ * This function removes framebuffer devices (eg. initialized by firmware)
+ * using memory range configured for @pdev's BAR @resource_id.
+ *
+ * The function assumes that PCI device with shadowed ROM drives a primary
+ * display and so kicks out vga16fb.
+ */
static inline int
drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
int resource_id,
diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h
index f9c15845f465..fac831c40106 100644
--- a/include/drm/drm_fourcc.h
+++ b/include/drm/drm_fourcc.h
@@ -25,6 +25,28 @@
#include <linux/types.h>
#include <uapi/drm/drm_fourcc.h>
+/*
+ * DRM formats are little endian. Define host endian variants for the
+ * most common formats here, to reduce the #ifdefs needed in drivers.
+ *
+ * Note that the DRM_FORMAT_BIG_ENDIAN flag should only be used in
+ * case the format can't be specified otherwise, so we don't end up
+ * with two values describing the same format.
+ */
+#ifdef __BIG_ENDIAN
+# define DRM_FORMAT_HOST_XRGB1555 (DRM_FORMAT_XRGB1555 | \
+ DRM_FORMAT_BIG_ENDIAN)
+# define DRM_FORMAT_HOST_RGB565 (DRM_FORMAT_RGB565 | \
+ DRM_FORMAT_BIG_ENDIAN)
+# define DRM_FORMAT_HOST_XRGB8888 DRM_FORMAT_BGRX8888
+# define DRM_FORMAT_HOST_ARGB8888 DRM_FORMAT_BGRA8888
+#else
+# define DRM_FORMAT_HOST_XRGB1555 DRM_FORMAT_XRGB1555
+# define DRM_FORMAT_HOST_RGB565 DRM_FORMAT_RGB565
+# define DRM_FORMAT_HOST_XRGB8888 DRM_FORMAT_XRGB8888
+# define DRM_FORMAT_HOST_ARGB8888 DRM_FORMAT_ARGB8888
+#endif
+
struct drm_device;
struct drm_mode_fb_cmd2;
diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h
index a0b202e1d69a..928e4172a0bb 100644
--- a/include/drm/drm_mode_config.h
+++ b/include/drm/drm_mode_config.h
@@ -809,6 +809,21 @@ struct drm_mode_config {
/* dumb ioctl parameters */
uint32_t preferred_depth, prefer_shadow;
+ bool quirk_addfb_prefer_xbgr_30bpp;
+
+ /**
+ * @quirk_addfb_prefer_host_byte_order:
+ *
+ * When set to true drm_mode_addfb() will pick host byte order
+ * pixel_format when calling drm_mode_addfb2(). This is how
+ * drm_mode_addfb() should have worked from day one. It
+ * didn't though, so we ended up with quirks in both kernel
+ * and userspace drivers to deal with the broken behavior.
+ * Simply fixing drm_mode_addfb() unconditionally would break
+ * these drivers, so add a quirk bit here to allow drivers
+ * opt-in.
+ */
+ bool quirk_addfb_prefer_host_byte_order;
/**
* @async_page_flip: Does this device support async flips on the primary
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
index 16f5b66684ca..0a0834bef8bd 100644
--- a/include/drm/drm_plane.h
+++ b/include/drm/drm_plane.h
@@ -27,6 +27,9 @@
#include <linux/ctype.h>
#include <drm/drm_mode_object.h>
#include <drm/drm_color_mgmt.h>
+#include <drm/drm_rect.h>
+#include <drm/drm_modeset_lock.h>
+#include <drm/drm_util.h>
struct drm_crtc;
struct drm_printer;
diff --git a/include/drm/drm_property.h b/include/drm/drm_property.h
index c030f6ccab99..5b9efff35d6d 100644
--- a/include/drm/drm_property.h
+++ b/include/drm/drm_property.h
@@ -27,6 +27,8 @@
#include <linux/ctype.h>
#include <drm/drm_mode_object.h>
+#include <uapi/drm/drm_mode.h>
+
/**
* struct drm_property_enum - symbolic values for enumerations
* @value: numeric property value for this enum entry
diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h
index e419c79ba94d..425432b85a87 100644
--- a/include/drm/drm_syncobj.h
+++ b/include/drm/drm_syncobj.h
@@ -131,10 +131,10 @@ drm_syncobj_fence_get(struct drm_syncobj *syncobj)
struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private,
u32 handle);
-void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
+void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, u64 point,
struct dma_fence *fence);
int drm_syncobj_find_fence(struct drm_file *file_private,
- u32 handle,
+ u32 handle, u64 point,
struct dma_fence **fence);
void drm_syncobj_free(struct kref *kref);
int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
diff --git a/include/drm/drm_util.h b/include/drm/drm_util.h
new file mode 100644
index 000000000000..88abdca89baa
--- /dev/null
+++ b/include/drm/drm_util.h
@@ -0,0 +1,32 @@
+/*
+ * Internal Header for the Direct Rendering Manager
+ *
+ * Copyright 2018 Intel Corporation
+ *
+ * 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.
+ */
+
+#ifndef _DRM_UTIL_H_
+#define _DRM_UTIL_H_
+
+/* helper for handling conditionals in various for_each macros */
+#define for_each_if(condition) if (!(condition)) {} else
+
+#endif
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
index fea64f2692a0..ab137f97ecbd 100644
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -141,7 +141,6 @@ struct vc_data {
struct uni_pagedir *vc_uni_pagedir;
struct uni_pagedir **vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */
struct uni_screen *vc_uni_screen; /* unicode screen content */
- bool vc_panic_force_write; /* when oops/panic this VC can accept forced output/blanking */
/* additional information is in vt_kern.h */
};
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 3cd375dafd0e..a3cab6dc9b44 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -456,10 +456,13 @@ struct fb_tile_ops {
* and host endianness. Drivers should not use this flag.
*/
#define FBINFO_BE_MATH 0x100000
+/*
+ * Hide smem_start in the FBIOGET_FSCREENINFO IOCTL. This is used by modern DRM
+ * drivers to stop userspace from trying to share buffers behind the kernel's
+ * back. Instead dma-buf based buffer sharing should be used.
+ */
+#define FBINFO_HIDE_SMEM_START 0x200000
-/* report to the VT layer that this fb driver can accept forced console
- output like oopses */
-#define FBINFO_CAN_FORCE_OUTPUT 0x200000
struct fb_info {
atomic_t count;
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
index 3fd07912909c..8dc77e40bc03 100644
--- a/include/linux/vt_kern.h
+++ b/include/linux/vt_kern.h
@@ -135,13 +135,6 @@ extern int do_unbind_con_driver(const struct consw *csw, int first, int last,
int deflt);
int vty_init(const struct file_operations *console_fops);
-static inline bool vt_force_oops_output(struct vc_data *vc)
-{
- if (oops_in_progress && vc->vc_panic_force_write && panic_timeout >= 0)
- return true;
- return false;
-}
-
extern char vt_dont_switch;
extern int default_utf8;
extern int global_cursor_default;
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index 2ed46e9ae16a..139632b87181 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -71,6 +71,9 @@ extern "C" {
#define DRM_FORMAT_BIG_ENDIAN (1<<31) /* format is big endian instead of little endian */
+/* Reserve 0 for the invalid format specifier */
+#define DRM_FORMAT_INVALID 0
+
/* color index */
#define DRM_FORMAT_C8 fourcc_code('C', '8', ' ', ' ') /* [7:0] C */
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index 8d67243952f4..d3e0fe31efc5 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -186,8 +186,9 @@ extern "C" {
/*
* DRM_MODE_REFLECT_<axis>
*
- * Signals that the contents of a drm plane is reflected in the <axis> axis,
+ * Signals that the contents of a drm plane is reflected along the <axis> axis,
* in the same way as mirroring.
+ * See kerneldoc chapter "Plane Composition Properties" for more details.
*
* This define is provided as a convenience, looking up the property id
* using the name->prop id lookup is the preferred method.