ASoC: fsl-asoc-card: add cs4271 and cs4272 support
[cascardo/linux.git] / drivers / gpu / drm / vc4 / vc4_render_cl.c
1 /*
2  * Copyright © 2014-2015 Broadcom
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23
24 /**
25  * DOC: Render command list generation
26  *
27  * In the VC4 driver, render command list generation is performed by the
28  * kernel instead of userspace.  We do this because validating a
29  * user-submitted command list is hard to get right and has high CPU overhead,
30  * while the number of valid configurations for render command lists is
31  * actually fairly low.
32  */
33
34 #include "uapi/drm/vc4_drm.h"
35 #include "vc4_drv.h"
36 #include "vc4_packet.h"
37
38 struct vc4_rcl_setup {
39         struct drm_gem_cma_object *color_read;
40         struct drm_gem_cma_object *color_write;
41         struct drm_gem_cma_object *zs_read;
42         struct drm_gem_cma_object *zs_write;
43         struct drm_gem_cma_object *msaa_color_write;
44         struct drm_gem_cma_object *msaa_zs_write;
45
46         struct drm_gem_cma_object *rcl;
47         u32 next_offset;
48 };
49
50 static inline void rcl_u8(struct vc4_rcl_setup *setup, u8 val)
51 {
52         *(u8 *)(setup->rcl->vaddr + setup->next_offset) = val;
53         setup->next_offset += 1;
54 }
55
56 static inline void rcl_u16(struct vc4_rcl_setup *setup, u16 val)
57 {
58         *(u16 *)(setup->rcl->vaddr + setup->next_offset) = val;
59         setup->next_offset += 2;
60 }
61
62 static inline void rcl_u32(struct vc4_rcl_setup *setup, u32 val)
63 {
64         *(u32 *)(setup->rcl->vaddr + setup->next_offset) = val;
65         setup->next_offset += 4;
66 }
67
68 /*
69  * Emits a no-op STORE_TILE_BUFFER_GENERAL.
70  *
71  * If we emit a PACKET_TILE_COORDINATES, it must be followed by a store of
72  * some sort before another load is triggered.
73  */
74 static void vc4_store_before_load(struct vc4_rcl_setup *setup)
75 {
76         rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL);
77         rcl_u16(setup,
78                 VC4_SET_FIELD(VC4_LOADSTORE_TILE_BUFFER_NONE,
79                               VC4_LOADSTORE_TILE_BUFFER_BUFFER) |
80                 VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR |
81                 VC4_STORE_TILE_BUFFER_DISABLE_ZS_CLEAR |
82                 VC4_STORE_TILE_BUFFER_DISABLE_VG_MASK_CLEAR);
83         rcl_u32(setup, 0); /* no address, since we're in None mode */
84 }
85
86 /*
87  * Calculates the physical address of the start of a tile in a RCL surface.
88  *
89  * Unlike the other load/store packets,
90  * VC4_PACKET_LOAD/STORE_FULL_RES_TILE_BUFFER don't look at the tile
91  * coordinates packet, and instead just store to the address given.
92  */
93 static uint32_t vc4_full_res_offset(struct vc4_exec_info *exec,
94                                     struct drm_gem_cma_object *bo,
95                                     struct drm_vc4_submit_rcl_surface *surf,
96                                     uint8_t x, uint8_t y)
97 {
98         return bo->paddr + surf->offset + VC4_TILE_BUFFER_SIZE *
99                 (DIV_ROUND_UP(exec->args->width, 32) * y + x);
100 }
101
102 /*
103  * Emits a PACKET_TILE_COORDINATES if one isn't already pending.
104  *
105  * The tile coordinates packet triggers a pending load if there is one, are
106  * used for clipping during rendering, and determine where loads/stores happen
107  * relative to their base address.
108  */
109 static void vc4_tile_coordinates(struct vc4_rcl_setup *setup,
110                                  uint32_t x, uint32_t y)
111 {
112         rcl_u8(setup, VC4_PACKET_TILE_COORDINATES);
113         rcl_u8(setup, x);
114         rcl_u8(setup, y);
115 }
116
117 static void emit_tile(struct vc4_exec_info *exec,
118                       struct vc4_rcl_setup *setup,
119                       uint8_t x, uint8_t y, bool first, bool last)
120 {
121         struct drm_vc4_submit_cl *args = exec->args;
122         bool has_bin = args->bin_cl_size != 0;
123
124         /* Note that the load doesn't actually occur until the
125          * tile coords packet is processed, and only one load
126          * may be outstanding at a time.
127          */
128         if (setup->color_read) {
129                 if (args->color_read.flags &
130                     VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
131                         rcl_u8(setup, VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER);
132                         rcl_u32(setup,
133                                 vc4_full_res_offset(exec, setup->color_read,
134                                                     &args->color_read, x, y) |
135                                 VC4_LOADSTORE_FULL_RES_DISABLE_ZS);
136                 } else {
137                         rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL);
138                         rcl_u16(setup, args->color_read.bits);
139                         rcl_u32(setup, setup->color_read->paddr +
140                                 args->color_read.offset);
141                 }
142         }
143
144         if (setup->zs_read) {
145                 if (args->zs_read.flags &
146                     VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
147                         rcl_u8(setup, VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER);
148                         rcl_u32(setup,
149                                 vc4_full_res_offset(exec, setup->zs_read,
150                                                     &args->zs_read, x, y) |
151                                 VC4_LOADSTORE_FULL_RES_DISABLE_COLOR);
152                 } else {
153                         if (setup->color_read) {
154                                 /* Exec previous load. */
155                                 vc4_tile_coordinates(setup, x, y);
156                                 vc4_store_before_load(setup);
157                         }
158
159                         rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL);
160                         rcl_u16(setup, args->zs_read.bits);
161                         rcl_u32(setup, setup->zs_read->paddr +
162                                 args->zs_read.offset);
163                 }
164         }
165
166         /* Clipping depends on tile coordinates having been
167          * emitted, so we always need one here.
168          */
169         vc4_tile_coordinates(setup, x, y);
170
171         /* Wait for the binner before jumping to the first
172          * tile's lists.
173          */
174         if (first && has_bin)
175                 rcl_u8(setup, VC4_PACKET_WAIT_ON_SEMAPHORE);
176
177         if (has_bin) {
178                 rcl_u8(setup, VC4_PACKET_BRANCH_TO_SUB_LIST);
179                 rcl_u32(setup, (exec->tile_bo->paddr +
180                                 exec->tile_alloc_offset +
181                                 (y * exec->bin_tiles_x + x) * 32));
182         }
183
184         if (setup->msaa_color_write) {
185                 bool last_tile_write = (!setup->msaa_zs_write &&
186                                         !setup->zs_write &&
187                                         !setup->color_write);
188                 uint32_t bits = VC4_LOADSTORE_FULL_RES_DISABLE_ZS;
189
190                 if (!last_tile_write)
191                         bits |= VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL;
192                 else if (last)
193                         bits |= VC4_LOADSTORE_FULL_RES_EOF;
194                 rcl_u8(setup, VC4_PACKET_STORE_FULL_RES_TILE_BUFFER);
195                 rcl_u32(setup,
196                         vc4_full_res_offset(exec, setup->msaa_color_write,
197                                             &args->msaa_color_write, x, y) |
198                         bits);
199         }
200
201         if (setup->msaa_zs_write) {
202                 bool last_tile_write = (!setup->zs_write &&
203                                         !setup->color_write);
204                 uint32_t bits = VC4_LOADSTORE_FULL_RES_DISABLE_COLOR;
205
206                 if (setup->msaa_color_write)
207                         vc4_tile_coordinates(setup, x, y);
208                 if (!last_tile_write)
209                         bits |= VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL;
210                 else if (last)
211                         bits |= VC4_LOADSTORE_FULL_RES_EOF;
212                 rcl_u8(setup, VC4_PACKET_STORE_FULL_RES_TILE_BUFFER);
213                 rcl_u32(setup,
214                         vc4_full_res_offset(exec, setup->msaa_zs_write,
215                                             &args->msaa_zs_write, x, y) |
216                         bits);
217         }
218
219         if (setup->zs_write) {
220                 bool last_tile_write = !setup->color_write;
221
222                 if (setup->msaa_color_write || setup->msaa_zs_write)
223                         vc4_tile_coordinates(setup, x, y);
224
225                 rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL);
226                 rcl_u16(setup, args->zs_write.bits |
227                         (last_tile_write ?
228                          0 : VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR));
229                 rcl_u32(setup,
230                         (setup->zs_write->paddr + args->zs_write.offset) |
231                         ((last && last_tile_write) ?
232                          VC4_LOADSTORE_TILE_BUFFER_EOF : 0));
233         }
234
235         if (setup->color_write) {
236                 if (setup->msaa_color_write || setup->msaa_zs_write ||
237                     setup->zs_write) {
238                         vc4_tile_coordinates(setup, x, y);
239                 }
240
241                 if (last)
242                         rcl_u8(setup, VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF);
243                 else
244                         rcl_u8(setup, VC4_PACKET_STORE_MS_TILE_BUFFER);
245         }
246 }
247
248 static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec,
249                              struct vc4_rcl_setup *setup)
250 {
251         struct drm_vc4_submit_cl *args = exec->args;
252         bool has_bin = args->bin_cl_size != 0;
253         uint8_t min_x_tile = args->min_x_tile;
254         uint8_t min_y_tile = args->min_y_tile;
255         uint8_t max_x_tile = args->max_x_tile;
256         uint8_t max_y_tile = args->max_y_tile;
257         uint8_t xtiles = max_x_tile - min_x_tile + 1;
258         uint8_t ytiles = max_y_tile - min_y_tile + 1;
259         uint8_t x, y;
260         uint32_t size, loop_body_size;
261
262         size = VC4_PACKET_TILE_RENDERING_MODE_CONFIG_SIZE;
263         loop_body_size = VC4_PACKET_TILE_COORDINATES_SIZE;
264
265         if (args->flags & VC4_SUBMIT_CL_USE_CLEAR_COLOR) {
266                 size += VC4_PACKET_CLEAR_COLORS_SIZE +
267                         VC4_PACKET_TILE_COORDINATES_SIZE +
268                         VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE;
269         }
270
271         if (setup->color_read) {
272                 if (args->color_read.flags &
273                     VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
274                         loop_body_size += VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER_SIZE;
275                 } else {
276                         loop_body_size += VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE;
277                 }
278         }
279         if (setup->zs_read) {
280                 if (args->zs_read.flags &
281                     VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
282                         loop_body_size += VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER_SIZE;
283                 } else {
284                         if (setup->color_read &&
285                             !(args->color_read.flags &
286                               VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES)) {
287                                 loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE;
288                                 loop_body_size += VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE;
289                         }
290                         loop_body_size += VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE;
291                 }
292         }
293
294         if (has_bin) {
295                 size += VC4_PACKET_WAIT_ON_SEMAPHORE_SIZE;
296                 loop_body_size += VC4_PACKET_BRANCH_TO_SUB_LIST_SIZE;
297         }
298
299         if (setup->msaa_color_write)
300                 loop_body_size += VC4_PACKET_STORE_FULL_RES_TILE_BUFFER_SIZE;
301         if (setup->msaa_zs_write)
302                 loop_body_size += VC4_PACKET_STORE_FULL_RES_TILE_BUFFER_SIZE;
303
304         if (setup->zs_write)
305                 loop_body_size += VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE;
306         if (setup->color_write)
307                 loop_body_size += VC4_PACKET_STORE_MS_TILE_BUFFER_SIZE;
308
309         /* We need a VC4_PACKET_TILE_COORDINATES in between each store. */
310         loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE *
311                 ((setup->msaa_color_write != NULL) +
312                  (setup->msaa_zs_write != NULL) +
313                  (setup->color_write != NULL) +
314                  (setup->zs_write != NULL) - 1);
315
316         size += xtiles * ytiles * loop_body_size;
317
318         setup->rcl = &vc4_bo_create(dev, size, true)->base;
319         if (!setup->rcl)
320                 return -ENOMEM;
321         list_add_tail(&to_vc4_bo(&setup->rcl->base)->unref_head,
322                       &exec->unref_list);
323
324         rcl_u8(setup, VC4_PACKET_TILE_RENDERING_MODE_CONFIG);
325         rcl_u32(setup,
326                 (setup->color_write ? (setup->color_write->paddr +
327                                        args->color_write.offset) :
328                  0));
329         rcl_u16(setup, args->width);
330         rcl_u16(setup, args->height);
331         rcl_u16(setup, args->color_write.bits);
332
333         /* The tile buffer gets cleared when the previous tile is stored.  If
334          * the clear values changed between frames, then the tile buffer has
335          * stale clear values in it, so we have to do a store in None mode (no
336          * writes) so that we trigger the tile buffer clear.
337          */
338         if (args->flags & VC4_SUBMIT_CL_USE_CLEAR_COLOR) {
339                 rcl_u8(setup, VC4_PACKET_CLEAR_COLORS);
340                 rcl_u32(setup, args->clear_color[0]);
341                 rcl_u32(setup, args->clear_color[1]);
342                 rcl_u32(setup, args->clear_z);
343                 rcl_u8(setup, args->clear_s);
344
345                 vc4_tile_coordinates(setup, 0, 0);
346
347                 rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL);
348                 rcl_u16(setup, VC4_LOADSTORE_TILE_BUFFER_NONE);
349                 rcl_u32(setup, 0); /* no address, since we're in None mode */
350         }
351
352         for (y = min_y_tile; y <= max_y_tile; y++) {
353                 for (x = min_x_tile; x <= max_x_tile; x++) {
354                         bool first = (x == min_x_tile && y == min_y_tile);
355                         bool last = (x == max_x_tile && y == max_y_tile);
356
357                         emit_tile(exec, setup, x, y, first, last);
358                 }
359         }
360
361         BUG_ON(setup->next_offset != size);
362         exec->ct1ca = setup->rcl->paddr;
363         exec->ct1ea = setup->rcl->paddr + setup->next_offset;
364
365         return 0;
366 }
367
368 static int vc4_full_res_bounds_check(struct vc4_exec_info *exec,
369                                      struct drm_gem_cma_object *obj,
370                                      struct drm_vc4_submit_rcl_surface *surf)
371 {
372         struct drm_vc4_submit_cl *args = exec->args;
373         u32 render_tiles_stride = DIV_ROUND_UP(exec->args->width, 32);
374
375         if (surf->offset > obj->base.size) {
376                 DRM_ERROR("surface offset %d > BO size %zd\n",
377                           surf->offset, obj->base.size);
378                 return -EINVAL;
379         }
380
381         if ((obj->base.size - surf->offset) / VC4_TILE_BUFFER_SIZE <
382             render_tiles_stride * args->max_y_tile + args->max_x_tile) {
383                 DRM_ERROR("MSAA tile %d, %d out of bounds "
384                           "(bo size %zd, offset %d).\n",
385                           args->max_x_tile, args->max_y_tile,
386                           obj->base.size,
387                           surf->offset);
388                 return -EINVAL;
389         }
390
391         return 0;
392 }
393
394 static int vc4_rcl_msaa_surface_setup(struct vc4_exec_info *exec,
395                                       struct drm_gem_cma_object **obj,
396                                       struct drm_vc4_submit_rcl_surface *surf)
397 {
398         if (surf->flags != 0 || surf->bits != 0) {
399                 DRM_ERROR("MSAA surface had nonzero flags/bits\n");
400                 return -EINVAL;
401         }
402
403         if (surf->hindex == ~0)
404                 return 0;
405
406         *obj = vc4_use_bo(exec, surf->hindex);
407         if (!*obj)
408                 return -EINVAL;
409
410         if (surf->offset & 0xf) {
411                 DRM_ERROR("MSAA write must be 16b aligned.\n");
412                 return -EINVAL;
413         }
414
415         return vc4_full_res_bounds_check(exec, *obj, surf);
416 }
417
418 static int vc4_rcl_surface_setup(struct vc4_exec_info *exec,
419                                  struct drm_gem_cma_object **obj,
420                                  struct drm_vc4_submit_rcl_surface *surf)
421 {
422         uint8_t tiling = VC4_GET_FIELD(surf->bits,
423                                        VC4_LOADSTORE_TILE_BUFFER_TILING);
424         uint8_t buffer = VC4_GET_FIELD(surf->bits,
425                                        VC4_LOADSTORE_TILE_BUFFER_BUFFER);
426         uint8_t format = VC4_GET_FIELD(surf->bits,
427                                        VC4_LOADSTORE_TILE_BUFFER_FORMAT);
428         int cpp;
429         int ret;
430
431         if (surf->flags & ~VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
432                 DRM_ERROR("Extra flags set\n");
433                 return -EINVAL;
434         }
435
436         if (surf->hindex == ~0)
437                 return 0;
438
439         *obj = vc4_use_bo(exec, surf->hindex);
440         if (!*obj)
441                 return -EINVAL;
442
443         if (surf->flags & VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
444                 if (surf == &exec->args->zs_write) {
445                         DRM_ERROR("general zs write may not be a full-res.\n");
446                         return -EINVAL;
447                 }
448
449                 if (surf->bits != 0) {
450                         DRM_ERROR("load/store general bits set with "
451                                   "full res load/store.\n");
452                         return -EINVAL;
453                 }
454
455                 ret = vc4_full_res_bounds_check(exec, *obj, surf);
456                 if (!ret)
457                         return ret;
458
459                 return 0;
460         }
461
462         if (surf->bits & ~(VC4_LOADSTORE_TILE_BUFFER_TILING_MASK |
463                            VC4_LOADSTORE_TILE_BUFFER_BUFFER_MASK |
464                            VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK)) {
465                 DRM_ERROR("Unknown bits in load/store: 0x%04x\n",
466                           surf->bits);
467                 return -EINVAL;
468         }
469
470         if (tiling > VC4_TILING_FORMAT_LT) {
471                 DRM_ERROR("Bad tiling format\n");
472                 return -EINVAL;
473         }
474
475         if (buffer == VC4_LOADSTORE_TILE_BUFFER_ZS) {
476                 if (format != 0) {
477                         DRM_ERROR("No color format should be set for ZS\n");
478                         return -EINVAL;
479                 }
480                 cpp = 4;
481         } else if (buffer == VC4_LOADSTORE_TILE_BUFFER_COLOR) {
482                 switch (format) {
483                 case VC4_LOADSTORE_TILE_BUFFER_BGR565:
484                 case VC4_LOADSTORE_TILE_BUFFER_BGR565_DITHER:
485                         cpp = 2;
486                         break;
487                 case VC4_LOADSTORE_TILE_BUFFER_RGBA8888:
488                         cpp = 4;
489                         break;
490                 default:
491                         DRM_ERROR("Bad tile buffer format\n");
492                         return -EINVAL;
493                 }
494         } else {
495                 DRM_ERROR("Bad load/store buffer %d.\n", buffer);
496                 return -EINVAL;
497         }
498
499         if (surf->offset & 0xf) {
500                 DRM_ERROR("load/store buffer must be 16b aligned.\n");
501                 return -EINVAL;
502         }
503
504         if (!vc4_check_tex_size(exec, *obj, surf->offset, tiling,
505                                 exec->args->width, exec->args->height, cpp)) {
506                 return -EINVAL;
507         }
508
509         return 0;
510 }
511
512 static int
513 vc4_rcl_render_config_surface_setup(struct vc4_exec_info *exec,
514                                     struct vc4_rcl_setup *setup,
515                                     struct drm_gem_cma_object **obj,
516                                     struct drm_vc4_submit_rcl_surface *surf)
517 {
518         uint8_t tiling = VC4_GET_FIELD(surf->bits,
519                                        VC4_RENDER_CONFIG_MEMORY_FORMAT);
520         uint8_t format = VC4_GET_FIELD(surf->bits,
521                                        VC4_RENDER_CONFIG_FORMAT);
522         int cpp;
523
524         if (surf->flags != 0) {
525                 DRM_ERROR("No flags supported on render config.\n");
526                 return -EINVAL;
527         }
528
529         if (surf->bits & ~(VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK |
530                            VC4_RENDER_CONFIG_FORMAT_MASK |
531                            VC4_RENDER_CONFIG_MS_MODE_4X |
532                            VC4_RENDER_CONFIG_DECIMATE_MODE_4X)) {
533                 DRM_ERROR("Unknown bits in render config: 0x%04x\n",
534                           surf->bits);
535                 return -EINVAL;
536         }
537
538         if (surf->hindex == ~0)
539                 return 0;
540
541         *obj = vc4_use_bo(exec, surf->hindex);
542         if (!*obj)
543                 return -EINVAL;
544
545         if (tiling > VC4_TILING_FORMAT_LT) {
546                 DRM_ERROR("Bad tiling format\n");
547                 return -EINVAL;
548         }
549
550         switch (format) {
551         case VC4_RENDER_CONFIG_FORMAT_BGR565_DITHERED:
552         case VC4_RENDER_CONFIG_FORMAT_BGR565:
553                 cpp = 2;
554                 break;
555         case VC4_RENDER_CONFIG_FORMAT_RGBA8888:
556                 cpp = 4;
557                 break;
558         default:
559                 DRM_ERROR("Bad tile buffer format\n");
560                 return -EINVAL;
561         }
562
563         if (!vc4_check_tex_size(exec, *obj, surf->offset, tiling,
564                                 exec->args->width, exec->args->height, cpp)) {
565                 return -EINVAL;
566         }
567
568         return 0;
569 }
570
571 int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec)
572 {
573         struct vc4_rcl_setup setup = {0};
574         struct drm_vc4_submit_cl *args = exec->args;
575         bool has_bin = args->bin_cl_size != 0;
576         int ret;
577
578         if (args->min_x_tile > args->max_x_tile ||
579             args->min_y_tile > args->max_y_tile) {
580                 DRM_ERROR("Bad render tile set (%d,%d)-(%d,%d)\n",
581                           args->min_x_tile, args->min_y_tile,
582                           args->max_x_tile, args->max_y_tile);
583                 return -EINVAL;
584         }
585
586         if (has_bin &&
587             (args->max_x_tile > exec->bin_tiles_x ||
588              args->max_y_tile > exec->bin_tiles_y)) {
589                 DRM_ERROR("Render tiles (%d,%d) outside of bin config "
590                           "(%d,%d)\n",
591                           args->max_x_tile, args->max_y_tile,
592                           exec->bin_tiles_x, exec->bin_tiles_y);
593                 return -EINVAL;
594         }
595
596         ret = vc4_rcl_render_config_surface_setup(exec, &setup,
597                                                   &setup.color_write,
598                                                   &args->color_write);
599         if (ret)
600                 return ret;
601
602         ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read);
603         if (ret)
604                 return ret;
605
606         ret = vc4_rcl_surface_setup(exec, &setup.zs_read, &args->zs_read);
607         if (ret)
608                 return ret;
609
610         ret = vc4_rcl_surface_setup(exec, &setup.zs_write, &args->zs_write);
611         if (ret)
612                 return ret;
613
614         ret = vc4_rcl_msaa_surface_setup(exec, &setup.msaa_color_write,
615                                          &args->msaa_color_write);
616         if (ret)
617                 return ret;
618
619         ret = vc4_rcl_msaa_surface_setup(exec, &setup.msaa_zs_write,
620                                          &args->msaa_zs_write);
621         if (ret)
622                 return ret;
623
624         /* We shouldn't even have the job submitted to us if there's no
625          * surface to write out.
626          */
627         if (!setup.color_write && !setup.zs_write &&
628             !setup.msaa_color_write && !setup.msaa_zs_write) {
629                 DRM_ERROR("RCL requires color or Z/S write\n");
630                 return -EINVAL;
631         }
632
633         return vc4_create_rcl_bo(dev, exec, &setup);
634 }