Merge tag '5.11-rc-smb3' of git://git.samba.org/sfrench/cifs-2.6
[linux-2.6-microblaze.git] / drivers / gpu / drm / vkms / vkms_plane.c
1 // SPDX-License-Identifier: GPL-2.0+
2
3 #include <linux/dma-buf-map.h>
4
5 #include <drm/drm_atomic.h>
6 #include <drm/drm_atomic_helper.h>
7 #include <drm/drm_fourcc.h>
8 #include <drm/drm_gem_framebuffer_helper.h>
9 #include <drm/drm_plane_helper.h>
10 #include <drm/drm_gem_shmem_helper.h>
11
12 #include "vkms_drv.h"
13
14 static const u32 vkms_formats[] = {
15         DRM_FORMAT_XRGB8888,
16 };
17
18 static const u32 vkms_cursor_formats[] = {
19         DRM_FORMAT_ARGB8888,
20 };
21
22 static struct drm_plane_state *
23 vkms_plane_duplicate_state(struct drm_plane *plane)
24 {
25         struct vkms_plane_state *vkms_state;
26         struct vkms_composer *composer;
27
28         vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
29         if (!vkms_state)
30                 return NULL;
31
32         composer = kzalloc(sizeof(*composer), GFP_KERNEL);
33         if (!composer) {
34                 DRM_DEBUG_KMS("Couldn't allocate composer\n");
35                 kfree(vkms_state);
36                 return NULL;
37         }
38
39         vkms_state->composer = composer;
40
41         __drm_atomic_helper_plane_duplicate_state(plane,
42                                                   &vkms_state->base);
43
44         return &vkms_state->base;
45 }
46
47 static void vkms_plane_destroy_state(struct drm_plane *plane,
48                                      struct drm_plane_state *old_state)
49 {
50         struct vkms_plane_state *vkms_state = to_vkms_plane_state(old_state);
51         struct drm_crtc *crtc = vkms_state->base.crtc;
52
53         if (crtc) {
54                 /* dropping the reference we acquired in
55                  * vkms_primary_plane_update()
56                  */
57                 if (drm_framebuffer_read_refcount(&vkms_state->composer->fb))
58                         drm_framebuffer_put(&vkms_state->composer->fb);
59         }
60
61         kfree(vkms_state->composer);
62         vkms_state->composer = NULL;
63
64         __drm_atomic_helper_plane_destroy_state(old_state);
65         kfree(vkms_state);
66 }
67
68 static void vkms_plane_reset(struct drm_plane *plane)
69 {
70         struct vkms_plane_state *vkms_state;
71
72         if (plane->state)
73                 vkms_plane_destroy_state(plane, plane->state);
74
75         vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
76         if (!vkms_state) {
77                 DRM_ERROR("Cannot allocate vkms_plane_state\n");
78                 return;
79         }
80
81         plane->state = &vkms_state->base;
82         plane->state->plane = plane;
83 }
84
85 static const struct drm_plane_funcs vkms_plane_funcs = {
86         .update_plane           = drm_atomic_helper_update_plane,
87         .disable_plane          = drm_atomic_helper_disable_plane,
88         .destroy                = drm_plane_cleanup,
89         .reset                  = vkms_plane_reset,
90         .atomic_duplicate_state = vkms_plane_duplicate_state,
91         .atomic_destroy_state   = vkms_plane_destroy_state,
92 };
93
94 static void vkms_plane_atomic_update(struct drm_plane *plane,
95                                      struct drm_plane_state *old_state)
96 {
97         struct vkms_plane_state *vkms_plane_state;
98         struct drm_framebuffer *fb = plane->state->fb;
99         struct vkms_composer *composer;
100
101         if (!plane->state->crtc || !fb)
102                 return;
103
104         vkms_plane_state = to_vkms_plane_state(plane->state);
105
106         composer = vkms_plane_state->composer;
107         memcpy(&composer->src, &plane->state->src, sizeof(struct drm_rect));
108         memcpy(&composer->dst, &plane->state->dst, sizeof(struct drm_rect));
109         memcpy(&composer->fb, fb, sizeof(struct drm_framebuffer));
110         drm_framebuffer_get(&composer->fb);
111         composer->offset = fb->offsets[0];
112         composer->pitch = fb->pitches[0];
113         composer->cpp = fb->format->cpp[0];
114 }
115
116 static int vkms_plane_atomic_check(struct drm_plane *plane,
117                                    struct drm_plane_state *state)
118 {
119         struct drm_crtc_state *crtc_state;
120         bool can_position = false;
121         int ret;
122
123         if (!state->fb || WARN_ON(!state->crtc))
124                 return 0;
125
126         crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
127         if (IS_ERR(crtc_state))
128                 return PTR_ERR(crtc_state);
129
130         if (plane->type == DRM_PLANE_TYPE_CURSOR)
131                 can_position = true;
132
133         ret = drm_atomic_helper_check_plane_state(state, crtc_state,
134                                                   DRM_PLANE_HELPER_NO_SCALING,
135                                                   DRM_PLANE_HELPER_NO_SCALING,
136                                                   can_position, true);
137         if (ret != 0)
138                 return ret;
139
140         /* for now primary plane must be visible and full screen */
141         if (!state->visible && !can_position)
142                 return -EINVAL;
143
144         return 0;
145 }
146
147 static int vkms_prepare_fb(struct drm_plane *plane,
148                            struct drm_plane_state *state)
149 {
150         struct drm_gem_object *gem_obj;
151         struct dma_buf_map map;
152         int ret;
153
154         if (!state->fb)
155                 return 0;
156
157         gem_obj = drm_gem_fb_get_obj(state->fb, 0);
158         ret = drm_gem_shmem_vmap(gem_obj, &map);
159         if (ret)
160                 DRM_ERROR("vmap failed: %d\n", ret);
161
162         return drm_gem_fb_prepare_fb(plane, state);
163 }
164
165 static void vkms_cleanup_fb(struct drm_plane *plane,
166                             struct drm_plane_state *old_state)
167 {
168         struct drm_gem_object *gem_obj;
169         struct drm_gem_shmem_object *shmem_obj;
170         struct dma_buf_map map;
171
172         if (!old_state->fb)
173                 return;
174
175         gem_obj = drm_gem_fb_get_obj(old_state->fb, 0);
176         shmem_obj = to_drm_gem_shmem_obj(drm_gem_fb_get_obj(old_state->fb, 0));
177         dma_buf_map_set_vaddr(&map, shmem_obj->vaddr);
178         drm_gem_shmem_vunmap(gem_obj, &map);
179 }
180
181 static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = {
182         .atomic_update          = vkms_plane_atomic_update,
183         .atomic_check           = vkms_plane_atomic_check,
184         .prepare_fb             = vkms_prepare_fb,
185         .cleanup_fb             = vkms_cleanup_fb,
186 };
187
188 struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev,
189                                   enum drm_plane_type type, int index)
190 {
191         struct drm_device *dev = &vkmsdev->drm;
192         const struct drm_plane_helper_funcs *funcs;
193         struct drm_plane *plane;
194         const u32 *formats;
195         int ret, nformats;
196
197         plane = kzalloc(sizeof(*plane), GFP_KERNEL);
198         if (!plane)
199                 return ERR_PTR(-ENOMEM);
200
201         if (type == DRM_PLANE_TYPE_CURSOR) {
202                 formats = vkms_cursor_formats;
203                 nformats = ARRAY_SIZE(vkms_cursor_formats);
204                 funcs = &vkms_primary_helper_funcs;
205         } else {
206                 formats = vkms_formats;
207                 nformats = ARRAY_SIZE(vkms_formats);
208                 funcs = &vkms_primary_helper_funcs;
209         }
210
211         ret = drm_universal_plane_init(dev, plane, 1 << index,
212                                        &vkms_plane_funcs,
213                                        formats, nformats,
214                                        NULL, type, NULL);
215         if (ret) {
216                 kfree(plane);
217                 return ERR_PTR(ret);
218         }
219
220         drm_plane_helper_add(plane, funcs);
221
222         return plane;
223 }