9b909221943fe27eba780c20b04d3ff3031edbf4
[linux-2.6-microblaze.git] / drivers / gpu / drm / vkms / vkms_crc.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include "vkms_drv.h"
3 #include <linux/crc32.h>
4 #include <drm/drm_gem_framebuffer_helper.h>
5
6 static uint32_t _vkms_get_crc(struct vkms_crc_data *crc_data)
7 {
8         struct drm_framebuffer *fb = &crc_data->fb;
9         struct drm_gem_object *gem_obj = drm_gem_fb_get_obj(fb, 0);
10         struct vkms_gem_object *vkms_obj = drm_gem_to_vkms_gem(gem_obj);
11         u32 crc = 0;
12         int i = 0;
13         unsigned int x = crc_data->src.x1 >> 16;
14         unsigned int y = crc_data->src.y1 >> 16;
15         unsigned int height = drm_rect_height(&crc_data->src) >> 16;
16         unsigned int width = drm_rect_width(&crc_data->src) >> 16;
17         unsigned int cpp = fb->format->cpp[0];
18         unsigned int src_offset;
19         unsigned int size_byte = width * cpp;
20         void *vaddr;
21
22         mutex_lock(&vkms_obj->pages_lock);
23         vaddr = vkms_obj->vaddr;
24         if (WARN_ON(!vaddr))
25                 return crc;
26
27         for (i = y; i < y + height; i++) {
28                 src_offset = fb->offsets[0] + (i * fb->pitches[0]) + (x * cpp);
29                 crc = crc32_le(crc, vaddr + src_offset, size_byte);
30         }
31         mutex_unlock(&vkms_obj->pages_lock);
32
33         return crc;
34 }
35
36 void vkms_crc_work_handle(struct work_struct *work)
37 {
38         struct vkms_crtc_state *crtc_state = container_of(work,
39                                                 struct vkms_crtc_state,
40                                                 crc_work);
41         struct drm_crtc *crtc = crtc_state->base.crtc;
42         struct vkms_output *out = drm_crtc_to_vkms_output(crtc);
43         struct vkms_device *vdev = container_of(out, struct vkms_device,
44                                                 output);
45         struct vkms_crc_data *primary_crc = NULL;
46         struct drm_plane *plane;
47
48         u32 crc32 = 0;
49
50         drm_for_each_plane(plane, &vdev->drm) {
51                 struct vkms_plane_state *vplane_state;
52                 struct vkms_crc_data *crc_data;
53
54                 vplane_state = to_vkms_plane_state(plane->state);
55                 crc_data = vplane_state->crc_data;
56
57                 if (drm_framebuffer_read_refcount(&crc_data->fb) == 0)
58                         continue;
59
60                 if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
61                         primary_crc = crc_data;
62                         break;
63                 }
64         }
65
66         if (primary_crc)
67                 crc32 = _vkms_get_crc(primary_crc);
68
69         drm_crtc_add_crc_entry(crtc, true, crtc_state->n_frame, &crc32);
70 }
71
72 int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name,
73                         size_t *values_cnt)
74 {
75         struct vkms_output *out = drm_crtc_to_vkms_output(crtc);
76         bool enabled = false;
77         unsigned long flags;
78         int ret = 0;
79
80         if (src_name && strcmp(src_name, "auto") == 0)
81                 enabled = true;
82         else if (src_name)
83                 ret = -EINVAL;
84
85         *values_cnt = 1;
86
87         /* make sure nothing is scheduled on crtc workq */
88         flush_workqueue(out->crc_workq);
89
90         spin_lock_irqsave(&out->lock, flags);
91         out->crc_enabled = enabled;
92         spin_unlock_irqrestore(&out->lock, flags);
93
94         return ret;
95 }