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