17ec681f3Smrg/*
27ec681f3Smrg * Copyright (C) 2021 Collabora, Ltd.
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
97ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice (including the next
127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
137ec681f3Smrg * Software.
147ec681f3Smrg *
157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
207ec681f3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
217ec681f3Smrg * SOFTWARE.
227ec681f3Smrg *
237ec681f3Smrg * Authors:
247ec681f3Smrg *   Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
257ec681f3Smrg *   Boris Brezillon <boris.brezillon@collabora.com>
267ec681f3Smrg */
277ec681f3Smrg
287ec681f3Smrg#include "util/macros.h"
297ec681f3Smrg
307ec681f3Smrg#include "panfrost-quirks.h"
317ec681f3Smrg
327ec681f3Smrg#include "pan_cs.h"
337ec681f3Smrg#include "pan_encoder.h"
347ec681f3Smrg#include "pan_texture.h"
357ec681f3Smrg
367ec681f3Smrgstatic unsigned
377ec681f3Smrgmod_to_block_fmt(uint64_t mod)
387ec681f3Smrg{
397ec681f3Smrg        switch (mod) {
407ec681f3Smrg        case DRM_FORMAT_MOD_LINEAR:
417ec681f3Smrg                return MALI_BLOCK_FORMAT_LINEAR;
427ec681f3Smrg	case DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED:
437ec681f3Smrg                return MALI_BLOCK_FORMAT_TILED_U_INTERLEAVED;
447ec681f3Smrg        default:
457ec681f3Smrg#if PAN_ARCH >= 5
467ec681f3Smrg                if (drm_is_afbc(mod))
477ec681f3Smrg                        return MALI_BLOCK_FORMAT_AFBC;
487ec681f3Smrg#endif
497ec681f3Smrg
507ec681f3Smrg                unreachable("Unsupported modifer");
517ec681f3Smrg        }
527ec681f3Smrg}
537ec681f3Smrg
547ec681f3Smrgstatic enum mali_msaa
557ec681f3Smrgmali_sampling_mode(const struct pan_image_view *view)
567ec681f3Smrg{
577ec681f3Smrg        if (view->image->layout.nr_samples > 1) {
587ec681f3Smrg                assert(view->nr_samples == view->image->layout.nr_samples);
597ec681f3Smrg                assert(view->image->layout.slices[0].surface_stride != 0);
607ec681f3Smrg                return MALI_MSAA_LAYERED;
617ec681f3Smrg        }
627ec681f3Smrg
637ec681f3Smrg        if (view->nr_samples > view->image->layout.nr_samples) {
647ec681f3Smrg                assert(view->image->layout.nr_samples == 1);
657ec681f3Smrg                return MALI_MSAA_AVERAGE;
667ec681f3Smrg        }
677ec681f3Smrg
687ec681f3Smrg        assert(view->nr_samples == view->image->layout.nr_samples);
697ec681f3Smrg        assert(view->nr_samples == 1);
707ec681f3Smrg
717ec681f3Smrg        return MALI_MSAA_SINGLE;
727ec681f3Smrg}
737ec681f3Smrg
747ec681f3Smrgstatic inline enum mali_sample_pattern
757ec681f3Smrgpan_sample_pattern(unsigned samples)
767ec681f3Smrg{
777ec681f3Smrg        switch (samples) {
787ec681f3Smrg        case 1:  return MALI_SAMPLE_PATTERN_SINGLE_SAMPLED;
797ec681f3Smrg        case 4:  return MALI_SAMPLE_PATTERN_ROTATED_4X_GRID;
807ec681f3Smrg        case 8:  return MALI_SAMPLE_PATTERN_D3D_8X_GRID;
817ec681f3Smrg        case 16: return MALI_SAMPLE_PATTERN_D3D_16X_GRID;
827ec681f3Smrg        default: unreachable("Unsupported sample count");
837ec681f3Smrg        }
847ec681f3Smrg}
857ec681f3Smrg
867ec681f3Smrgint
877ec681f3SmrgGENX(pan_select_crc_rt)(const struct pan_fb_info *fb)
887ec681f3Smrg{
897ec681f3Smrg#if PAN_ARCH <= 6
907ec681f3Smrg        if (fb->rt_count == 1 && fb->rts[0].view && !fb->rts[0].discard &&
917ec681f3Smrg            fb->rts[0].view->image->layout.crc_mode != PAN_IMAGE_CRC_NONE)
927ec681f3Smrg                return 0;
937ec681f3Smrg
947ec681f3Smrg        return -1;
957ec681f3Smrg#else
967ec681f3Smrg        bool best_rt_valid = false;
977ec681f3Smrg        int best_rt = -1;
987ec681f3Smrg
997ec681f3Smrg        for (unsigned i = 0; i < fb->rt_count; i++) {
1007ec681f3Smrg		if (!fb->rts[i].view || fb->rts[0].discard ||
1017ec681f3Smrg                    fb->rts[i].view->image->layout.crc_mode == PAN_IMAGE_CRC_NONE)
1027ec681f3Smrg                        continue;
1037ec681f3Smrg
1047ec681f3Smrg                bool valid = *(fb->rts[i].crc_valid);
1057ec681f3Smrg                bool full = !fb->extent.minx && !fb->extent.miny &&
1067ec681f3Smrg                            fb->extent.maxx == (fb->width - 1) &&
1077ec681f3Smrg                            fb->extent.maxy == (fb->height - 1);
1087ec681f3Smrg                if (!full && !valid)
1097ec681f3Smrg                        continue;
1107ec681f3Smrg
1117ec681f3Smrg                if (best_rt < 0 || (valid && !best_rt_valid)) {
1127ec681f3Smrg                        best_rt = i;
1137ec681f3Smrg                        best_rt_valid = valid;
1147ec681f3Smrg                }
1157ec681f3Smrg
1167ec681f3Smrg                if (valid)
1177ec681f3Smrg                        break;
1187ec681f3Smrg        }
1197ec681f3Smrg
1207ec681f3Smrg        return best_rt;
1217ec681f3Smrg#endif
1227ec681f3Smrg}
1237ec681f3Smrg
1247ec681f3Smrgstatic enum mali_zs_format
1257ec681f3Smrgtranslate_zs_format(enum pipe_format in)
1267ec681f3Smrg{
1277ec681f3Smrg        switch (in) {
1287ec681f3Smrg        case PIPE_FORMAT_Z16_UNORM: return MALI_ZS_FORMAT_D16;
1297ec681f3Smrg        case PIPE_FORMAT_Z24_UNORM_S8_UINT: return MALI_ZS_FORMAT_D24S8;
1307ec681f3Smrg        case PIPE_FORMAT_Z24X8_UNORM: return MALI_ZS_FORMAT_D24X8;
1317ec681f3Smrg        case PIPE_FORMAT_Z32_FLOAT: return MALI_ZS_FORMAT_D32;
1327ec681f3Smrg        case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: return MALI_ZS_FORMAT_D32_S8X24;
1337ec681f3Smrg        default: unreachable("Unsupported depth/stencil format.");
1347ec681f3Smrg        }
1357ec681f3Smrg}
1367ec681f3Smrg
1377ec681f3Smrg#if PAN_ARCH >= 5
1387ec681f3Smrgstatic enum mali_s_format
1397ec681f3Smrgtranslate_s_format(enum pipe_format in)
1407ec681f3Smrg{
1417ec681f3Smrg        switch (in) {
1427ec681f3Smrg        case PIPE_FORMAT_S8_UINT: return MALI_S_FORMAT_S8;
1437ec681f3Smrg        case PIPE_FORMAT_S8_UINT_Z24_UNORM:
1447ec681f3Smrg        case PIPE_FORMAT_S8X24_UINT:
1457ec681f3Smrg                return MALI_S_FORMAT_S8X24;
1467ec681f3Smrg        case PIPE_FORMAT_Z24_UNORM_S8_UINT:
1477ec681f3Smrg        case PIPE_FORMAT_X24S8_UINT:
1487ec681f3Smrg                return MALI_S_FORMAT_X24S8;
1497ec681f3Smrg        case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
1507ec681f3Smrg                return MALI_S_FORMAT_X32_S8X24;
1517ec681f3Smrg        default:
1527ec681f3Smrg                unreachable("Unsupported stencil format.");
1537ec681f3Smrg        }
1547ec681f3Smrg}
1557ec681f3Smrg
1567ec681f3Smrgstatic void
1577ec681f3Smrgpan_prepare_s(const struct pan_fb_info *fb,
1587ec681f3Smrg              struct MALI_ZS_CRC_EXTENSION *ext)
1597ec681f3Smrg{
1607ec681f3Smrg        const struct pan_image_view *s = fb->zs.view.s;
1617ec681f3Smrg
1627ec681f3Smrg        if (!s)
1637ec681f3Smrg                return;
1647ec681f3Smrg
1657ec681f3Smrg        unsigned level = s->first_level;
1667ec681f3Smrg
1677ec681f3Smrg        ext->s_msaa = mali_sampling_mode(s);
1687ec681f3Smrg
1697ec681f3Smrg        struct pan_surface surf;
1707ec681f3Smrg        pan_iview_get_surface(s, 0, 0, 0, &surf);
1717ec681f3Smrg
1727ec681f3Smrg        assert(s->image->layout.modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED ||
1737ec681f3Smrg               s->image->layout.modifier == DRM_FORMAT_MOD_LINEAR);
1747ec681f3Smrg        ext->s_writeback_base = surf.data;
1757ec681f3Smrg        ext->s_writeback_row_stride = s->image->layout.slices[level].row_stride;
1767ec681f3Smrg        ext->s_writeback_surface_stride =
1777ec681f3Smrg                (s->image->layout.nr_samples > 1) ?
1787ec681f3Smrg                s->image->layout.slices[level].surface_stride : 0;
1797ec681f3Smrg        ext->s_block_format = mod_to_block_fmt(s->image->layout.modifier);
1807ec681f3Smrg        ext->s_write_format = translate_s_format(s->format);
1817ec681f3Smrg}
1827ec681f3Smrg
1837ec681f3Smrgstatic void
1847ec681f3Smrgpan_prepare_zs(const struct pan_fb_info *fb,
1857ec681f3Smrg               struct MALI_ZS_CRC_EXTENSION *ext)
1867ec681f3Smrg{
1877ec681f3Smrg        const struct pan_image_view *zs = fb->zs.view.zs;
1887ec681f3Smrg
1897ec681f3Smrg        if (!zs)
1907ec681f3Smrg                return;
1917ec681f3Smrg
1927ec681f3Smrg        unsigned level = zs->first_level;
1937ec681f3Smrg
1947ec681f3Smrg        ext->zs_msaa = mali_sampling_mode(zs);
1957ec681f3Smrg
1967ec681f3Smrg        struct pan_surface surf;
1977ec681f3Smrg        pan_iview_get_surface(zs, 0, 0, 0, &surf);
1987ec681f3Smrg
1997ec681f3Smrg        if (drm_is_afbc(zs->image->layout.modifier)) {
2007ec681f3Smrg#if PAN_ARCH >= 6
2017ec681f3Smrg                const struct pan_image_slice_layout *slice = &zs->image->layout.slices[level];
2027ec681f3Smrg
2037ec681f3Smrg                ext->zs_afbc_row_stride = slice->afbc.row_stride /
2047ec681f3Smrg                                          AFBC_HEADER_BYTES_PER_TILE;
2057ec681f3Smrg#else
2067ec681f3Smrg                ext->zs_block_format = MALI_BLOCK_FORMAT_AFBC;
2077ec681f3Smrg                ext->zs_afbc_body_size = 0x1000;
2087ec681f3Smrg                ext->zs_afbc_chunk_size = 9;
2097ec681f3Smrg                ext->zs_afbc_sparse = true;
2107ec681f3Smrg#endif
2117ec681f3Smrg
2127ec681f3Smrg                ext->zs_afbc_header = surf.afbc.header;
2137ec681f3Smrg                ext->zs_afbc_body = surf.afbc.body;
2147ec681f3Smrg        } else {
2157ec681f3Smrg                assert(zs->image->layout.modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED ||
2167ec681f3Smrg                       zs->image->layout.modifier == DRM_FORMAT_MOD_LINEAR);
2177ec681f3Smrg
2187ec681f3Smrg                /* TODO: Z32F(S8) support, which is always linear */
2197ec681f3Smrg
2207ec681f3Smrg                ext->zs_writeback_base = surf.data;
2217ec681f3Smrg                ext->zs_writeback_row_stride =
2227ec681f3Smrg                        zs->image->layout.slices[level].row_stride;
2237ec681f3Smrg                ext->zs_writeback_surface_stride =
2247ec681f3Smrg                        (zs->image->layout.nr_samples > 1) ?
2257ec681f3Smrg                        zs->image->layout.slices[level].surface_stride : 0;
2267ec681f3Smrg        }
2277ec681f3Smrg
2287ec681f3Smrg        ext->zs_block_format = mod_to_block_fmt(zs->image->layout.modifier);
2297ec681f3Smrg        ext->zs_write_format = translate_zs_format(zs->format);
2307ec681f3Smrg        if (ext->zs_write_format == MALI_ZS_FORMAT_D24S8)
2317ec681f3Smrg                ext->s_writeback_base = ext->zs_writeback_base;
2327ec681f3Smrg}
2337ec681f3Smrg
2347ec681f3Smrgstatic void
2357ec681f3Smrgpan_prepare_crc(const struct pan_fb_info *fb, int rt_crc,
2367ec681f3Smrg                struct MALI_ZS_CRC_EXTENSION *ext)
2377ec681f3Smrg{
2387ec681f3Smrg        if (rt_crc < 0)
2397ec681f3Smrg                return;
2407ec681f3Smrg
2417ec681f3Smrg        assert(rt_crc < fb->rt_count);
2427ec681f3Smrg
2437ec681f3Smrg        const struct pan_image_view *rt = fb->rts[rt_crc].view;
2447ec681f3Smrg        const struct pan_image_slice_layout *slice = &rt->image->layout.slices[rt->first_level];
2457ec681f3Smrg        ext->crc_base = (rt->image->layout.crc_mode == PAN_IMAGE_CRC_INBAND ?
2467ec681f3Smrg                         (rt->image->data.bo->ptr.gpu + rt->image->data.offset) :
2477ec681f3Smrg                         (rt->image->crc.bo->ptr.gpu + rt->image->crc.offset)) +
2487ec681f3Smrg                        slice->crc.offset;
2497ec681f3Smrg        ext->crc_row_stride = slice->crc.stride;
2507ec681f3Smrg
2517ec681f3Smrg#if PAN_ARCH >= 7
2527ec681f3Smrg        ext->crc_render_target = rt_crc;
2537ec681f3Smrg
2547ec681f3Smrg        if (fb->rts[rt_crc].clear) {
2557ec681f3Smrg                uint32_t clear_val = fb->rts[rt_crc].clear_value[0];
2567ec681f3Smrg                ext->crc_clear_color = clear_val | 0xc000000000000000 |
2577ec681f3Smrg                                       (((uint64_t)clear_val & 0xffff) << 32);
2587ec681f3Smrg        }
2597ec681f3Smrg#endif
2607ec681f3Smrg}
2617ec681f3Smrg
2627ec681f3Smrgstatic void
2637ec681f3Smrgpan_emit_zs_crc_ext(const struct pan_fb_info *fb, int rt_crc,
2647ec681f3Smrg                    void *zs_crc_ext)
2657ec681f3Smrg{
2667ec681f3Smrg        pan_pack(zs_crc_ext, ZS_CRC_EXTENSION, cfg) {
2677ec681f3Smrg                pan_prepare_crc(fb, rt_crc, &cfg);
2687ec681f3Smrg                cfg.zs_clean_pixel_write_enable = fb->zs.clear.z || fb->zs.clear.s;
2697ec681f3Smrg                pan_prepare_zs(fb, &cfg);
2707ec681f3Smrg                pan_prepare_s(fb, &cfg);
2717ec681f3Smrg        }
2727ec681f3Smrg}
2737ec681f3Smrg
2747ec681f3Smrg/* Measure format as it appears in the tile buffer */
2757ec681f3Smrg
2767ec681f3Smrgstatic unsigned
2777ec681f3Smrgpan_bytes_per_pixel_tib(enum pipe_format format)
2787ec681f3Smrg{
2797ec681f3Smrg        if (panfrost_blendable_formats_v7[format].internal) {
2807ec681f3Smrg                /* Blendable formats are always 32-bits in the tile buffer,
2817ec681f3Smrg                 * extra bits are used as padding or to dither */
2827ec681f3Smrg                return 4;
2837ec681f3Smrg        } else {
2847ec681f3Smrg                /* Non-blendable formats are raw, rounded up to the nearest
2857ec681f3Smrg                 * power-of-two size */
2867ec681f3Smrg                unsigned bytes = util_format_get_blocksize(format);
2877ec681f3Smrg                return util_next_power_of_two(bytes);
2887ec681f3Smrg        }
2897ec681f3Smrg}
2907ec681f3Smrg
2917ec681f3Smrgstatic unsigned
2927ec681f3Smrgpan_internal_cbuf_size(const struct pan_fb_info *fb,
2937ec681f3Smrg                       unsigned *tile_size)
2947ec681f3Smrg{
2957ec681f3Smrg        unsigned total_size = 0;
2967ec681f3Smrg
2977ec681f3Smrg        *tile_size = 16 * 16;
2987ec681f3Smrg        for (int cb = 0; cb < fb->rt_count; ++cb) {
2997ec681f3Smrg                const struct pan_image_view *rt = fb->rts[cb].view;
3007ec681f3Smrg
3017ec681f3Smrg                if (!rt)
3027ec681f3Smrg                        continue;
3037ec681f3Smrg
3047ec681f3Smrg                total_size += pan_bytes_per_pixel_tib(rt->format) *
3057ec681f3Smrg                              rt->nr_samples * (*tile_size);
3067ec681f3Smrg        }
3077ec681f3Smrg
3087ec681f3Smrg        /* We have a 4KB budget, let's reduce the tile size until it fits. */
3097ec681f3Smrg        while (total_size > 4096) {
3107ec681f3Smrg                total_size >>= 1;
3117ec681f3Smrg                *tile_size >>= 1;
3127ec681f3Smrg        }
3137ec681f3Smrg
3147ec681f3Smrg        /* Align on 1k. */
3157ec681f3Smrg        total_size = ALIGN_POT(total_size, 1024);
3167ec681f3Smrg
3177ec681f3Smrg        /* Minimum tile size is 4x4. */
3187ec681f3Smrg        assert(*tile_size >= 4 * 4);
3197ec681f3Smrg        return total_size;
3207ec681f3Smrg}
3217ec681f3Smrg
3227ec681f3Smrgstatic enum mali_color_format
3237ec681f3Smrgpan_mfbd_raw_format(unsigned bits)
3247ec681f3Smrg{
3257ec681f3Smrg        switch (bits) {
3267ec681f3Smrg        case    8: return MALI_COLOR_FORMAT_RAW8;
3277ec681f3Smrg        case   16: return MALI_COLOR_FORMAT_RAW16;
3287ec681f3Smrg        case   24: return MALI_COLOR_FORMAT_RAW24;
3297ec681f3Smrg        case   32: return MALI_COLOR_FORMAT_RAW32;
3307ec681f3Smrg        case   48: return MALI_COLOR_FORMAT_RAW48;
3317ec681f3Smrg        case   64: return MALI_COLOR_FORMAT_RAW64;
3327ec681f3Smrg        case   96: return MALI_COLOR_FORMAT_RAW96;
3337ec681f3Smrg        case  128: return MALI_COLOR_FORMAT_RAW128;
3347ec681f3Smrg        case  192: return MALI_COLOR_FORMAT_RAW192;
3357ec681f3Smrg        case  256: return MALI_COLOR_FORMAT_RAW256;
3367ec681f3Smrg        case  384: return MALI_COLOR_FORMAT_RAW384;
3377ec681f3Smrg        case  512: return MALI_COLOR_FORMAT_RAW512;
3387ec681f3Smrg        case  768: return MALI_COLOR_FORMAT_RAW768;
3397ec681f3Smrg        case 1024: return MALI_COLOR_FORMAT_RAW1024;
3407ec681f3Smrg        case 1536: return MALI_COLOR_FORMAT_RAW1536;
3417ec681f3Smrg        case 2048: return MALI_COLOR_FORMAT_RAW2048;
3427ec681f3Smrg        default: unreachable("invalid raw bpp");
3437ec681f3Smrg        }
3447ec681f3Smrg}
3457ec681f3Smrg
3467ec681f3Smrgstatic void
3477ec681f3Smrgpan_rt_init_format(const struct pan_image_view *rt,
3487ec681f3Smrg                   struct MALI_RENDER_TARGET *cfg)
3497ec681f3Smrg{
3507ec681f3Smrg        /* Explode details on the format */
3517ec681f3Smrg
3527ec681f3Smrg        const struct util_format_description *desc =
3537ec681f3Smrg                util_format_description(rt->format);
3547ec681f3Smrg
3557ec681f3Smrg        /* The swizzle for rendering is inverted from texturing */
3567ec681f3Smrg
3577ec681f3Smrg        unsigned char swizzle[4] = {
3587ec681f3Smrg                PIPE_SWIZZLE_X, PIPE_SWIZZLE_Y, PIPE_SWIZZLE_Z, PIPE_SWIZZLE_W,
3597ec681f3Smrg        };
3607ec681f3Smrg
3617ec681f3Smrg        /* Fill in accordingly, defaulting to 8-bit UNORM */
3627ec681f3Smrg
3637ec681f3Smrg        if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB)
3647ec681f3Smrg                cfg->srgb = true;
3657ec681f3Smrg
3667ec681f3Smrg        struct pan_blendable_format fmt = panfrost_blendable_formats_v7[rt->format];
3677ec681f3Smrg
3687ec681f3Smrg        if (fmt.internal) {
3697ec681f3Smrg                cfg->internal_format = fmt.internal;
3707ec681f3Smrg                cfg->writeback_format = fmt.writeback;
3717ec681f3Smrg                panfrost_invert_swizzle(desc->swizzle, swizzle);
3727ec681f3Smrg        } else {
3737ec681f3Smrg                /* Construct RAW internal/writeback, where internal is
3747ec681f3Smrg                 * specified logarithmically (round to next power-of-two).
3757ec681f3Smrg                 * Offset specified from RAW8, where 8 = 2^3 */
3767ec681f3Smrg
3777ec681f3Smrg                unsigned bits = desc->block.bits;
3787ec681f3Smrg                unsigned offset = util_logbase2_ceil(bits) - 3;
3797ec681f3Smrg                assert(offset <= 4);
3807ec681f3Smrg
3817ec681f3Smrg                cfg->internal_format =
3827ec681f3Smrg                        MALI_COLOR_BUFFER_INTERNAL_FORMAT_RAW8 + offset;
3837ec681f3Smrg
3847ec681f3Smrg                cfg->writeback_format = pan_mfbd_raw_format(bits);
3857ec681f3Smrg        }
3867ec681f3Smrg
3877ec681f3Smrg        cfg->swizzle = panfrost_translate_swizzle_4(swizzle);
3887ec681f3Smrg}
3897ec681f3Smrg
3907ec681f3Smrgstatic void
3917ec681f3Smrgpan_prepare_rt(const struct pan_fb_info *fb, unsigned idx,
3927ec681f3Smrg               unsigned cbuf_offset,
3937ec681f3Smrg               struct MALI_RENDER_TARGET *cfg)
3947ec681f3Smrg{
3957ec681f3Smrg        cfg->clean_pixel_write_enable = fb->rts[idx].clear;
3967ec681f3Smrg        cfg->internal_buffer_offset = cbuf_offset;
3977ec681f3Smrg        if (fb->rts[idx].clear) {
3987ec681f3Smrg                cfg->clear.color_0 = fb->rts[idx].clear_value[0];
3997ec681f3Smrg                cfg->clear.color_1 = fb->rts[idx].clear_value[1];
4007ec681f3Smrg                cfg->clear.color_2 = fb->rts[idx].clear_value[2];
4017ec681f3Smrg                cfg->clear.color_3 = fb->rts[idx].clear_value[3];
4027ec681f3Smrg        }
4037ec681f3Smrg
4047ec681f3Smrg        const struct pan_image_view *rt = fb->rts[idx].view;
4057ec681f3Smrg        if (!rt || fb->rts[idx].discard) {
4067ec681f3Smrg                cfg->internal_format = MALI_COLOR_BUFFER_INTERNAL_FORMAT_R8G8B8A8;
4077ec681f3Smrg                cfg->internal_buffer_offset = cbuf_offset;
4087ec681f3Smrg#if PAN_ARCH >= 7
4097ec681f3Smrg                cfg->writeback_block_format = MALI_BLOCK_FORMAT_TILED_U_INTERLEAVED;
4107ec681f3Smrg                cfg->dithering_enable = true;
4117ec681f3Smrg#endif
4127ec681f3Smrg                return;
4137ec681f3Smrg        }
4147ec681f3Smrg
4157ec681f3Smrg        cfg->write_enable = true;
4167ec681f3Smrg        cfg->dithering_enable = true;
4177ec681f3Smrg
4187ec681f3Smrg        unsigned level = rt->first_level;
4197ec681f3Smrg        assert(rt->last_level == rt->first_level);
4207ec681f3Smrg        assert(rt->last_layer == rt->first_layer);
4217ec681f3Smrg
4227ec681f3Smrg        int row_stride = rt->image->layout.slices[level].row_stride;
4237ec681f3Smrg
4247ec681f3Smrg        /* Only set layer_stride for layered MSAA rendering  */
4257ec681f3Smrg
4267ec681f3Smrg        unsigned layer_stride =
4277ec681f3Smrg                (rt->image->layout.nr_samples > 1) ?
4287ec681f3Smrg                        rt->image->layout.slices[level].surface_stride : 0;
4297ec681f3Smrg
4307ec681f3Smrg        cfg->writeback_msaa = mali_sampling_mode(rt);
4317ec681f3Smrg
4327ec681f3Smrg        pan_rt_init_format(rt, cfg);
4337ec681f3Smrg
4347ec681f3Smrg#if PAN_ARCH <= 5
4357ec681f3Smrg        cfg->writeback_block_format = mod_to_block_fmt(rt->image->layout.modifier);
4367ec681f3Smrg#else
4377ec681f3Smrg        cfg->writeback_block_format = mod_to_block_fmt(rt->image->layout.modifier);
4387ec681f3Smrg#endif
4397ec681f3Smrg
4407ec681f3Smrg        struct pan_surface surf;
4417ec681f3Smrg        pan_iview_get_surface(rt, 0, 0, 0, &surf);
4427ec681f3Smrg
4437ec681f3Smrg        if (drm_is_afbc(rt->image->layout.modifier)) {
4447ec681f3Smrg                const struct pan_image_slice_layout *slice = &rt->image->layout.slices[level];
4457ec681f3Smrg
4467ec681f3Smrg#if PAN_ARCH >= 6
4477ec681f3Smrg                cfg->afbc.row_stride = slice->afbc.row_stride /
4487ec681f3Smrg                                       AFBC_HEADER_BYTES_PER_TILE;
4497ec681f3Smrg                cfg->afbc.afbc_wide_block_enable =
4507ec681f3Smrg                        panfrost_block_dim(rt->image->layout.modifier, true, 0) > 16;
4517ec681f3Smrg#else
4527ec681f3Smrg                cfg->afbc.chunk_size = 9;
4537ec681f3Smrg                cfg->afbc.sparse = true;
4547ec681f3Smrg                cfg->afbc.body_size = slice->afbc.body_size;
4557ec681f3Smrg#endif
4567ec681f3Smrg
4577ec681f3Smrg                cfg->afbc.header = surf.afbc.header;
4587ec681f3Smrg                cfg->afbc.body = surf.afbc.body;
4597ec681f3Smrg
4607ec681f3Smrg                if (rt->image->layout.modifier & AFBC_FORMAT_MOD_YTR)
4617ec681f3Smrg                        cfg->afbc.yuv_transform_enable = true;
4627ec681f3Smrg        } else {
4637ec681f3Smrg                assert(rt->image->layout.modifier == DRM_FORMAT_MOD_LINEAR ||
4647ec681f3Smrg                       rt->image->layout.modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED);
4657ec681f3Smrg                cfg->rgb.base = surf.data;
4667ec681f3Smrg                cfg->rgb.row_stride = row_stride;
4677ec681f3Smrg                cfg->rgb.surface_stride = layer_stride;
4687ec681f3Smrg        }
4697ec681f3Smrg}
4707ec681f3Smrg#endif
4717ec681f3Smrg
4727ec681f3Smrgvoid
4737ec681f3SmrgGENX(pan_emit_tls)(const struct pan_tls_info *info,
4747ec681f3Smrg                   void *out)
4757ec681f3Smrg{
4767ec681f3Smrg        pan_pack(out, LOCAL_STORAGE, cfg) {
4777ec681f3Smrg                if (info->tls.size) {
4787ec681f3Smrg                        unsigned shift =
4797ec681f3Smrg                                panfrost_get_stack_shift(info->tls.size);
4807ec681f3Smrg
4817ec681f3Smrg                        cfg.tls_size = shift;
4827ec681f3Smrg                        cfg.tls_base_pointer = info->tls.ptr;
4837ec681f3Smrg                }
4847ec681f3Smrg
4857ec681f3Smrg                if (info->wls.size) {
4867ec681f3Smrg                        assert(!(info->wls.ptr & 4095));
4877ec681f3Smrg                        assert((info->wls.ptr & 0xffffffff00000000ULL) == ((info->wls.ptr + info->wls.size - 1) & 0xffffffff00000000ULL));
4887ec681f3Smrg                        cfg.wls_base_pointer = info->wls.ptr;
4897ec681f3Smrg                        unsigned wls_size = pan_wls_adjust_size(info->wls.size);
4907ec681f3Smrg                        cfg.wls_instances = pan_wls_instances(&info->wls.dim);
4917ec681f3Smrg                        cfg.wls_size_scale = util_logbase2(wls_size) + 1;
4927ec681f3Smrg                } else {
4937ec681f3Smrg                        cfg.wls_instances = MALI_LOCAL_STORAGE_NO_WORKGROUP_MEM;
4947ec681f3Smrg                }
4957ec681f3Smrg        }
4967ec681f3Smrg}
4977ec681f3Smrg
4987ec681f3Smrg#if PAN_ARCH <= 5
4997ec681f3Smrgstatic void
5007ec681f3Smrgpan_emit_midgard_tiler(const struct panfrost_device *dev,
5017ec681f3Smrg                       const struct pan_fb_info *fb,
5027ec681f3Smrg                       const struct pan_tiler_context *tiler_ctx,
5037ec681f3Smrg                       void *out)
5047ec681f3Smrg{
5057ec681f3Smrg        bool hierarchy = !(dev->quirks & MIDGARD_NO_HIER_TILING);
5067ec681f3Smrg
5077ec681f3Smrg        assert(tiler_ctx->midgard.polygon_list->ptr.gpu);
5087ec681f3Smrg
5097ec681f3Smrg        pan_pack(out, TILER_CONTEXT, cfg) {
5107ec681f3Smrg                unsigned header_size;
5117ec681f3Smrg
5127ec681f3Smrg                if (tiler_ctx->midgard.disable) {
5137ec681f3Smrg                        cfg.hierarchy_mask =
5147ec681f3Smrg                                hierarchy ?
5157ec681f3Smrg                                MALI_MIDGARD_TILER_DISABLED :
5167ec681f3Smrg                                MALI_MIDGARD_TILER_USER;
5177ec681f3Smrg                        header_size = MALI_MIDGARD_TILER_MINIMUM_HEADER_SIZE;
5187ec681f3Smrg                        cfg.polygon_list_size = header_size + (hierarchy ? 0 : 4);
5197ec681f3Smrg                        cfg.heap_start = tiler_ctx->midgard.polygon_list->ptr.gpu;
5207ec681f3Smrg                        cfg.heap_end = tiler_ctx->midgard.polygon_list->ptr.gpu;
5217ec681f3Smrg		} else {
5227ec681f3Smrg                        cfg.hierarchy_mask =
5237ec681f3Smrg                                panfrost_choose_hierarchy_mask(fb->width,
5247ec681f3Smrg                                                               fb->height,
5257ec681f3Smrg                                                               1, hierarchy);
5267ec681f3Smrg                        header_size = panfrost_tiler_header_size(fb->width,
5277ec681f3Smrg                                                                 fb->height,
5287ec681f3Smrg                                                                 cfg.hierarchy_mask,
5297ec681f3Smrg                                                                 hierarchy);
5307ec681f3Smrg                        cfg.polygon_list_size =
5317ec681f3Smrg                                panfrost_tiler_full_size(fb->width, fb->height,
5327ec681f3Smrg                                                         cfg.hierarchy_mask,
5337ec681f3Smrg                                                         hierarchy);
5347ec681f3Smrg                        cfg.heap_start = dev->tiler_heap->ptr.gpu;
5357ec681f3Smrg                        cfg.heap_end = dev->tiler_heap->ptr.gpu + dev->tiler_heap->size;
5367ec681f3Smrg                }
5377ec681f3Smrg
5387ec681f3Smrg                cfg.polygon_list = tiler_ctx->midgard.polygon_list->ptr.gpu;
5397ec681f3Smrg                cfg.polygon_list_body = cfg.polygon_list + header_size;
5407ec681f3Smrg        }
5417ec681f3Smrg}
5427ec681f3Smrg#endif
5437ec681f3Smrg
5447ec681f3Smrg#if PAN_ARCH >= 5
5457ec681f3Smrgstatic void
5467ec681f3Smrgpan_emit_rt(const struct pan_fb_info *fb,
5477ec681f3Smrg            unsigned idx, unsigned cbuf_offset, void *out)
5487ec681f3Smrg{
5497ec681f3Smrg        pan_pack(out, RENDER_TARGET, cfg) {
5507ec681f3Smrg                pan_prepare_rt(fb, idx, cbuf_offset, &cfg);
5517ec681f3Smrg        }
5527ec681f3Smrg}
5537ec681f3Smrg
5547ec681f3Smrg#if PAN_ARCH >= 6
5557ec681f3Smrg/* All Bifrost and Valhall GPUs are affected by issue TSIX-2033:
5567ec681f3Smrg *
5577ec681f3Smrg *      Forcing clean_tile_writes breaks INTERSECT readbacks
5587ec681f3Smrg *
5597ec681f3Smrg * To workaround, use the frame shader mode ALWAYS instead of INTERSECT if
5607ec681f3Smrg * clean tile writes is forced. Since INTERSECT is a hint that the hardware may
5617ec681f3Smrg * ignore, this cannot affect correctness, only performance */
5627ec681f3Smrg
5637ec681f3Smrgstatic enum mali_pre_post_frame_shader_mode
5647ec681f3Smrgpan_fix_frame_shader_mode(enum mali_pre_post_frame_shader_mode mode, bool force_clean_tile)
5657ec681f3Smrg{
5667ec681f3Smrg        if (force_clean_tile && mode == MALI_PRE_POST_FRAME_SHADER_MODE_INTERSECT)
5677ec681f3Smrg                return MALI_PRE_POST_FRAME_SHADER_MODE_ALWAYS;
5687ec681f3Smrg        else
5697ec681f3Smrg                return mode;
5707ec681f3Smrg}
5717ec681f3Smrg
5727ec681f3Smrg/* Regardless of clean_tile_write_enable, the hardware writes clean tiles if
5737ec681f3Smrg * the effective tile size differs from the superblock size of any enabled AFBC
5747ec681f3Smrg * render target. Check this condition. */
5757ec681f3Smrg
5767ec681f3Smrgstatic bool
5777ec681f3Smrgpan_force_clean_write_rt(const struct pan_image_view *rt, unsigned tile_size)
5787ec681f3Smrg{
5797ec681f3Smrg        if (!drm_is_afbc(rt->image->layout.modifier))
5807ec681f3Smrg                return false;
5817ec681f3Smrg
5827ec681f3Smrg        unsigned superblock = panfrost_block_dim(rt->image->layout.modifier, true, 0);
5837ec681f3Smrg
5847ec681f3Smrg        assert(superblock >= 16);
5857ec681f3Smrg        assert(tile_size <= 16*16);
5867ec681f3Smrg
5877ec681f3Smrg        /* Tile size and superblock differ unless they are both 16x16 */
5887ec681f3Smrg        return !(superblock == 16 && tile_size == 16*16);
5897ec681f3Smrg}
5907ec681f3Smrg
5917ec681f3Smrgstatic bool
5927ec681f3Smrgpan_force_clean_write(const struct pan_fb_info *fb, unsigned tile_size)
5937ec681f3Smrg{
5947ec681f3Smrg        /* Maximum tile size */
5957ec681f3Smrg        assert(tile_size <= 16*16);
5967ec681f3Smrg
5977ec681f3Smrg        for (unsigned i = 0; i < fb->rt_count; ++i) {
5987ec681f3Smrg                if (fb->rts[i].view && !fb->rts[i].discard &&
5997ec681f3Smrg                    pan_force_clean_write_rt(fb->rts[i].view, tile_size))
6007ec681f3Smrg                        return true;
6017ec681f3Smrg        }
6027ec681f3Smrg
6037ec681f3Smrg        if (fb->zs.view.zs && !fb->zs.discard.z &&
6047ec681f3Smrg            pan_force_clean_write_rt(fb->zs.view.zs, tile_size))
6057ec681f3Smrg                return true;
6067ec681f3Smrg
6077ec681f3Smrg        if (fb->zs.view.s && !fb->zs.discard.s &&
6087ec681f3Smrg            pan_force_clean_write_rt(fb->zs.view.s, tile_size))
6097ec681f3Smrg                return true;
6107ec681f3Smrg
6117ec681f3Smrg        return false;
6127ec681f3Smrg}
6137ec681f3Smrg
6147ec681f3Smrg#endif
6157ec681f3Smrg
6167ec681f3Smrgstatic unsigned
6177ec681f3Smrgpan_emit_mfbd(const struct panfrost_device *dev,
6187ec681f3Smrg              const struct pan_fb_info *fb,
6197ec681f3Smrg              const struct pan_tls_info *tls,
6207ec681f3Smrg              const struct pan_tiler_context *tiler_ctx,
6217ec681f3Smrg              void *out)
6227ec681f3Smrg{
6237ec681f3Smrg        unsigned tags = MALI_FBD_TAG_IS_MFBD;
6247ec681f3Smrg        void *fbd = out;
6257ec681f3Smrg        void *rtd = out + pan_size(FRAMEBUFFER);
6267ec681f3Smrg
6277ec681f3Smrg#if PAN_ARCH <= 5
6287ec681f3Smrg        GENX(pan_emit_tls)(tls,
6297ec681f3Smrg                           pan_section_ptr(fbd, FRAMEBUFFER, LOCAL_STORAGE));
6307ec681f3Smrg#endif
6317ec681f3Smrg
6327ec681f3Smrg        unsigned tile_size;
6337ec681f3Smrg        unsigned internal_cbuf_size = pan_internal_cbuf_size(fb, &tile_size);
6347ec681f3Smrg        int crc_rt = GENX(pan_select_crc_rt)(fb);
6357ec681f3Smrg        bool has_zs_crc_ext = pan_fbd_has_zs_crc_ext(fb);
6367ec681f3Smrg
6377ec681f3Smrg        pan_section_pack(fbd, FRAMEBUFFER, PARAMETERS, cfg) {
6387ec681f3Smrg#if PAN_ARCH >= 6
6397ec681f3Smrg                bool force_clean_write = pan_force_clean_write(fb, tile_size);
6407ec681f3Smrg
6417ec681f3Smrg                cfg.sample_locations =
6427ec681f3Smrg                        panfrost_sample_positions(dev, pan_sample_pattern(fb->nr_samples));
6437ec681f3Smrg                cfg.pre_frame_0 = pan_fix_frame_shader_mode(fb->bifrost.pre_post.modes[0], force_clean_write);
6447ec681f3Smrg                cfg.pre_frame_1 = pan_fix_frame_shader_mode(fb->bifrost.pre_post.modes[1], force_clean_write);
6457ec681f3Smrg                cfg.post_frame  = pan_fix_frame_shader_mode(fb->bifrost.pre_post.modes[2], force_clean_write);
6467ec681f3Smrg                cfg.frame_shader_dcds = fb->bifrost.pre_post.dcds.gpu;
6477ec681f3Smrg                cfg.tiler = tiler_ctx->bifrost;
6487ec681f3Smrg#endif
6497ec681f3Smrg                cfg.width = fb->width;
6507ec681f3Smrg                cfg.height = fb->height;
6517ec681f3Smrg                cfg.bound_max_x = fb->width - 1;
6527ec681f3Smrg                cfg.bound_max_y = fb->height - 1;
6537ec681f3Smrg
6547ec681f3Smrg                cfg.effective_tile_size = tile_size;
6557ec681f3Smrg                cfg.tie_break_rule = MALI_TIE_BREAK_RULE_MINUS_180_IN_0_OUT;
6567ec681f3Smrg                cfg.render_target_count = MAX2(fb->rt_count, 1);
6577ec681f3Smrg
6587ec681f3Smrg                /* Default to 24 bit depth if there's no surface. */
6597ec681f3Smrg                cfg.z_internal_format =
6607ec681f3Smrg                        fb->zs.view.zs ?
6617ec681f3Smrg                        panfrost_get_z_internal_format(fb->zs.view.zs->format) :
6627ec681f3Smrg                        MALI_Z_INTERNAL_FORMAT_D24;
6637ec681f3Smrg
6647ec681f3Smrg                cfg.z_clear = fb->zs.clear_value.depth;
6657ec681f3Smrg                cfg.s_clear = fb->zs.clear_value.stencil;
6667ec681f3Smrg                cfg.color_buffer_allocation = internal_cbuf_size;
6677ec681f3Smrg                cfg.sample_count = fb->nr_samples;
6687ec681f3Smrg                cfg.sample_pattern = pan_sample_pattern(fb->nr_samples);
6697ec681f3Smrg                cfg.z_write_enable = (fb->zs.view.zs && !fb->zs.discard.z);
6707ec681f3Smrg                cfg.s_write_enable = (fb->zs.view.s && !fb->zs.discard.s);
6717ec681f3Smrg                cfg.has_zs_crc_extension = has_zs_crc_ext;
6727ec681f3Smrg
6737ec681f3Smrg                if (crc_rt >= 0) {
6747ec681f3Smrg                        bool *valid = fb->rts[crc_rt].crc_valid;
6757ec681f3Smrg                        bool full = !fb->extent.minx && !fb->extent.miny &&
6767ec681f3Smrg                                    fb->extent.maxx == (fb->width - 1) &&
6777ec681f3Smrg                                    fb->extent.maxy == (fb->height - 1);
6787ec681f3Smrg
6797ec681f3Smrg                        cfg.crc_read_enable = *valid;
6807ec681f3Smrg
6817ec681f3Smrg                        /* If the data is currently invalid, still write CRC
6827ec681f3Smrg                         * data if we are doing a full write, so that it is
6837ec681f3Smrg                         * valid for next time. */
6847ec681f3Smrg                        cfg.crc_write_enable = *valid || full;
6857ec681f3Smrg
6867ec681f3Smrg                        *valid |= full;
6877ec681f3Smrg                }
6887ec681f3Smrg        }
6897ec681f3Smrg
6907ec681f3Smrg#if PAN_ARCH >= 6
6917ec681f3Smrg        pan_section_pack(fbd, FRAMEBUFFER, PADDING, padding);
6927ec681f3Smrg#else
6937ec681f3Smrg        pan_emit_midgard_tiler(dev, fb, tiler_ctx,
6947ec681f3Smrg                               pan_section_ptr(fbd, FRAMEBUFFER, TILER));
6957ec681f3Smrg
6967ec681f3Smrg        /* All weights set to 0, nothing to do here */
6977ec681f3Smrg        pan_section_pack(fbd, FRAMEBUFFER, TILER_WEIGHTS, w);
6987ec681f3Smrg#endif
6997ec681f3Smrg
7007ec681f3Smrg        if (has_zs_crc_ext) {
7017ec681f3Smrg                pan_emit_zs_crc_ext(fb, crc_rt,
7027ec681f3Smrg                                    out + pan_size(FRAMEBUFFER));
7037ec681f3Smrg                rtd += pan_size(ZS_CRC_EXTENSION);
7047ec681f3Smrg                tags |= MALI_FBD_TAG_HAS_ZS_RT;
7057ec681f3Smrg        }
7067ec681f3Smrg
7077ec681f3Smrg        unsigned rt_count = MAX2(fb->rt_count, 1);
7087ec681f3Smrg        unsigned cbuf_offset = 0;
7097ec681f3Smrg        for (unsigned i = 0; i < rt_count; i++) {
7107ec681f3Smrg                pan_emit_rt(fb, i, cbuf_offset, rtd);
7117ec681f3Smrg                rtd += pan_size(RENDER_TARGET);
7127ec681f3Smrg                if (!fb->rts[i].view)
7137ec681f3Smrg                        continue;
7147ec681f3Smrg
7157ec681f3Smrg                cbuf_offset += pan_bytes_per_pixel_tib(fb->rts[i].view->format) *
7167ec681f3Smrg                               tile_size * fb->rts[i].view->image->layout.nr_samples;
7177ec681f3Smrg
7187ec681f3Smrg                if (i != crc_rt)
7197ec681f3Smrg                        *(fb->rts[i].crc_valid) = false;
7207ec681f3Smrg        }
7217ec681f3Smrg        tags |= MALI_POSITIVE(MAX2(fb->rt_count, 1)) << 2;
7227ec681f3Smrg
7237ec681f3Smrg        return tags;
7247ec681f3Smrg}
7257ec681f3Smrg#else /* PAN_ARCH == 4 */
7267ec681f3Smrgstatic void
7277ec681f3Smrgpan_emit_sfbd_tiler(const struct panfrost_device *dev,
7287ec681f3Smrg                    const struct pan_fb_info *fb,
7297ec681f3Smrg                    const struct pan_tiler_context *ctx,
7307ec681f3Smrg                    void *fbd)
7317ec681f3Smrg{
7327ec681f3Smrg       pan_emit_midgard_tiler(dev, fb, ctx,
7337ec681f3Smrg                              pan_section_ptr(fbd, FRAMEBUFFER, TILER));
7347ec681f3Smrg
7357ec681f3Smrg        /* All weights set to 0, nothing to do here */
7367ec681f3Smrg        pan_section_pack(fbd, FRAMEBUFFER, PADDING_1, padding);
7377ec681f3Smrg        pan_section_pack(fbd, FRAMEBUFFER, TILER_WEIGHTS, w);
7387ec681f3Smrg}
7397ec681f3Smrg
7407ec681f3Smrgstatic void
7417ec681f3Smrgpan_emit_sfbd(const struct panfrost_device *dev,
7427ec681f3Smrg              const struct pan_fb_info *fb,
7437ec681f3Smrg              const struct pan_tls_info *tls,
7447ec681f3Smrg              const struct pan_tiler_context *tiler_ctx,
7457ec681f3Smrg              void *fbd)
7467ec681f3Smrg{
7477ec681f3Smrg        GENX(pan_emit_tls)(tls,
7487ec681f3Smrg                           pan_section_ptr(fbd, FRAMEBUFFER,
7497ec681f3Smrg                                           LOCAL_STORAGE));
7507ec681f3Smrg        pan_section_pack(fbd, FRAMEBUFFER, PARAMETERS, cfg) {
7517ec681f3Smrg                cfg.bound_max_x = fb->width - 1;
7527ec681f3Smrg                cfg.bound_max_y = fb->height - 1;
7537ec681f3Smrg                cfg.dithering_enable = true;
7547ec681f3Smrg                cfg.clean_pixel_write_enable = true;
7557ec681f3Smrg                cfg.tie_break_rule = MALI_TIE_BREAK_RULE_MINUS_180_IN_0_OUT;
7567ec681f3Smrg                if (fb->rts[0].clear) {
7577ec681f3Smrg                        cfg.clear_color_0 = fb->rts[0].clear_value[0];
7587ec681f3Smrg                        cfg.clear_color_1 = fb->rts[0].clear_value[1];
7597ec681f3Smrg                        cfg.clear_color_2 = fb->rts[0].clear_value[2];
7607ec681f3Smrg                        cfg.clear_color_3 = fb->rts[0].clear_value[3];
7617ec681f3Smrg                }
7627ec681f3Smrg
7637ec681f3Smrg                if (fb->zs.clear.z)
7647ec681f3Smrg                        cfg.z_clear = fb->zs.clear_value.depth;
7657ec681f3Smrg
7667ec681f3Smrg                if (fb->zs.clear.s)
7677ec681f3Smrg                        cfg.s_clear = fb->zs.clear_value.stencil;
7687ec681f3Smrg
7697ec681f3Smrg                if (fb->rt_count && fb->rts[0].view) {
7707ec681f3Smrg                        const struct pan_image_view *rt = fb->rts[0].view;
7717ec681f3Smrg
7727ec681f3Smrg                        const struct util_format_description *desc =
7737ec681f3Smrg                                util_format_description(rt->format);
7747ec681f3Smrg
7757ec681f3Smrg                        /* The swizzle for rendering is inverted from texturing */
7767ec681f3Smrg                        unsigned char swizzle[4];
7777ec681f3Smrg                        panfrost_invert_swizzle(desc->swizzle, swizzle);
7787ec681f3Smrg                        cfg.swizzle = panfrost_translate_swizzle_4(swizzle);
7797ec681f3Smrg
7807ec681f3Smrg                        struct pan_blendable_format fmt = panfrost_blendable_formats_v7[rt->format];
7817ec681f3Smrg                        if (fmt.internal) {
7827ec681f3Smrg                                cfg.internal_format = fmt.internal;
7837ec681f3Smrg                                cfg.color_writeback_format = fmt.writeback;
7847ec681f3Smrg                        } else {
7857ec681f3Smrg                                unreachable("raw formats not finished for SFBD");
7867ec681f3Smrg                        }
7877ec681f3Smrg
7887ec681f3Smrg                        unsigned level = rt->first_level;
7897ec681f3Smrg                        struct pan_surface surf;
7907ec681f3Smrg
7917ec681f3Smrg                        pan_iview_get_surface(rt, 0, 0, 0, &surf);
7927ec681f3Smrg
7937ec681f3Smrg                        cfg.color_write_enable = !fb->rts[0].discard;
7947ec681f3Smrg                        cfg.color_writeback.base = surf.data;
7957ec681f3Smrg                        cfg.color_writeback.row_stride =
7967ec681f3Smrg	                        rt->image->layout.slices[level].row_stride;
7977ec681f3Smrg
7987ec681f3Smrg                        cfg.color_block_format = mod_to_block_fmt(rt->image->layout.modifier);
7997ec681f3Smrg                        assert(cfg.color_block_format == MALI_BLOCK_FORMAT_LINEAR ||
8007ec681f3Smrg                               cfg.color_block_format == MALI_BLOCK_FORMAT_TILED_U_INTERLEAVED);
8017ec681f3Smrg
8027ec681f3Smrg                        if (rt->image->layout.crc_mode != PAN_IMAGE_CRC_NONE) {
8037ec681f3Smrg                                const struct pan_image_slice_layout *slice =
8047ec681f3Smrg                                        &rt->image->layout.slices[level];
8057ec681f3Smrg
8067ec681f3Smrg                                cfg.crc_buffer.row_stride = slice->crc.stride;
8077ec681f3Smrg                                if (rt->image->layout.crc_mode == PAN_IMAGE_CRC_INBAND) {
8087ec681f3Smrg                                        cfg.crc_buffer.base = rt->image->data.bo->ptr.gpu +
8097ec681f3Smrg                                                              rt->image->data.offset +
8107ec681f3Smrg                                                              slice->crc.offset;
8117ec681f3Smrg                                } else {
8127ec681f3Smrg                                        cfg.crc_buffer.base = rt->image->crc.bo->ptr.gpu +
8137ec681f3Smrg                                                              rt->image->crc.offset +
8147ec681f3Smrg                                                              slice->crc.offset;
8157ec681f3Smrg                                }
8167ec681f3Smrg                        }
8177ec681f3Smrg                }
8187ec681f3Smrg
8197ec681f3Smrg                if (fb->zs.view.zs) {
8207ec681f3Smrg                        const struct pan_image_view *zs = fb->zs.view.zs;
8217ec681f3Smrg                        unsigned level = zs->first_level;
8227ec681f3Smrg                        struct pan_surface surf;
8237ec681f3Smrg
8247ec681f3Smrg                        pan_iview_get_surface(zs, 0, 0, 0, &surf);
8257ec681f3Smrg
8267ec681f3Smrg                        cfg.zs_write_enable = !fb->zs.discard.z;
8277ec681f3Smrg                        cfg.zs_writeback.base = surf.data;
8287ec681f3Smrg                        cfg.zs_writeback.row_stride =
8297ec681f3Smrg                                zs->image->layout.slices[level].row_stride;
8307ec681f3Smrg                        cfg.zs_block_format = mod_to_block_fmt(zs->image->layout.modifier);
8317ec681f3Smrg                        assert(cfg.zs_block_format == MALI_BLOCK_FORMAT_LINEAR ||
8327ec681f3Smrg                               cfg.zs_block_format == MALI_BLOCK_FORMAT_TILED_U_INTERLEAVED);
8337ec681f3Smrg
8347ec681f3Smrg                        cfg.zs_format = translate_zs_format(zs->format);
8357ec681f3Smrg                }
8367ec681f3Smrg
8377ec681f3Smrg                cfg.sample_count = fb->nr_samples;
8387ec681f3Smrg
8397ec681f3Smrg                if (fb->rt_count)
8407ec681f3Smrg                        cfg.msaa = mali_sampling_mode(fb->rts[0].view);
8417ec681f3Smrg        }
8427ec681f3Smrg        pan_emit_sfbd_tiler(dev, fb, tiler_ctx, fbd);
8437ec681f3Smrg        pan_section_pack(fbd, FRAMEBUFFER, PADDING_2, padding);
8447ec681f3Smrg}
8457ec681f3Smrg#endif
8467ec681f3Smrg
8477ec681f3Smrgunsigned
8487ec681f3SmrgGENX(pan_emit_fbd)(const struct panfrost_device *dev,
8497ec681f3Smrg                   const struct pan_fb_info *fb,
8507ec681f3Smrg                   const struct pan_tls_info *tls,
8517ec681f3Smrg                   const struct pan_tiler_context *tiler_ctx,
8527ec681f3Smrg                   void *out)
8537ec681f3Smrg{
8547ec681f3Smrg#if PAN_ARCH == 4
8557ec681f3Smrg        assert(fb->rt_count <= 1);
8567ec681f3Smrg        pan_emit_sfbd(dev, fb, tls, tiler_ctx, out);
8577ec681f3Smrg        return 0;
8587ec681f3Smrg#else
8597ec681f3Smrg        return pan_emit_mfbd(dev, fb, tls, tiler_ctx, out);
8607ec681f3Smrg#endif
8617ec681f3Smrg}
8627ec681f3Smrg
8637ec681f3Smrg#if PAN_ARCH >= 6
8647ec681f3Smrgvoid
8657ec681f3SmrgGENX(pan_emit_tiler_heap)(const struct panfrost_device *dev,
8667ec681f3Smrg                          void *out)
8677ec681f3Smrg{
8687ec681f3Smrg        pan_pack(out, TILER_HEAP, heap) {
8697ec681f3Smrg                heap.size = dev->tiler_heap->size;
8707ec681f3Smrg                heap.base = dev->tiler_heap->ptr.gpu;
8717ec681f3Smrg                heap.bottom = dev->tiler_heap->ptr.gpu;
8727ec681f3Smrg                heap.top = dev->tiler_heap->ptr.gpu + dev->tiler_heap->size;
8737ec681f3Smrg        }
8747ec681f3Smrg}
8757ec681f3Smrg
8767ec681f3Smrgvoid
8777ec681f3SmrgGENX(pan_emit_tiler_ctx)(const struct panfrost_device *dev,
8787ec681f3Smrg                         unsigned fb_width, unsigned fb_height,
8797ec681f3Smrg                         unsigned nr_samples,
8807ec681f3Smrg                         mali_ptr heap,
8817ec681f3Smrg                         void *out)
8827ec681f3Smrg{
8837ec681f3Smrg        unsigned max_levels = dev->tiler_features.max_levels;
8847ec681f3Smrg        assert(max_levels >= 2);
8857ec681f3Smrg
8867ec681f3Smrg        pan_pack(out, TILER_CONTEXT, tiler) {
8877ec681f3Smrg                /* TODO: Select hierarchy mask more effectively */
8887ec681f3Smrg                tiler.hierarchy_mask = (max_levels >= 8) ? 0xFF : 0x28;
8897ec681f3Smrg                tiler.fb_width = fb_width;
8907ec681f3Smrg                tiler.fb_height = fb_height;
8917ec681f3Smrg                tiler.heap = heap;
8927ec681f3Smrg                tiler.sample_pattern = pan_sample_pattern(nr_samples);
8937ec681f3Smrg        }
8947ec681f3Smrg}
8957ec681f3Smrg#endif
8967ec681f3Smrg
8977ec681f3Smrgvoid
8987ec681f3SmrgGENX(pan_emit_fragment_job)(const struct pan_fb_info *fb,
8997ec681f3Smrg                            mali_ptr fbd,
9007ec681f3Smrg                            void *out)
9017ec681f3Smrg{
9027ec681f3Smrg        pan_section_pack(out, FRAGMENT_JOB, HEADER, header) {
9037ec681f3Smrg                header.type = MALI_JOB_TYPE_FRAGMENT;
9047ec681f3Smrg                header.index = 1;
9057ec681f3Smrg        }
9067ec681f3Smrg
9077ec681f3Smrg        pan_section_pack(out, FRAGMENT_JOB, PAYLOAD, payload) {
9087ec681f3Smrg                payload.bound_min_x = fb->extent.minx >> MALI_TILE_SHIFT;
9097ec681f3Smrg                payload.bound_min_y = fb->extent.miny >> MALI_TILE_SHIFT;
9107ec681f3Smrg                payload.bound_max_x = fb->extent.maxx >> MALI_TILE_SHIFT;
9117ec681f3Smrg                payload.bound_max_y = fb->extent.maxy >> MALI_TILE_SHIFT;
9127ec681f3Smrg                payload.framebuffer = fbd;
9137ec681f3Smrg
9147ec681f3Smrg#if PAN_ARCH >= 5
9157ec681f3Smrg                if (fb->tile_map.base) {
9167ec681f3Smrg                        payload.has_tile_enable_map = true;
9177ec681f3Smrg                        payload.tile_enable_map = fb->tile_map.base;
9187ec681f3Smrg                        payload.tile_enable_map_row_stride = fb->tile_map.stride;
9197ec681f3Smrg                }
9207ec681f3Smrg#endif
9217ec681f3Smrg        }
9227ec681f3Smrg}
923