]> Git Repo - linux.git/blob - drivers/gpu/drm/vc4/vc4_plane.c
Merge tag 'acpi-4.21-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[linux.git] / drivers / gpu / drm / vc4 / vc4_plane.c
1 /*
2  * Copyright (C) 2015 Broadcom
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
8
9 /**
10  * DOC: VC4 plane module
11  *
12  * Each DRM plane is a layer of pixels being scanned out by the HVS.
13  *
14  * At atomic modeset check time, we compute the HVS display element
15  * state that would be necessary for displaying the plane (giving us a
16  * chance to figure out if a plane configuration is invalid), then at
17  * atomic flush time the CRTC will ask us to write our element state
18  * into the region of the HVS that it has allocated for us.
19  */
20
21 #include <drm/drm_atomic.h>
22 #include <drm/drm_atomic_helper.h>
23 #include <drm/drm_fb_cma_helper.h>
24 #include <drm/drm_plane_helper.h>
25 #include <drm/drm_atomic_uapi.h>
26
27 #include "uapi/drm/vc4_drm.h"
28 #include "vc4_drv.h"
29 #include "vc4_regs.h"
30
31 static const struct hvs_format {
32         u32 drm; /* DRM_FORMAT_* */
33         u32 hvs; /* HVS_FORMAT_* */
34         u32 pixel_order;
35 } hvs_formats[] = {
36         {
37                 .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
38                 .pixel_order = HVS_PIXEL_ORDER_ABGR,
39         },
40         {
41                 .drm = DRM_FORMAT_ARGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
42                 .pixel_order = HVS_PIXEL_ORDER_ABGR,
43         },
44         {
45                 .drm = DRM_FORMAT_ABGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
46                 .pixel_order = HVS_PIXEL_ORDER_ARGB,
47         },
48         {
49                 .drm = DRM_FORMAT_XBGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
50                 .pixel_order = HVS_PIXEL_ORDER_ARGB,
51         },
52         {
53                 .drm = DRM_FORMAT_RGB565, .hvs = HVS_PIXEL_FORMAT_RGB565,
54                 .pixel_order = HVS_PIXEL_ORDER_XRGB,
55         },
56         {
57                 .drm = DRM_FORMAT_BGR565, .hvs = HVS_PIXEL_FORMAT_RGB565,
58                 .pixel_order = HVS_PIXEL_ORDER_XBGR,
59         },
60         {
61                 .drm = DRM_FORMAT_ARGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
62                 .pixel_order = HVS_PIXEL_ORDER_ABGR,
63         },
64         {
65                 .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
66                 .pixel_order = HVS_PIXEL_ORDER_ABGR,
67         },
68         {
69                 .drm = DRM_FORMAT_RGB888, .hvs = HVS_PIXEL_FORMAT_RGB888,
70                 .pixel_order = HVS_PIXEL_ORDER_XRGB,
71         },
72         {
73                 .drm = DRM_FORMAT_BGR888, .hvs = HVS_PIXEL_FORMAT_RGB888,
74                 .pixel_order = HVS_PIXEL_ORDER_XBGR,
75         },
76         {
77                 .drm = DRM_FORMAT_YUV422,
78                 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
79                 .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
80         },
81         {
82                 .drm = DRM_FORMAT_YVU422,
83                 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
84                 .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
85         },
86         {
87                 .drm = DRM_FORMAT_YUV420,
88                 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
89                 .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
90         },
91         {
92                 .drm = DRM_FORMAT_YVU420,
93                 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
94                 .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
95         },
96         {
97                 .drm = DRM_FORMAT_NV12,
98                 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE,
99                 .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
100         },
101         {
102                 .drm = DRM_FORMAT_NV21,
103                 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE,
104                 .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
105         },
106         {
107                 .drm = DRM_FORMAT_NV16,
108                 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
109                 .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
110         },
111         {
112                 .drm = DRM_FORMAT_NV61,
113                 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
114                 .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
115         },
116 };
117
118 static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
119 {
120         unsigned i;
121
122         for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) {
123                 if (hvs_formats[i].drm == drm_format)
124                         return &hvs_formats[i];
125         }
126
127         return NULL;
128 }
129
130 static enum vc4_scaling_mode vc4_get_scaling_mode(u32 src, u32 dst)
131 {
132         if (dst == src)
133                 return VC4_SCALING_NONE;
134         if (3 * dst >= 2 * src)
135                 return VC4_SCALING_PPF;
136         else
137                 return VC4_SCALING_TPZ;
138 }
139
140 static bool plane_enabled(struct drm_plane_state *state)
141 {
142         return state->fb && state->crtc;
143 }
144
145 static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane)
146 {
147         struct vc4_plane_state *vc4_state;
148
149         if (WARN_ON(!plane->state))
150                 return NULL;
151
152         vc4_state = kmemdup(plane->state, sizeof(*vc4_state), GFP_KERNEL);
153         if (!vc4_state)
154                 return NULL;
155
156         memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm));
157         vc4_state->dlist_initialized = 0;
158
159         __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base);
160
161         if (vc4_state->dlist) {
162                 vc4_state->dlist = kmemdup(vc4_state->dlist,
163                                            vc4_state->dlist_count * 4,
164                                            GFP_KERNEL);
165                 if (!vc4_state->dlist) {
166                         kfree(vc4_state);
167                         return NULL;
168                 }
169                 vc4_state->dlist_size = vc4_state->dlist_count;
170         }
171
172         return &vc4_state->base;
173 }
174
175 static void vc4_plane_destroy_state(struct drm_plane *plane,
176                                     struct drm_plane_state *state)
177 {
178         struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
179         struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
180
181         if (vc4_state->lbm.allocated) {
182                 unsigned long irqflags;
183
184                 spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
185                 drm_mm_remove_node(&vc4_state->lbm);
186                 spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);
187         }
188
189         kfree(vc4_state->dlist);
190         __drm_atomic_helper_plane_destroy_state(&vc4_state->base);
191         kfree(state);
192 }
193
194 /* Called during init to allocate the plane's atomic state. */
195 static void vc4_plane_reset(struct drm_plane *plane)
196 {
197         struct vc4_plane_state *vc4_state;
198
199         WARN_ON(plane->state);
200
201         vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
202         if (!vc4_state)
203                 return;
204
205         __drm_atomic_helper_plane_reset(plane, &vc4_state->base);
206 }
207
208 static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val)
209 {
210         if (vc4_state->dlist_count == vc4_state->dlist_size) {
211                 u32 new_size = max(4u, vc4_state->dlist_count * 2);
212                 u32 *new_dlist = kmalloc_array(new_size, 4, GFP_KERNEL);
213
214                 if (!new_dlist)
215                         return;
216                 memcpy(new_dlist, vc4_state->dlist, vc4_state->dlist_count * 4);
217
218                 kfree(vc4_state->dlist);
219                 vc4_state->dlist = new_dlist;
220                 vc4_state->dlist_size = new_size;
221         }
222
223         vc4_state->dlist[vc4_state->dlist_count++] = val;
224 }
225
226 /* Returns the scl0/scl1 field based on whether the dimensions need to
227  * be up/down/non-scaled.
228  *
229  * This is a replication of a table from the spec.
230  */
231 static u32 vc4_get_scl_field(struct drm_plane_state *state, int plane)
232 {
233         struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
234
235         switch (vc4_state->x_scaling[plane] << 2 | vc4_state->y_scaling[plane]) {
236         case VC4_SCALING_PPF << 2 | VC4_SCALING_PPF:
237                 return SCALER_CTL0_SCL_H_PPF_V_PPF;
238         case VC4_SCALING_TPZ << 2 | VC4_SCALING_PPF:
239                 return SCALER_CTL0_SCL_H_TPZ_V_PPF;
240         case VC4_SCALING_PPF << 2 | VC4_SCALING_TPZ:
241                 return SCALER_CTL0_SCL_H_PPF_V_TPZ;
242         case VC4_SCALING_TPZ << 2 | VC4_SCALING_TPZ:
243                 return SCALER_CTL0_SCL_H_TPZ_V_TPZ;
244         case VC4_SCALING_PPF << 2 | VC4_SCALING_NONE:
245                 return SCALER_CTL0_SCL_H_PPF_V_NONE;
246         case VC4_SCALING_NONE << 2 | VC4_SCALING_PPF:
247                 return SCALER_CTL0_SCL_H_NONE_V_PPF;
248         case VC4_SCALING_NONE << 2 | VC4_SCALING_TPZ:
249                 return SCALER_CTL0_SCL_H_NONE_V_TPZ;
250         case VC4_SCALING_TPZ << 2 | VC4_SCALING_NONE:
251                 return SCALER_CTL0_SCL_H_TPZ_V_NONE;
252         default:
253         case VC4_SCALING_NONE << 2 | VC4_SCALING_NONE:
254                 /* The unity case is independently handled by
255                  * SCALER_CTL0_UNITY.
256                  */
257                 return 0;
258         }
259 }
260
261 static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
262 {
263         struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
264         struct drm_framebuffer *fb = state->fb;
265         struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
266         u32 subpixel_src_mask = (1 << 16) - 1;
267         u32 format = fb->format->format;
268         int num_planes = fb->format->num_planes;
269         struct drm_crtc_state *crtc_state;
270         u32 h_subsample, v_subsample;
271         int i, ret;
272
273         crtc_state = drm_atomic_get_existing_crtc_state(state->state,
274                                                         state->crtc);
275         if (!crtc_state) {
276                 DRM_DEBUG_KMS("Invalid crtc state\n");
277                 return -EINVAL;
278         }
279
280         ret = drm_atomic_helper_check_plane_state(state, crtc_state, 1,
281                                                   INT_MAX, true, true);
282         if (ret)
283                 return ret;
284
285         h_subsample = drm_format_horz_chroma_subsampling(format);
286         v_subsample = drm_format_vert_chroma_subsampling(format);
287
288         for (i = 0; i < num_planes; i++)
289                 vc4_state->offsets[i] = bo->paddr + fb->offsets[i];
290
291         /* We don't support subpixel source positioning for scaling. */
292         if ((state->src.x1 & subpixel_src_mask) ||
293             (state->src.x2 & subpixel_src_mask) ||
294             (state->src.y1 & subpixel_src_mask) ||
295             (state->src.y2 & subpixel_src_mask)) {
296                 return -EINVAL;
297         }
298
299         vc4_state->src_x = state->src.x1 >> 16;
300         vc4_state->src_y = state->src.y1 >> 16;
301         vc4_state->src_w[0] = (state->src.x2 - state->src.x1) >> 16;
302         vc4_state->src_h[0] = (state->src.y2 - state->src.y1) >> 16;
303
304         vc4_state->crtc_x = state->dst.x1;
305         vc4_state->crtc_y = state->dst.y1;
306         vc4_state->crtc_w = state->dst.x2 - state->dst.x1;
307         vc4_state->crtc_h = state->dst.y2 - state->dst.y1;
308
309         vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0],
310                                                        vc4_state->crtc_w);
311         vc4_state->y_scaling[0] = vc4_get_scaling_mode(vc4_state->src_h[0],
312                                                        vc4_state->crtc_h);
313
314         vc4_state->is_unity = (vc4_state->x_scaling[0] == VC4_SCALING_NONE &&
315                                vc4_state->y_scaling[0] == VC4_SCALING_NONE);
316
317         if (num_planes > 1) {
318                 vc4_state->is_yuv = true;
319
320                 vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample;
321                 vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample;
322
323                 vc4_state->x_scaling[1] =
324                         vc4_get_scaling_mode(vc4_state->src_w[1],
325                                              vc4_state->crtc_w);
326                 vc4_state->y_scaling[1] =
327                         vc4_get_scaling_mode(vc4_state->src_h[1],
328                                              vc4_state->crtc_h);
329
330                 /* YUV conversion requires that horizontal scaling be enabled
331                  * on the UV plane even if vc4_get_scaling_mode() returned
332                  * VC4_SCALING_NONE (which can happen when the down-scaling
333                  * ratio is 0.5). Let's force it to VC4_SCALING_PPF in this
334                  * case.
335                  */
336                 if (vc4_state->x_scaling[1] == VC4_SCALING_NONE)
337                         vc4_state->x_scaling[1] = VC4_SCALING_PPF;
338         } else {
339                 vc4_state->is_yuv = false;
340                 vc4_state->x_scaling[1] = VC4_SCALING_NONE;
341                 vc4_state->y_scaling[1] = VC4_SCALING_NONE;
342         }
343
344         return 0;
345 }
346
347 static void vc4_write_tpz(struct vc4_plane_state *vc4_state, u32 src, u32 dst)
348 {
349         u32 scale, recip;
350
351         scale = (1 << 16) * src / dst;
352
353         /* The specs note that while the reciprocal would be defined
354          * as (1<<32)/scale, ~0 is close enough.
355          */
356         recip = ~0 / scale;
357
358         vc4_dlist_write(vc4_state,
359                         VC4_SET_FIELD(scale, SCALER_TPZ0_SCALE) |
360                         VC4_SET_FIELD(0, SCALER_TPZ0_IPHASE));
361         vc4_dlist_write(vc4_state,
362                         VC4_SET_FIELD(recip, SCALER_TPZ1_RECIP));
363 }
364
365 static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst)
366 {
367         u32 scale = (1 << 16) * src / dst;
368
369         vc4_dlist_write(vc4_state,
370                         SCALER_PPF_AGC |
371                         VC4_SET_FIELD(scale, SCALER_PPF_SCALE) |
372                         VC4_SET_FIELD(0, SCALER_PPF_IPHASE));
373 }
374
375 static u32 vc4_lbm_size(struct drm_plane_state *state)
376 {
377         struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
378         /* This is the worst case number.  One of the two sizes will
379          * be used depending on the scaling configuration.
380          */
381         u32 pix_per_line = max(vc4_state->src_w[0], (u32)vc4_state->crtc_w);
382         u32 lbm;
383
384         /* LBM is not needed when there's no vertical scaling. */
385         if (vc4_state->y_scaling[0] == VC4_SCALING_NONE &&
386             vc4_state->y_scaling[1] == VC4_SCALING_NONE)
387                 return 0;
388
389         if (!vc4_state->is_yuv) {
390                 if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ)
391                         lbm = pix_per_line * 8;
392                 else {
393                         /* In special cases, this multiplier might be 12. */
394                         lbm = pix_per_line * 16;
395                 }
396         } else {
397                 /* There are cases for this going down to a multiplier
398                  * of 2, but according to the firmware source, the
399                  * table in the docs is somewhat wrong.
400                  */
401                 lbm = pix_per_line * 16;
402         }
403
404         lbm = roundup(lbm, 32);
405
406         return lbm;
407 }
408
409 static void vc4_write_scaling_parameters(struct drm_plane_state *state,
410                                          int channel)
411 {
412         struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
413
414         /* Ch0 H-PPF Word 0: Scaling Parameters */
415         if (vc4_state->x_scaling[channel] == VC4_SCALING_PPF) {
416                 vc4_write_ppf(vc4_state,
417                               vc4_state->src_w[channel], vc4_state->crtc_w);
418         }
419
420         /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */
421         if (vc4_state->y_scaling[channel] == VC4_SCALING_PPF) {
422                 vc4_write_ppf(vc4_state,
423                               vc4_state->src_h[channel], vc4_state->crtc_h);
424                 vc4_dlist_write(vc4_state, 0xc0c0c0c0);
425         }
426
427         /* Ch0 H-TPZ Words 0-1: Scaling Parameters, Recip */
428         if (vc4_state->x_scaling[channel] == VC4_SCALING_TPZ) {
429                 vc4_write_tpz(vc4_state,
430                               vc4_state->src_w[channel], vc4_state->crtc_w);
431         }
432
433         /* Ch0 V-TPZ Words 0-2: Scaling Parameters, Recip, Context */
434         if (vc4_state->y_scaling[channel] == VC4_SCALING_TPZ) {
435                 vc4_write_tpz(vc4_state,
436                               vc4_state->src_h[channel], vc4_state->crtc_h);
437                 vc4_dlist_write(vc4_state, 0xc0c0c0c0);
438         }
439 }
440
441 static int vc4_plane_allocate_lbm(struct drm_plane_state *state)
442 {
443         struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev);
444         struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
445         unsigned long irqflags;
446         u32 lbm_size;
447
448         lbm_size = vc4_lbm_size(state);
449         if (!lbm_size)
450                 return 0;
451
452         if (WARN_ON(!vc4_state->lbm_offset))
453                 return -EINVAL;
454
455         /* Allocate the LBM memory that the HVS will use for temporary
456          * storage due to our scaling/format conversion.
457          */
458         if (!vc4_state->lbm.allocated) {
459                 int ret;
460
461                 spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
462                 ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm,
463                                                  &vc4_state->lbm,
464                                                  lbm_size, 32, 0, 0);
465                 spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);
466
467                 if (ret)
468                         return ret;
469         } else {
470                 WARN_ON_ONCE(lbm_size != vc4_state->lbm.size);
471         }
472
473         vc4_state->dlist[vc4_state->lbm_offset] = vc4_state->lbm.start;
474
475         return 0;
476 }
477
478 /* Writes out a full display list for an active plane to the plane's
479  * private dlist state.
480  */
481 static int vc4_plane_mode_set(struct drm_plane *plane,
482                               struct drm_plane_state *state)
483 {
484         struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
485         struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
486         struct drm_framebuffer *fb = state->fb;
487         u32 ctl0_offset = vc4_state->dlist_count;
488         const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);
489         u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier);
490         int num_planes = drm_format_num_planes(format->drm);
491         u32 h_subsample, v_subsample;
492         bool mix_plane_alpha;
493         bool covers_screen;
494         u32 scl0, scl1, pitch0;
495         u32 tiling;
496         u32 hvs_format = format->hvs;
497         int ret, i;
498
499         if (vc4_state->dlist_initialized)
500                 return 0;
501
502         ret = vc4_plane_setup_clipping_and_scaling(state);
503         if (ret)
504                 return ret;
505
506         /* SCL1 is used for Cb/Cr scaling of planar formats.  For RGB
507          * and 4:4:4, scl1 should be set to scl0 so both channels of
508          * the scaler do the same thing.  For YUV, the Y plane needs
509          * to be put in channel 1 and Cb/Cr in channel 0, so we swap
510          * the scl fields here.
511          */
512         if (num_planes == 1) {
513                 scl0 = vc4_get_scl_field(state, 0);
514                 scl1 = scl0;
515         } else {
516                 scl0 = vc4_get_scl_field(state, 1);
517                 scl1 = vc4_get_scl_field(state, 0);
518         }
519
520         h_subsample = drm_format_horz_chroma_subsampling(format->drm);
521         v_subsample = drm_format_vert_chroma_subsampling(format->drm);
522
523         switch (base_format_mod) {
524         case DRM_FORMAT_MOD_LINEAR:
525                 tiling = SCALER_CTL0_TILING_LINEAR;
526                 pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH);
527
528                 /* Adjust the base pointer to the first pixel to be scanned
529                  * out.
530                  */
531                 for (i = 0; i < num_planes; i++) {
532                         vc4_state->offsets[i] += vc4_state->src_y /
533                                                  (i ? v_subsample : 1) *
534                                                  fb->pitches[i];
535                         vc4_state->offsets[i] += vc4_state->src_x /
536                                                  (i ? h_subsample : 1) *
537                                                  fb->format->cpp[i];
538                 }
539
540                 break;
541
542         case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: {
543                 u32 tile_size_shift = 12; /* T tiles are 4kb */
544                 /* Whole-tile offsets, mostly for setting the pitch. */
545                 u32 tile_w_shift = fb->format->cpp[0] == 2 ? 6 : 5;
546                 u32 tile_h_shift = 5; /* 16 and 32bpp are 32 pixels high */
547                 u32 tile_w_mask = (1 << tile_w_shift) - 1;
548                 /* The height mask on 32-bit-per-pixel tiles is 63, i.e. twice
549                  * the height (in pixels) of a 4k tile.
550                  */
551                 u32 tile_h_mask = (2 << tile_h_shift) - 1;
552                 /* For T-tiled, the FB pitch is "how many bytes from one row to
553                  * the next, such that
554                  *
555                  *      pitch * tile_h == tile_size * tiles_per_row
556                  */
557                 u32 tiles_w = fb->pitches[0] >> (tile_size_shift - tile_h_shift);
558                 u32 tiles_l = vc4_state->src_x >> tile_w_shift;
559                 u32 tiles_r = tiles_w - tiles_l;
560                 u32 tiles_t = vc4_state->src_y >> tile_h_shift;
561                 /* Intra-tile offsets, which modify the base address (the
562                  * SCALER_PITCH0_TILE_Y_OFFSET tells HVS how to walk from that
563                  * base address).
564                  */
565                 u32 tile_y = (vc4_state->src_y >> 4) & 1;
566                 u32 subtile_y = (vc4_state->src_y >> 2) & 3;
567                 u32 utile_y = vc4_state->src_y & 3;
568                 u32 x_off = vc4_state->src_x & tile_w_mask;
569                 u32 y_off = vc4_state->src_y & tile_h_mask;
570
571                 tiling = SCALER_CTL0_TILING_256B_OR_T;
572                 pitch0 = (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) |
573                           VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) |
574                           VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) |
575                           VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R));
576                 vc4_state->offsets[0] += tiles_t * (tiles_w << tile_size_shift);
577                 vc4_state->offsets[0] += subtile_y << 8;
578                 vc4_state->offsets[0] += utile_y << 4;
579
580                 /* Rows of tiles alternate left-to-right and right-to-left. */
581                 if (tiles_t & 1) {
582                         pitch0 |= SCALER_PITCH0_TILE_INITIAL_LINE_DIR;
583                         vc4_state->offsets[0] += (tiles_w - tiles_l) <<
584                                                  tile_size_shift;
585                         vc4_state->offsets[0] -= (1 + !tile_y) << 10;
586                 } else {
587                         vc4_state->offsets[0] += tiles_l << tile_size_shift;
588                         vc4_state->offsets[0] += tile_y << 10;
589                 }
590
591                 break;
592         }
593
594         case DRM_FORMAT_MOD_BROADCOM_SAND64:
595         case DRM_FORMAT_MOD_BROADCOM_SAND128:
596         case DRM_FORMAT_MOD_BROADCOM_SAND256: {
597                 uint32_t param = fourcc_mod_broadcom_param(fb->modifier);
598
599                 /* Column-based NV12 or RGBA.
600                  */
601                 if (fb->format->num_planes > 1) {
602                         if (hvs_format != HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE) {
603                                 DRM_DEBUG_KMS("SAND format only valid for NV12/21");
604                                 return -EINVAL;
605                         }
606                         hvs_format = HVS_PIXEL_FORMAT_H264;
607                 } else {
608                         if (base_format_mod == DRM_FORMAT_MOD_BROADCOM_SAND256) {
609                                 DRM_DEBUG_KMS("SAND256 format only valid for H.264");
610                                 return -EINVAL;
611                         }
612                 }
613
614                 switch (base_format_mod) {
615                 case DRM_FORMAT_MOD_BROADCOM_SAND64:
616                         tiling = SCALER_CTL0_TILING_64B;
617                         break;
618                 case DRM_FORMAT_MOD_BROADCOM_SAND128:
619                         tiling = SCALER_CTL0_TILING_128B;
620                         break;
621                 case DRM_FORMAT_MOD_BROADCOM_SAND256:
622                         tiling = SCALER_CTL0_TILING_256B_OR_T;
623                         break;
624                 default:
625                         break;
626                 }
627
628                 if (param > SCALER_TILE_HEIGHT_MASK) {
629                         DRM_DEBUG_KMS("SAND height too large (%d)\n", param);
630                         return -EINVAL;
631                 }
632
633                 pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT);
634                 break;
635         }
636
637         default:
638                 DRM_DEBUG_KMS("Unsupported FB tiling flag 0x%16llx",
639                               (long long)fb->modifier);
640                 return -EINVAL;
641         }
642
643         /* Control word */
644         vc4_dlist_write(vc4_state,
645                         SCALER_CTL0_VALID |
646                         VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND, SCALER_CTL0_RGBA_EXPAND) |
647                         (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
648                         (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
649                         VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
650                         (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |
651                         VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
652                         VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1));
653
654         /* Position Word 0: Image Positions and Alpha Value */
655         vc4_state->pos0_offset = vc4_state->dlist_count;
656         vc4_dlist_write(vc4_state,
657                         VC4_SET_FIELD(state->alpha >> 8, SCALER_POS0_FIXED_ALPHA) |
658                         VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) |
659                         VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y));
660
661         /* Position Word 1: Scaled Image Dimensions. */
662         if (!vc4_state->is_unity) {
663                 vc4_dlist_write(vc4_state,
664                                 VC4_SET_FIELD(vc4_state->crtc_w,
665                                               SCALER_POS1_SCL_WIDTH) |
666                                 VC4_SET_FIELD(vc4_state->crtc_h,
667                                               SCALER_POS1_SCL_HEIGHT));
668         }
669
670         /* Don't waste cycles mixing with plane alpha if the set alpha
671          * is opaque or there is no per-pixel alpha information.
672          * In any case we use the alpha property value as the fixed alpha.
673          */
674         mix_plane_alpha = state->alpha != DRM_BLEND_ALPHA_OPAQUE &&
675                           fb->format->has_alpha;
676
677         /* Position Word 2: Source Image Size, Alpha */
678         vc4_state->pos2_offset = vc4_state->dlist_count;
679         vc4_dlist_write(vc4_state,
680                         VC4_SET_FIELD(fb->format->has_alpha ?
681                                       SCALER_POS2_ALPHA_MODE_PIPELINE :
682                                       SCALER_POS2_ALPHA_MODE_FIXED,
683                                       SCALER_POS2_ALPHA_MODE) |
684                         (mix_plane_alpha ? SCALER_POS2_ALPHA_MIX : 0) |
685                         (fb->format->has_alpha ? SCALER_POS2_ALPHA_PREMULT : 0) |
686                         VC4_SET_FIELD(vc4_state->src_w[0], SCALER_POS2_WIDTH) |
687                         VC4_SET_FIELD(vc4_state->src_h[0], SCALER_POS2_HEIGHT));
688
689         /* Position Word 3: Context.  Written by the HVS. */
690         vc4_dlist_write(vc4_state, 0xc0c0c0c0);
691
692
693         /* Pointer Word 0/1/2: RGB / Y / Cb / Cr Pointers
694          *
695          * The pointers may be any byte address.
696          */
697         vc4_state->ptr0_offset = vc4_state->dlist_count;
698         for (i = 0; i < num_planes; i++)
699                 vc4_dlist_write(vc4_state, vc4_state->offsets[i]);
700
701         /* Pointer Context Word 0/1/2: Written by the HVS */
702         for (i = 0; i < num_planes; i++)
703                 vc4_dlist_write(vc4_state, 0xc0c0c0c0);
704
705         /* Pitch word 0 */
706         vc4_dlist_write(vc4_state, pitch0);
707
708         /* Pitch word 1/2 */
709         for (i = 1; i < num_planes; i++) {
710                 if (hvs_format != HVS_PIXEL_FORMAT_H264) {
711                         vc4_dlist_write(vc4_state,
712                                         VC4_SET_FIELD(fb->pitches[i],
713                                                       SCALER_SRC_PITCH));
714                 } else {
715                         vc4_dlist_write(vc4_state, pitch0);
716                 }
717         }
718
719         /* Colorspace conversion words */
720         if (vc4_state->is_yuv) {
721                 vc4_dlist_write(vc4_state, SCALER_CSC0_ITR_R_601_5);
722                 vc4_dlist_write(vc4_state, SCALER_CSC1_ITR_R_601_5);
723                 vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5);
724         }
725
726         vc4_state->lbm_offset = 0;
727
728         if (vc4_state->x_scaling[0] != VC4_SCALING_NONE ||
729             vc4_state->x_scaling[1] != VC4_SCALING_NONE ||
730             vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
731             vc4_state->y_scaling[1] != VC4_SCALING_NONE) {
732                 /* Reserve a slot for the LBM Base Address. The real value will
733                  * be set when calling vc4_plane_allocate_lbm().
734                  */
735                 if (vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
736                     vc4_state->y_scaling[1] != VC4_SCALING_NONE)
737                         vc4_state->lbm_offset = vc4_state->dlist_count++;
738
739                 if (num_planes > 1) {
740                         /* Emit Cb/Cr as channel 0 and Y as channel
741                          * 1. This matches how we set up scl0/scl1
742                          * above.
743                          */
744                         vc4_write_scaling_parameters(state, 1);
745                 }
746                 vc4_write_scaling_parameters(state, 0);
747
748                 /* If any PPF setup was done, then all the kernel
749                  * pointers get uploaded.
750                  */
751                 if (vc4_state->x_scaling[0] == VC4_SCALING_PPF ||
752                     vc4_state->y_scaling[0] == VC4_SCALING_PPF ||
753                     vc4_state->x_scaling[1] == VC4_SCALING_PPF ||
754                     vc4_state->y_scaling[1] == VC4_SCALING_PPF) {
755                         u32 kernel = VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start,
756                                                    SCALER_PPF_KERNEL_OFFSET);
757
758                         /* HPPF plane 0 */
759                         vc4_dlist_write(vc4_state, kernel);
760                         /* VPPF plane 0 */
761                         vc4_dlist_write(vc4_state, kernel);
762                         /* HPPF plane 1 */
763                         vc4_dlist_write(vc4_state, kernel);
764                         /* VPPF plane 1 */
765                         vc4_dlist_write(vc4_state, kernel);
766                 }
767         }
768
769         vc4_state->dlist[ctl0_offset] |=
770                 VC4_SET_FIELD(vc4_state->dlist_count, SCALER_CTL0_SIZE);
771
772         /* crtc_* are already clipped coordinates. */
773         covers_screen = vc4_state->crtc_x == 0 && vc4_state->crtc_y == 0 &&
774                         vc4_state->crtc_w == state->crtc->mode.hdisplay &&
775                         vc4_state->crtc_h == state->crtc->mode.vdisplay;
776         /* Background fill might be necessary when the plane has per-pixel
777          * alpha content or a non-opaque plane alpha and could blend from the
778          * background or does not cover the entire screen.
779          */
780         vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen ||
781                                    state->alpha != DRM_BLEND_ALPHA_OPAQUE;
782
783         /* Flag the dlist as initialized to avoid checking it twice in case
784          * the async update check already called vc4_plane_mode_set() and
785          * decided to fallback to sync update because async update was not
786          * possible.
787          */
788         vc4_state->dlist_initialized = 1;
789
790         return 0;
791 }
792
793 /* If a modeset involves changing the setup of a plane, the atomic
794  * infrastructure will call this to validate a proposed plane setup.
795  * However, if a plane isn't getting updated, this (and the
796  * corresponding vc4_plane_atomic_update) won't get called.  Thus, we
797  * compute the dlist here and have all active plane dlists get updated
798  * in the CRTC's flush.
799  */
800 static int vc4_plane_atomic_check(struct drm_plane *plane,
801                                   struct drm_plane_state *state)
802 {
803         struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
804         int ret;
805
806         vc4_state->dlist_count = 0;
807
808         if (!plane_enabled(state))
809                 return 0;
810
811         ret = vc4_plane_mode_set(plane, state);
812         if (ret)
813                 return ret;
814
815         return vc4_plane_allocate_lbm(state);
816 }
817
818 static void vc4_plane_atomic_update(struct drm_plane *plane,
819                                     struct drm_plane_state *old_state)
820 {
821         /* No contents here.  Since we don't know where in the CRTC's
822          * dlist we should be stored, our dlist is uploaded to the
823          * hardware with vc4_plane_write_dlist() at CRTC atomic_flush
824          * time.
825          */
826 }
827
828 u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist)
829 {
830         struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
831         int i;
832
833         vc4_state->hw_dlist = dlist;
834
835         /* Can't memcpy_toio() because it needs to be 32-bit writes. */
836         for (i = 0; i < vc4_state->dlist_count; i++)
837                 writel(vc4_state->dlist[i], &dlist[i]);
838
839         return vc4_state->dlist_count;
840 }
841
842 u32 vc4_plane_dlist_size(const struct drm_plane_state *state)
843 {
844         const struct vc4_plane_state *vc4_state =
845                 container_of(state, typeof(*vc4_state), base);
846
847         return vc4_state->dlist_count;
848 }
849
850 /* Updates the plane to immediately (well, once the FIFO needs
851  * refilling) scan out from at a new framebuffer.
852  */
853 void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb)
854 {
855         struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
856         struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
857         uint32_t addr;
858
859         /* We're skipping the address adjustment for negative origin,
860          * because this is only called on the primary plane.
861          */
862         WARN_ON_ONCE(plane->state->crtc_x < 0 || plane->state->crtc_y < 0);
863         addr = bo->paddr + fb->offsets[0];
864
865         /* Write the new address into the hardware immediately.  The
866          * scanout will start from this address as soon as the FIFO
867          * needs to refill with pixels.
868          */
869         writel(addr, &vc4_state->hw_dlist[vc4_state->ptr0_offset]);
870
871         /* Also update the CPU-side dlist copy, so that any later
872          * atomic updates that don't do a new modeset on our plane
873          * also use our updated address.
874          */
875         vc4_state->dlist[vc4_state->ptr0_offset] = addr;
876 }
877
878 static void vc4_plane_atomic_async_update(struct drm_plane *plane,
879                                           struct drm_plane_state *state)
880 {
881         struct vc4_plane_state *vc4_state, *new_vc4_state;
882
883         drm_atomic_set_fb_for_plane(plane->state, state->fb);
884         plane->state->crtc_x = state->crtc_x;
885         plane->state->crtc_y = state->crtc_y;
886         plane->state->crtc_w = state->crtc_w;
887         plane->state->crtc_h = state->crtc_h;
888         plane->state->src_x = state->src_x;
889         plane->state->src_y = state->src_y;
890         plane->state->src_w = state->src_w;
891         plane->state->src_h = state->src_h;
892         plane->state->src_h = state->src_h;
893         plane->state->alpha = state->alpha;
894         plane->state->pixel_blend_mode = state->pixel_blend_mode;
895         plane->state->rotation = state->rotation;
896         plane->state->zpos = state->zpos;
897         plane->state->normalized_zpos = state->normalized_zpos;
898         plane->state->color_encoding = state->color_encoding;
899         plane->state->color_range = state->color_range;
900         plane->state->src = state->src;
901         plane->state->dst = state->dst;
902         plane->state->visible = state->visible;
903
904         new_vc4_state = to_vc4_plane_state(state);
905         vc4_state = to_vc4_plane_state(plane->state);
906
907         vc4_state->crtc_x = new_vc4_state->crtc_x;
908         vc4_state->crtc_y = new_vc4_state->crtc_y;
909         vc4_state->crtc_h = new_vc4_state->crtc_h;
910         vc4_state->crtc_w = new_vc4_state->crtc_w;
911         vc4_state->src_x = new_vc4_state->src_x;
912         vc4_state->src_y = new_vc4_state->src_y;
913         memcpy(vc4_state->src_w, new_vc4_state->src_w,
914                sizeof(vc4_state->src_w));
915         memcpy(vc4_state->src_h, new_vc4_state->src_h,
916                sizeof(vc4_state->src_h));
917         memcpy(vc4_state->x_scaling, new_vc4_state->x_scaling,
918                sizeof(vc4_state->x_scaling));
919         memcpy(vc4_state->y_scaling, new_vc4_state->y_scaling,
920                sizeof(vc4_state->y_scaling));
921         vc4_state->is_unity = new_vc4_state->is_unity;
922         vc4_state->is_yuv = new_vc4_state->is_yuv;
923         memcpy(vc4_state->offsets, new_vc4_state->offsets,
924                sizeof(vc4_state->offsets));
925         vc4_state->needs_bg_fill = new_vc4_state->needs_bg_fill;
926
927         /* Update the current vc4_state pos0, pos2 and ptr0 dlist entries. */
928         vc4_state->dlist[vc4_state->pos0_offset] =
929                 new_vc4_state->dlist[vc4_state->pos0_offset];
930         vc4_state->dlist[vc4_state->pos2_offset] =
931                 new_vc4_state->dlist[vc4_state->pos2_offset];
932         vc4_state->dlist[vc4_state->ptr0_offset] =
933                 new_vc4_state->dlist[vc4_state->ptr0_offset];
934
935         /* Note that we can't just call vc4_plane_write_dlist()
936          * because that would smash the context data that the HVS is
937          * currently using.
938          */
939         writel(vc4_state->dlist[vc4_state->pos0_offset],
940                &vc4_state->hw_dlist[vc4_state->pos0_offset]);
941         writel(vc4_state->dlist[vc4_state->pos2_offset],
942                &vc4_state->hw_dlist[vc4_state->pos2_offset]);
943         writel(vc4_state->dlist[vc4_state->ptr0_offset],
944                &vc4_state->hw_dlist[vc4_state->ptr0_offset]);
945 }
946
947 static int vc4_plane_atomic_async_check(struct drm_plane *plane,
948                                         struct drm_plane_state *state)
949 {
950         struct vc4_plane_state *old_vc4_state, *new_vc4_state;
951         int ret;
952         u32 i;
953
954         ret = vc4_plane_mode_set(plane, state);
955         if (ret)
956                 return ret;
957
958         old_vc4_state = to_vc4_plane_state(plane->state);
959         new_vc4_state = to_vc4_plane_state(state);
960         if (old_vc4_state->dlist_count != new_vc4_state->dlist_count ||
961             old_vc4_state->pos0_offset != new_vc4_state->pos0_offset ||
962             old_vc4_state->pos2_offset != new_vc4_state->pos2_offset ||
963             old_vc4_state->ptr0_offset != new_vc4_state->ptr0_offset ||
964             vc4_lbm_size(plane->state) != vc4_lbm_size(state))
965                 return -EINVAL;
966
967         /* Only pos0, pos2 and ptr0 DWORDS can be updated in an async update
968          * if anything else has changed, fallback to a sync update.
969          */
970         for (i = 0; i < new_vc4_state->dlist_count; i++) {
971                 if (i == new_vc4_state->pos0_offset ||
972                     i == new_vc4_state->pos2_offset ||
973                     i == new_vc4_state->ptr0_offset ||
974                     (new_vc4_state->lbm_offset &&
975                      i == new_vc4_state->lbm_offset))
976                         continue;
977
978                 if (new_vc4_state->dlist[i] != old_vc4_state->dlist[i])
979                         return -EINVAL;
980         }
981
982         return 0;
983 }
984
985 static int vc4_prepare_fb(struct drm_plane *plane,
986                           struct drm_plane_state *state)
987 {
988         struct vc4_bo *bo;
989         struct dma_fence *fence;
990         int ret;
991
992         if (!state->fb)
993                 return 0;
994
995         bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base);
996
997         fence = reservation_object_get_excl_rcu(bo->resv);
998         drm_atomic_set_fence_for_plane(state, fence);
999
1000         if (plane->state->fb == state->fb)
1001                 return 0;
1002
1003         ret = vc4_bo_inc_usecnt(bo);
1004         if (ret)
1005                 return ret;
1006
1007         return 0;
1008 }
1009
1010 static void vc4_cleanup_fb(struct drm_plane *plane,
1011                            struct drm_plane_state *state)
1012 {
1013         struct vc4_bo *bo;
1014
1015         if (plane->state->fb == state->fb || !state->fb)
1016                 return;
1017
1018         bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base);
1019         vc4_bo_dec_usecnt(bo);
1020 }
1021
1022 static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
1023         .atomic_check = vc4_plane_atomic_check,
1024         .atomic_update = vc4_plane_atomic_update,
1025         .prepare_fb = vc4_prepare_fb,
1026         .cleanup_fb = vc4_cleanup_fb,
1027         .atomic_async_check = vc4_plane_atomic_async_check,
1028         .atomic_async_update = vc4_plane_atomic_async_update,
1029 };
1030
1031 static void vc4_plane_destroy(struct drm_plane *plane)
1032 {
1033         drm_plane_cleanup(plane);
1034 }
1035
1036 static bool vc4_format_mod_supported(struct drm_plane *plane,
1037                                      uint32_t format,
1038                                      uint64_t modifier)
1039 {
1040         /* Support T_TILING for RGB formats only. */
1041         switch (format) {
1042         case DRM_FORMAT_XRGB8888:
1043         case DRM_FORMAT_ARGB8888:
1044         case DRM_FORMAT_ABGR8888:
1045         case DRM_FORMAT_XBGR8888:
1046         case DRM_FORMAT_RGB565:
1047         case DRM_FORMAT_BGR565:
1048         case DRM_FORMAT_ARGB1555:
1049         case DRM_FORMAT_XRGB1555:
1050                 switch (fourcc_mod_broadcom_mod(modifier)) {
1051                 case DRM_FORMAT_MOD_LINEAR:
1052                 case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
1053                 case DRM_FORMAT_MOD_BROADCOM_SAND64:
1054                 case DRM_FORMAT_MOD_BROADCOM_SAND128:
1055                         return true;
1056                 default:
1057                         return false;
1058                 }
1059         case DRM_FORMAT_NV12:
1060         case DRM_FORMAT_NV21:
1061                 switch (fourcc_mod_broadcom_mod(modifier)) {
1062                 case DRM_FORMAT_MOD_LINEAR:
1063                 case DRM_FORMAT_MOD_BROADCOM_SAND64:
1064                 case DRM_FORMAT_MOD_BROADCOM_SAND128:
1065                 case DRM_FORMAT_MOD_BROADCOM_SAND256:
1066                         return true;
1067                 default:
1068                         return false;
1069                 }
1070         case DRM_FORMAT_YUV422:
1071         case DRM_FORMAT_YVU422:
1072         case DRM_FORMAT_YUV420:
1073         case DRM_FORMAT_YVU420:
1074         case DRM_FORMAT_NV16:
1075         case DRM_FORMAT_NV61:
1076         default:
1077                 return (modifier == DRM_FORMAT_MOD_LINEAR);
1078         }
1079 }
1080
1081 static const struct drm_plane_funcs vc4_plane_funcs = {
1082         .update_plane = drm_atomic_helper_update_plane,
1083         .disable_plane = drm_atomic_helper_disable_plane,
1084         .destroy = vc4_plane_destroy,
1085         .set_property = NULL,
1086         .reset = vc4_plane_reset,
1087         .atomic_duplicate_state = vc4_plane_duplicate_state,
1088         .atomic_destroy_state = vc4_plane_destroy_state,
1089         .format_mod_supported = vc4_format_mod_supported,
1090 };
1091
1092 struct drm_plane *vc4_plane_init(struct drm_device *dev,
1093                                  enum drm_plane_type type)
1094 {
1095         struct drm_plane *plane = NULL;
1096         struct vc4_plane *vc4_plane;
1097         u32 formats[ARRAY_SIZE(hvs_formats)];
1098         int ret = 0;
1099         unsigned i;
1100         static const uint64_t modifiers[] = {
1101                 DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
1102                 DRM_FORMAT_MOD_BROADCOM_SAND128,
1103                 DRM_FORMAT_MOD_BROADCOM_SAND64,
1104                 DRM_FORMAT_MOD_BROADCOM_SAND256,
1105                 DRM_FORMAT_MOD_LINEAR,
1106                 DRM_FORMAT_MOD_INVALID
1107         };
1108
1109         vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane),
1110                                  GFP_KERNEL);
1111         if (!vc4_plane)
1112                 return ERR_PTR(-ENOMEM);
1113
1114         for (i = 0; i < ARRAY_SIZE(hvs_formats); i++)
1115                 formats[i] = hvs_formats[i].drm;
1116
1117         plane = &vc4_plane->base;
1118         ret = drm_universal_plane_init(dev, plane, 0,
1119                                        &vc4_plane_funcs,
1120                                        formats, ARRAY_SIZE(formats),
1121                                        modifiers, type, NULL);
1122
1123         drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
1124
1125         drm_plane_create_alpha_property(plane);
1126
1127         return plane;
1128 }
This page took 0.105469 seconds and 4 git commands to generate.