8cf5f3b9d965f386c89539502e542b11a86d96e1
[platform/kernel/linux-starfive.git] / drivers / gpu / drm / verisilicon / vs_plane.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2020 VeriSilicon Holdings Co., Ltd.
4  */
5
6 #include <drm/drm_atomic.h>
7 #include <drm/drm_atomic_helper.h>
8 #include <drm/drm_plane_helper.h>
9 #include <drm/drm_fb_cma_helper.h>
10 #include <drm/drm_gem_cma_helper.h>
11 #include <drm/vs_drm.h>
12
13 #include "vs_type.h"
14 #include "vs_crtc.h"
15 #include "vs_plane.h"
16 #include "vs_gem.h"
17 #include "vs_fb.h"
18
19 void vs_plane_destory(struct drm_plane *plane)
20 {
21         struct vs_plane *vs_plane = to_vs_plane(plane);
22
23         drm_plane_cleanup(plane);
24         kfree(vs_plane);
25 }
26
27 static void vs_plane_reset(struct drm_plane *plane)
28 {
29         struct vs_plane_state *state;
30         struct vs_plane *vs_plane = to_vs_plane(plane);
31
32         if (plane->state) {
33                 __drm_atomic_helper_plane_destroy_state(plane->state);
34
35                 state = to_vs_plane_state(plane->state);
36                 kfree(state);
37                 plane->state = NULL;
38         }
39
40         state = kzalloc(sizeof(*state), GFP_KERNEL);
41         if (state == NULL)
42                 return;
43
44         __drm_atomic_helper_plane_reset(plane, &state->base);
45
46         state->degamma = VS_DEGAMMA_DISABLE;
47         state->degamma_changed = false;
48         state->base.zpos = vs_plane->id;
49
50         memset(&state->status, 0, sizeof(state->status));
51 }
52
53 static void _vs_plane_duplicate_blob(struct vs_plane_state *state,
54                                                                          struct vs_plane_state *ori_state)
55 {
56         state->watermark = ori_state->watermark;
57         state->color_mgmt = ori_state->color_mgmt;
58         state->roi = ori_state->roi;
59
60         if (state->watermark)
61                 drm_property_blob_get(state->watermark);
62         if (state->color_mgmt)
63                 drm_property_blob_get(state->color_mgmt);
64         if (state->roi)
65                 drm_property_blob_get(state->roi);
66 }
67
68 static int
69 _vs_plane_set_property_blob_from_id(struct drm_device *dev,
70                                                                         struct drm_property_blob **blob,
71                                                                         uint64_t blob_id,
72                                                                         size_t expected_size)
73 {
74         struct drm_property_blob *new_blob = NULL;
75
76         if (blob_id) {
77                 new_blob = drm_property_lookup_blob(dev, blob_id);
78                 if (new_blob == NULL)
79                         return -EINVAL;
80
81                 if (new_blob->length != expected_size) {
82                         drm_property_blob_put(new_blob);
83                         return -EINVAL;
84                 }
85         }
86
87         drm_property_replace_blob(blob, new_blob);
88         drm_property_blob_put(new_blob);
89
90         return 0;
91 }
92
93 static struct drm_plane_state *
94 vs_plane_atomic_duplicate_state(struct drm_plane *plane)
95 {
96         struct vs_plane_state *ori_state;
97         struct vs_plane_state *state;
98
99         if (WARN_ON(!plane->state))
100                 return NULL;
101
102         ori_state = to_vs_plane_state(plane->state);
103         state = kzalloc(sizeof(*state), GFP_KERNEL);
104         if (!state)
105                 return NULL;
106
107         __drm_atomic_helper_plane_duplicate_state(plane, &state->base);
108
109         state->degamma = ori_state->degamma;
110         state->degamma_changed = ori_state->degamma_changed;
111
112         _vs_plane_duplicate_blob(state, ori_state);
113         memcpy(&state->status, &ori_state->status, sizeof(ori_state->status));
114
115         return &state->base;
116 }
117
118 static void vs_plane_atomic_destroy_state(struct drm_plane *plane,
119                                           struct drm_plane_state *state)
120 {
121         struct vs_plane_state *vs_plane_state = to_vs_plane_state(state);
122
123         __drm_atomic_helper_plane_destroy_state(state);
124
125         drm_property_blob_put(vs_plane_state->watermark);
126         drm_property_blob_put(vs_plane_state->color_mgmt);
127         drm_property_blob_put(vs_plane_state->roi);
128         kfree(vs_plane_state);
129 }
130
131 static int vs_plane_atomic_set_property(struct drm_plane *plane,
132                                         struct drm_plane_state *state,
133                                         struct drm_property *property,
134                                         uint64_t val)
135 {
136         struct drm_device *dev = plane->dev;
137         struct vs_plane *vs_plane = to_vs_plane(plane);
138         struct vs_plane_state *vs_plane_state = to_vs_plane_state(state);
139         int ret = 0;
140
141         if (property == vs_plane->degamma_mode) {
142                 if (vs_plane_state->degamma != val) {
143                         vs_plane_state->degamma = val;
144                         vs_plane_state->degamma_changed = true;
145                 } else {
146                         vs_plane_state->degamma_changed = false;
147                 }
148         } else if (property == vs_plane->watermark_prop) {
149                 ret = _vs_plane_set_property_blob_from_id(dev,
150                                                                 &vs_plane_state->watermark,
151                                                                 val, sizeof(struct drm_vs_watermark));
152                 return ret;
153         } else if (property == vs_plane->color_mgmt_prop) {
154                 ret = _vs_plane_set_property_blob_from_id(dev,
155                                                                 &vs_plane_state->color_mgmt,
156                                                                 val, sizeof(struct drm_vs_color_mgmt));
157                 return ret;
158         } else if (property == vs_plane->roi_prop) {
159                 ret = _vs_plane_set_property_blob_from_id(dev,
160                                                                 &vs_plane_state->roi,
161                                                                 val, sizeof(struct drm_vs_roi));
162                 return ret;
163         } else {
164                 return -EINVAL;
165         }
166
167         return 0;
168 }
169
170 static int vs_plane_atomic_get_property(struct drm_plane *plane,
171                                            const struct drm_plane_state *state,
172                                            struct drm_property *property,
173                                            uint64_t *val)
174 {
175         struct vs_plane *vs_plane = to_vs_plane(plane);
176         const struct vs_plane_state *vs_plane_state =
177                 container_of(state, const struct vs_plane_state, base);
178
179         if (property == vs_plane->degamma_mode)
180                 *val = vs_plane_state->degamma;
181         else if (property == vs_plane->watermark_prop)
182                 *val = (vs_plane_state->watermark) ?
183                                         vs_plane_state->watermark->base.id : 0;
184         else if (property == vs_plane->color_mgmt_prop)
185                 *val = (vs_plane_state->color_mgmt) ?
186                                         vs_plane_state->color_mgmt->base.id : 0;
187         else if (property == vs_plane->roi_prop)
188                 *val = (vs_plane_state->roi) ?
189                                         vs_plane_state->roi->base.id : 0;
190         else
191                 return -EINVAL;
192
193         return 0;
194 }
195
196 static bool vs_format_mod_supported(struct drm_plane *plane,
197                                         uint32_t format,
198                                         uint64_t modifier)
199 {
200    int i;
201
202    /*
203         * We always have to allow these modifiers:
204         * 1. Core DRM checks for LINEAR support if userspace does not provide modifiers.
205         * 2. Not passing any modifiers is the same as explicitly passing INVALID.
206         */
207    if (modifier == DRM_FORMAT_MOD_LINEAR) {
208            return true;
209    }
210
211    /* Check that the modifier is on the list of the plane's supported modifiers. */
212    for (i = 0; i < plane->modifier_count; i++) {
213            if (modifier == plane->modifiers[i])
214                    break;
215    }
216    if (i == plane->modifier_count)
217            return false;
218
219    return true;
220 }
221
222
223 const struct drm_plane_funcs vs_plane_funcs = {
224         .update_plane           = drm_atomic_helper_update_plane,
225         .disable_plane          = drm_atomic_helper_disable_plane,
226         .destroy                = vs_plane_destory,
227         .reset                  = vs_plane_reset,
228         .atomic_duplicate_state = vs_plane_atomic_duplicate_state,
229         .atomic_destroy_state   = vs_plane_atomic_destroy_state,
230         .atomic_set_property    = vs_plane_atomic_set_property,
231         .atomic_get_property    = vs_plane_atomic_get_property,
232         .format_mod_supported   = vs_format_mod_supported,
233 };
234
235 static unsigned char vs_get_plane_number(struct drm_framebuffer *fb)
236 {
237         const struct drm_format_info *info;
238
239         if (!fb)
240                 return 0;
241
242         info = drm_format_info(fb->format->format);
243         if (!info || info->num_planes > MAX_NUM_PLANES)
244                 return 0;
245
246         return info->num_planes;
247 }
248
249
250 static int vs_plane_atomic_check(struct drm_plane *plane,
251                            struct drm_atomic_state *state)
252 {
253         struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
254                                                                                  plane);
255         struct vs_plane *vs_plane = to_vs_plane(plane);
256         struct drm_framebuffer *fb = new_plane_state->fb;
257         struct drm_crtc *crtc = new_plane_state->crtc;
258         struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
259
260         if (!crtc || !fb)
261                 return 0;
262
263         //return vs_plane->funcs->check(vs_crtc->dev, vs_plane, new_plane_state);
264         return vs_plane->funcs->check(vs_crtc->dev, plane, state);
265 }
266
267 static void vs_plane_atomic_update(struct drm_plane *plane,
268                 struct drm_atomic_state *state)
269 {
270         struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
271                                                                            plane);
272         unsigned char i, num_planes;
273         struct drm_framebuffer *fb;
274         struct vs_plane *vs_plane = to_vs_plane(plane);
275         //struct drm_plane_state *state = plane->state;
276         struct vs_crtc *vs_crtc = to_vs_crtc(new_state->crtc);
277         struct vs_plane_state *plane_state = to_vs_plane_state(new_state);
278         //struct drm_format_name_buf *name = &plane_state->status.format_name;
279
280         if (!new_state->fb || !new_state->crtc)
281                 return;
282
283         fb = new_state->fb;
284
285         num_planes = vs_get_plane_number(fb);
286
287         for (i = 0; i < num_planes; i++) {
288                 struct vs_gem_object *vs_obj;
289
290                 vs_obj = vs_fb_get_gem_obj(fb, i);
291                 vs_plane->dma_addr[i] = vs_obj->iova + fb->offsets[i];
292         }
293
294         plane_state->status.src = drm_plane_state_src(new_state);
295         plane_state->status.dest = drm_plane_state_dest(new_state);
296         //drm_get_format_name(fb->format->format, name);
297
298         vs_plane->funcs->update(vs_crtc->dev, vs_plane, plane, state);
299 }
300
301 static void vs_plane_atomic_disable(struct drm_plane *plane,
302                                          struct drm_atomic_state *state)
303 {
304         struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
305                                                                                    plane);
306         struct vs_plane *vs_plane = to_vs_plane(plane);
307         struct vs_crtc *vs_crtc = to_vs_crtc(old_state->crtc);
308
309         vs_plane->funcs->disable(vs_crtc->dev, vs_plane, old_state);
310 }
311
312 const struct drm_plane_helper_funcs vs_plane_helper_funcs = {
313         .atomic_check   = vs_plane_atomic_check,
314         .atomic_update  = vs_plane_atomic_update,
315         .atomic_disable = vs_plane_atomic_disable,
316 };
317
318 static const struct drm_prop_enum_list vs_degamma_mode_enum_list[] = {
319         { VS_DEGAMMA_DISABLE,   "disabled" },
320         { VS_DEGAMMA_BT709, "preset degamma for BT709" },
321         { VS_DEGAMMA_BT2020,    "preset degamma for BT2020" },
322 };
323
324 struct vs_plane *vs_plane_create(struct drm_device *drm_dev,
325                                  struct vs_plane_info *info,
326                                  unsigned int layer_num,
327                                  unsigned int possible_crtcs)
328 {
329         struct vs_plane *plane;
330         int ret;
331
332         if (!info)
333                 return NULL;
334
335         plane = kzalloc(sizeof(struct vs_plane), GFP_KERNEL);
336         if (!plane)
337                 return NULL;
338
339         ret = drm_universal_plane_init(drm_dev, &plane->base, possible_crtcs,
340                                 &vs_plane_funcs, info->formats,
341                                 info->num_formats, info->modifiers, info->type,
342                                 info->name ? info->name : NULL);
343         if (ret)
344                 goto err_free_plane;
345
346         drm_plane_helper_add(&plane->base, &vs_plane_helper_funcs);
347
348         /* Set up the plane properties */
349         if (info->degamma_size) {
350                 plane->degamma_mode = drm_property_create_enum(drm_dev, 0,
351                                           "DEGAMMA_MODE",
352                                           vs_degamma_mode_enum_list,
353                                           ARRAY_SIZE(vs_degamma_mode_enum_list));
354
355                 if (!plane->degamma_mode)
356                         goto error_cleanup_plane;
357
358                 drm_object_attach_property(&plane->base.base,
359                                            plane->degamma_mode,
360                                            VS_DEGAMMA_DISABLE);
361         }
362
363         if (info->rotation) {
364                 ret = drm_plane_create_rotation_property(&plane->base,
365                                                          DRM_MODE_ROTATE_0,
366                                                          info->rotation);
367                 if (ret)
368                         goto error_cleanup_plane;
369         }
370
371         if (info->blend_mode) {
372                 ret = drm_plane_create_blend_mode_property(&plane->base,
373                                                            info->blend_mode);
374                 if (ret)
375                         goto error_cleanup_plane;
376                 ret = drm_plane_create_alpha_property(&plane->base);
377                 if (ret)
378                         goto error_cleanup_plane;
379         }
380
381         if (info->color_encoding) {
382                 ret = drm_plane_create_color_properties(&plane->base,
383                                            info->color_encoding,
384                                            BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
385                                            DRM_COLOR_YCBCR_BT709,
386                                            DRM_COLOR_YCBCR_LIMITED_RANGE);
387                 if (ret)
388                         goto error_cleanup_plane;
389         }
390
391         if (info->zpos != 255) {
392                 ret = drm_plane_create_zpos_property(&plane->base, info->zpos, 0, layer_num - 1);
393                 if (ret)
394                         goto error_cleanup_plane;
395         }
396 #if KERNEL_VERSION(5, 8, 0) <= LINUX_VERSION_CODE
397         else {
398                 ret = drm_plane_create_zpos_immutable_property(&plane->base,
399                                                                                                            info->zpos);
400                 if (ret)
401                         goto error_cleanup_plane;
402         }
403 #endif
404
405         if (info->watermark) {
406                 plane->watermark_prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB,
407                                                                  "WATERMARK", 0);
408                 if (!plane->watermark_prop)
409                         goto error_cleanup_plane;
410
411                 drm_object_attach_property(&plane->base.base, plane->watermark_prop, 0);
412         }
413
414         if (info->color_mgmt) {
415                 plane->color_mgmt_prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB,
416                                                                  "COLOR_CONFIG", 0);
417                 if (!plane->color_mgmt_prop)
418                         goto error_cleanup_plane;
419
420                 drm_object_attach_property(&plane->base.base, plane->color_mgmt_prop, 0);
421         }
422
423         if (info->roi) {
424                 plane->roi_prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB,
425                                                          "ROI", 0);
426                 if (!plane->roi_prop)
427                         goto error_cleanup_plane;
428
429                 drm_object_attach_property(&plane->base.base, plane->roi_prop, 0);
430         }
431
432         return plane;
433
434 error_cleanup_plane:
435         drm_plane_cleanup(&plane->base);
436 err_free_plane:
437         kfree(plane);
438         return NULL;
439 }