brintos

brintos / linux-shallow public Read only

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