1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2021 Intel Corporation 4 */ 5 6 #include <linux/dma-fence.h> 7 #include <linux/dma-resv.h> 8 9 #include <drm/drm_blend.h> 10 #include <drm/drm_gem.h> 11 #include <drm/drm_modeset_helper.h> 12 #include <drm/drm_print.h> 13 14 #include "intel_bo.h" 15 #include "intel_display.h" 16 #include "intel_display_core.h" 17 #include "intel_display_types.h" 18 #include "intel_display_utils.h" 19 #include "intel_fb.h" 20 #include "intel_frontbuffer.h" 21 #include "intel_parent.h" 22 #include "intel_plane.h" 23 24 #define check_array_bounds(display, a, i) drm_WARN_ON((display)->drm, (i) >= ARRAY_SIZE(a)) 25 26 /* 27 * From the Sky Lake PRM: 28 * "The Color Control Surface (CCS) contains the compression status of 29 * the cache-line pairs. The compression state of the cache-line pair 30 * is specified by 2 bits in the CCS. Each CCS cache-line represents 31 * an area on the main surface of 16 x16 sets of 128 byte Y-tiled 32 * cache-line-pairs. CCS is always Y tiled." 33 * 34 * Since cache line pairs refers to horizontally adjacent cache lines, 35 * each cache line in the CCS corresponds to an area of 32x16 cache 36 * lines on the main surface. Since each pixel is 4 bytes, this gives 37 * us a ratio of one byte in the CCS for each 8x16 pixels in the 38 * main surface. 39 */ 40 static const struct drm_format_info skl_ccs_formats[] = { 41 { .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 2, 42 .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, }, 43 { .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 2, 44 .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, }, 45 { .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 2, 46 .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, .has_alpha = true, }, 47 { .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 2, 48 .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, .has_alpha = true, }, 49 { .format = DRM_FORMAT_XRGB2101010, .depth = 30, .num_planes = 2, 50 .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, }, 51 { .format = DRM_FORMAT_XBGR2101010, .depth = 30, .num_planes = 2, 52 .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, }, 53 { .format = DRM_FORMAT_ARGB2101010, .depth = 30, .num_planes = 2, 54 .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, .has_alpha = true, }, 55 { .format = DRM_FORMAT_ABGR2101010, .depth = 30, .num_planes = 2, 56 .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, .has_alpha = true, }, 57 }; 58 59 /* 60 * Gen-12 compression uses 4 bits of CCS data for each cache line pair in the 61 * main surface. And each 64B CCS cache line represents an area of 4x1 Y-tiles 62 * in the main surface. With 4 byte pixels and each Y-tile having dimensions of 63 * 32x32 pixels, the ratio turns out to 1B in the CCS for every 2x32 pixels in 64 * the main surface. 65 */ 66 static const struct drm_format_info gen12_ccs_formats[] = { 67 { .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 2, 68 .char_per_block = { 4, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 }, 69 .hsub = 1, .vsub = 1, }, 70 { .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 2, 71 .char_per_block = { 4, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 }, 72 .hsub = 1, .vsub = 1, }, 73 { .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 2, 74 .char_per_block = { 4, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 }, 75 .hsub = 1, .vsub = 1, .has_alpha = true }, 76 { .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 2, 77 .char_per_block = { 4, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 }, 78 .hsub = 1, .vsub = 1, .has_alpha = true }, 79 { .format = DRM_FORMAT_XRGB2101010, .depth = 30, .num_planes = 2, 80 .char_per_block = { 4, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 }, 81 .hsub = 1, .vsub = 1, }, 82 { .format = DRM_FORMAT_XBGR2101010, .depth = 30, .num_planes = 2, 83 .char_per_block = { 4, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 }, 84 .hsub = 1, .vsub = 1, }, 85 { .format = DRM_FORMAT_ARGB2101010, .depth = 30, .num_planes = 2, 86 .char_per_block = { 4, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 }, 87 .hsub = 1, .vsub = 1, .has_alpha = true }, 88 { .format = DRM_FORMAT_ABGR2101010, .depth = 30, .num_planes = 2, 89 .char_per_block = { 4, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 }, 90 .hsub = 1, .vsub = 1, .has_alpha = true }, 91 { .format = DRM_FORMAT_XRGB16161616F, .depth = 0, .num_planes = 2, 92 .char_per_block = { 8, 1 }, .block_w = { 1, 1 }, .block_h = { 1, 1 }, 93 .hsub = 1, .vsub = 1, }, 94 { .format = DRM_FORMAT_XBGR16161616F, .depth = 0, .num_planes = 2, 95 .char_per_block = { 8, 1 }, .block_w = { 1, 1 }, .block_h = { 1, 1 }, 96 .hsub = 1, .vsub = 1, }, 97 { .format = DRM_FORMAT_ARGB16161616F, .depth = 0, .num_planes = 2, 98 .char_per_block = { 8, 1 }, .block_w = { 1, 1 }, .block_h = { 1, 1 }, 99 .hsub = 1, .vsub = 1, .has_alpha = true }, 100 { .format = DRM_FORMAT_ABGR16161616F, .depth = 0, .num_planes = 2, 101 .char_per_block = { 8, 1 }, .block_w = { 1, 1 }, .block_h = { 1, 1 }, 102 .hsub = 1, .vsub = 1, .has_alpha = true }, 103 { .format = DRM_FORMAT_YUYV, .num_planes = 2, 104 .char_per_block = { 2, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 }, 105 .hsub = 2, .vsub = 1, .is_yuv = true }, 106 { .format = DRM_FORMAT_YVYU, .num_planes = 2, 107 .char_per_block = { 2, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 }, 108 .hsub = 2, .vsub = 1, .is_yuv = true }, 109 { .format = DRM_FORMAT_UYVY, .num_planes = 2, 110 .char_per_block = { 2, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 }, 111 .hsub = 2, .vsub = 1, .is_yuv = true }, 112 { .format = DRM_FORMAT_VYUY, .num_planes = 2, 113 .char_per_block = { 2, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 }, 114 .hsub = 2, .vsub = 1, .is_yuv = true }, 115 { .format = DRM_FORMAT_XYUV8888, .num_planes = 2, 116 .char_per_block = { 4, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 }, 117 .hsub = 1, .vsub = 1, .is_yuv = true }, 118 { .format = DRM_FORMAT_NV12, .num_planes = 4, 119 .char_per_block = { 1, 2, 1, 1 }, .block_w = { 1, 1, 4, 4 }, .block_h = { 1, 1, 1, 1 }, 120 .hsub = 2, .vsub = 2, .is_yuv = true }, 121 { .format = DRM_FORMAT_P010, .num_planes = 4, 122 .char_per_block = { 2, 4, 1, 1 }, .block_w = { 1, 1, 2, 2 }, .block_h = { 1, 1, 1, 1 }, 123 .hsub = 2, .vsub = 2, .is_yuv = true }, 124 { .format = DRM_FORMAT_P012, .num_planes = 4, 125 .char_per_block = { 2, 4, 1, 1 }, .block_w = { 1, 1, 2, 2 }, .block_h = { 1, 1, 1, 1 }, 126 .hsub = 2, .vsub = 2, .is_yuv = true }, 127 { .format = DRM_FORMAT_P016, .num_planes = 4, 128 .char_per_block = { 2, 4, 1, 1 }, .block_w = { 1, 1, 2, 2 }, .block_h = { 1, 1, 1, 1 }, 129 .hsub = 2, .vsub = 2, .is_yuv = true }, 130 }; 131 132 /* 133 * Same as gen12_ccs_formats[] above, but with additional surface used 134 * to pass Clear Color information in plane 2 with 64 bits of data. 135 */ 136 static const struct drm_format_info gen12_ccs_cc_formats[] = { 137 { .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 3, 138 .char_per_block = { 4, 1, 0 }, .block_w = { 1, 2, 0 }, .block_h = { 1, 1, 0 }, 139 .hsub = 1, .vsub = 1, }, 140 { .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 3, 141 .char_per_block = { 4, 1, 0 }, .block_w = { 1, 2, 0 }, .block_h = { 1, 1, 0 }, 142 .hsub = 1, .vsub = 1, }, 143 { .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 3, 144 .char_per_block = { 4, 1, 0 }, .block_w = { 1, 2, 0 }, .block_h = { 1, 1, 0 }, 145 .hsub = 1, .vsub = 1, .has_alpha = true }, 146 { .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 3, 147 .char_per_block = { 4, 1, 0 }, .block_w = { 1, 2, 0 }, .block_h = { 1, 1, 0 }, 148 .hsub = 1, .vsub = 1, .has_alpha = true }, 149 { .format = DRM_FORMAT_XRGB2101010, .depth = 30, .num_planes = 3, 150 .char_per_block = { 4, 1, 0 }, .block_w = { 1, 2, 0 }, .block_h = { 1, 1, 0 }, 151 .hsub = 1, .vsub = 1, }, 152 { .format = DRM_FORMAT_XBGR2101010, .depth = 30, .num_planes = 3, 153 .char_per_block = { 4, 1, 0 }, .block_w = { 1, 2, 0 }, .block_h = { 1, 1, 0 }, 154 .hsub = 1, .vsub = 1, }, 155 { .format = DRM_FORMAT_ARGB2101010, .depth = 30, .num_planes = 3, 156 .char_per_block = { 4, 1, 0 }, .block_w = { 1, 2, 0 }, .block_h = { 1, 1, 0 }, 157 .hsub = 1, .vsub = 1, .has_alpha = true }, 158 { .format = DRM_FORMAT_ABGR2101010, .depth = 30, .num_planes = 3, 159 .char_per_block = { 4, 1, 0 }, .block_w = { 1, 2, 0 }, .block_h = { 1, 1, 0 }, 160 .hsub = 1, .vsub = 1, .has_alpha = true }, 161 { .format = DRM_FORMAT_XRGB16161616F, .depth = 0, .num_planes = 3, 162 .char_per_block = { 8, 1, 0 }, .block_w = { 1, 1, 0 }, .block_h = { 1, 1, 0 }, 163 .hsub = 1, .vsub = 1, }, 164 { .format = DRM_FORMAT_XBGR16161616F, .depth = 0, .num_planes = 3, 165 .char_per_block = { 8, 1, 0 }, .block_w = { 1, 1, 0 }, .block_h = { 1, 1, 0 }, 166 .hsub = 1, .vsub = 1, }, 167 { .format = DRM_FORMAT_ARGB16161616F, .depth = 0, .num_planes = 3, 168 .char_per_block = { 8, 1, 0 }, .block_w = { 1, 1, 0 }, .block_h = { 1, 1, 0 }, 169 .hsub = 1, .vsub = 1, .has_alpha = true }, 170 { .format = DRM_FORMAT_ABGR16161616F, .depth = 0, .num_planes = 3, 171 .char_per_block = { 8, 1, 0 }, .block_w = { 1, 1, 0 }, .block_h = { 1, 1, 0 }, 172 .hsub = 1, .vsub = 1, .has_alpha = true }, 173 }; 174 175 static const struct drm_format_info gen12_flat_ccs_cc_formats[] = { 176 { .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 2, 177 .char_per_block = { 4, 0 }, .block_w = { 1, 0 }, .block_h = { 1, 0 }, 178 .hsub = 1, .vsub = 1, }, 179 { .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 2, 180 .char_per_block = { 4, 0 }, .block_w = { 1, 0 }, .block_h = { 1, 0 }, 181 .hsub = 1, .vsub = 1, }, 182 { .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 2, 183 .char_per_block = { 4, 0 }, .block_w = { 1, 0 }, .block_h = { 1, 0 }, 184 .hsub = 1, .vsub = 1, .has_alpha = true }, 185 { .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 2, 186 .char_per_block = { 4, 0 }, .block_w = { 1, 0 }, .block_h = { 1, 0 }, 187 .hsub = 1, .vsub = 1, .has_alpha = true }, 188 { .format = DRM_FORMAT_XRGB2101010, .depth = 30, .num_planes = 2, 189 .char_per_block = { 4, 0 }, .block_w = { 1, 0 }, .block_h = { 1, 0 }, 190 .hsub = 1, .vsub = 1, }, 191 { .format = DRM_FORMAT_XBGR2101010, .depth = 30, .num_planes = 2, 192 .char_per_block = { 4, 0 }, .block_w = { 1, 0 }, .block_h = { 1, 0 }, 193 .hsub = 1, .vsub = 1, }, 194 { .format = DRM_FORMAT_ARGB2101010, .depth = 30, .num_planes = 2, 195 .char_per_block = { 4, 0 }, .block_w = { 1, 0 }, .block_h = { 1, 0 }, 196 .hsub = 1, .vsub = 1, .has_alpha = true }, 197 { .format = DRM_FORMAT_ABGR2101010, .depth = 30, .num_planes = 2, 198 .char_per_block = { 4, 0 }, .block_w = { 1, 0 }, .block_h = { 1, 0 }, 199 .hsub = 1, .vsub = 1, .has_alpha = true }, 200 { .format = DRM_FORMAT_XRGB16161616F, .depth = 0, .num_planes = 2, 201 .char_per_block = { 8, 0 }, .block_w = { 1, 0 }, .block_h = { 1, 0 }, 202 .hsub = 1, .vsub = 1, }, 203 { .format = DRM_FORMAT_XBGR16161616F, .depth = 0, .num_planes = 2, 204 .char_per_block = { 8, 0 }, .block_w = { 1, 0 }, .block_h = { 1, 0 }, 205 .hsub = 1, .vsub = 1, }, 206 { .format = DRM_FORMAT_ARGB16161616F, .depth = 0, .num_planes = 2, 207 .char_per_block = { 8, 0 }, .block_w = { 1, 0 }, .block_h = { 1, 0 }, 208 .hsub = 1, .vsub = 1, .has_alpha = true }, 209 { .format = DRM_FORMAT_ABGR16161616F, .depth = 0, .num_planes = 2, 210 .char_per_block = { 8, 0 }, .block_w = { 1, 0 }, .block_h = { 1, 0 }, 211 .hsub = 1, .vsub = 1, .has_alpha = true }, 212 }; 213 214 struct intel_modifier_desc { 215 u64 modifier; 216 struct { 217 u8 from; 218 u8 until; 219 } display_ver; 220 #define DISPLAY_VER_ALL { 0, -1 } 221 222 const struct drm_format_info *formats; 223 int format_count; 224 #define FORMAT_OVERRIDE(format_list) \ 225 .formats = format_list, \ 226 .format_count = ARRAY_SIZE(format_list) 227 228 u8 plane_caps; 229 230 struct { 231 u8 cc_planes:3; 232 u8 packed_aux_planes:4; 233 u8 planar_aux_planes:4; 234 } ccs; 235 }; 236 237 #define INTEL_PLANE_CAP_CCS_MASK (INTEL_PLANE_CAP_CCS_RC | \ 238 INTEL_PLANE_CAP_CCS_RC_CC | \ 239 INTEL_PLANE_CAP_CCS_MC) 240 #define INTEL_PLANE_CAP_TILING_MASK (INTEL_PLANE_CAP_TILING_X | \ 241 INTEL_PLANE_CAP_TILING_Y | \ 242 INTEL_PLANE_CAP_TILING_Yf | \ 243 INTEL_PLANE_CAP_TILING_4) 244 #define INTEL_PLANE_CAP_TILING_NONE 0 245 246 static const struct intel_modifier_desc intel_modifiers[] = { 247 { 248 .modifier = I915_FORMAT_MOD_4_TILED_LNL_CCS, 249 .display_ver = { 20, -1 }, 250 .plane_caps = INTEL_PLANE_CAP_TILING_4, 251 }, { 252 .modifier = I915_FORMAT_MOD_4_TILED_BMG_CCS, 253 .display_ver = { 14, -1 }, 254 .plane_caps = INTEL_PLANE_CAP_TILING_4 | INTEL_PLANE_CAP_NEED64K_PHYS, 255 }, { 256 .modifier = I915_FORMAT_MOD_4_TILED_MTL_MC_CCS, 257 .display_ver = { 14, 14 }, 258 .plane_caps = INTEL_PLANE_CAP_TILING_4 | INTEL_PLANE_CAP_CCS_MC, 259 260 .ccs.packed_aux_planes = BIT(1), 261 .ccs.planar_aux_planes = BIT(2) | BIT(3), 262 263 FORMAT_OVERRIDE(gen12_ccs_formats), 264 }, { 265 .modifier = I915_FORMAT_MOD_4_TILED_MTL_RC_CCS, 266 .display_ver = { 14, 14 }, 267 .plane_caps = INTEL_PLANE_CAP_TILING_4 | INTEL_PLANE_CAP_CCS_RC, 268 269 .ccs.packed_aux_planes = BIT(1), 270 271 FORMAT_OVERRIDE(gen12_ccs_formats), 272 }, { 273 .modifier = I915_FORMAT_MOD_4_TILED_MTL_RC_CCS_CC, 274 .display_ver = { 14, 14 }, 275 .plane_caps = INTEL_PLANE_CAP_TILING_4 | INTEL_PLANE_CAP_CCS_RC_CC, 276 277 .ccs.cc_planes = BIT(2), 278 .ccs.packed_aux_planes = BIT(1), 279 280 FORMAT_OVERRIDE(gen12_ccs_cc_formats), 281 }, { 282 .modifier = I915_FORMAT_MOD_4_TILED_DG2_MC_CCS, 283 .display_ver = { 13, 13 }, 284 .plane_caps = INTEL_PLANE_CAP_TILING_4 | INTEL_PLANE_CAP_CCS_MC, 285 }, { 286 .modifier = I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC, 287 .display_ver = { 13, 13 }, 288 .plane_caps = INTEL_PLANE_CAP_TILING_4 | INTEL_PLANE_CAP_CCS_RC_CC, 289 290 .ccs.cc_planes = BIT(1), 291 292 FORMAT_OVERRIDE(gen12_flat_ccs_cc_formats), 293 }, { 294 .modifier = I915_FORMAT_MOD_4_TILED_DG2_RC_CCS, 295 .display_ver = { 13, 13 }, 296 .plane_caps = INTEL_PLANE_CAP_TILING_4 | INTEL_PLANE_CAP_CCS_RC, 297 }, { 298 .modifier = I915_FORMAT_MOD_4_TILED, 299 .display_ver = { 13, -1 }, 300 .plane_caps = INTEL_PLANE_CAP_TILING_4, 301 }, { 302 .modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS, 303 .display_ver = { 12, 13 }, 304 .plane_caps = INTEL_PLANE_CAP_TILING_Y | INTEL_PLANE_CAP_CCS_MC, 305 306 .ccs.packed_aux_planes = BIT(1), 307 .ccs.planar_aux_planes = BIT(2) | BIT(3), 308 309 FORMAT_OVERRIDE(gen12_ccs_formats), 310 }, { 311 .modifier = I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS, 312 .display_ver = { 12, 13 }, 313 .plane_caps = INTEL_PLANE_CAP_TILING_Y | INTEL_PLANE_CAP_CCS_RC, 314 315 .ccs.packed_aux_planes = BIT(1), 316 317 FORMAT_OVERRIDE(gen12_ccs_formats), 318 }, { 319 .modifier = I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC, 320 .display_ver = { 12, 13 }, 321 .plane_caps = INTEL_PLANE_CAP_TILING_Y | INTEL_PLANE_CAP_CCS_RC_CC, 322 323 .ccs.cc_planes = BIT(2), 324 .ccs.packed_aux_planes = BIT(1), 325 326 FORMAT_OVERRIDE(gen12_ccs_cc_formats), 327 }, { 328 .modifier = I915_FORMAT_MOD_Yf_TILED_CCS, 329 .display_ver = { 9, 11 }, 330 .plane_caps = INTEL_PLANE_CAP_TILING_Yf | INTEL_PLANE_CAP_CCS_RC, 331 332 .ccs.packed_aux_planes = BIT(1), 333 334 FORMAT_OVERRIDE(skl_ccs_formats), 335 }, { 336 .modifier = I915_FORMAT_MOD_Y_TILED_CCS, 337 .display_ver = { 9, 11 }, 338 .plane_caps = INTEL_PLANE_CAP_TILING_Y | INTEL_PLANE_CAP_CCS_RC, 339 340 .ccs.packed_aux_planes = BIT(1), 341 342 FORMAT_OVERRIDE(skl_ccs_formats), 343 }, { 344 .modifier = I915_FORMAT_MOD_Yf_TILED, 345 .display_ver = { 9, 11 }, 346 .plane_caps = INTEL_PLANE_CAP_TILING_Yf, 347 }, { 348 .modifier = I915_FORMAT_MOD_Y_TILED, 349 .display_ver = { 9, 13 }, 350 .plane_caps = INTEL_PLANE_CAP_TILING_Y, 351 }, { 352 .modifier = I915_FORMAT_MOD_X_TILED, 353 .display_ver = { 0, 29 }, 354 .plane_caps = INTEL_PLANE_CAP_TILING_X, 355 }, { 356 .modifier = DRM_FORMAT_MOD_LINEAR, 357 .display_ver = DISPLAY_VER_ALL, 358 }, 359 }; 360 361 static const struct intel_modifier_desc *lookup_modifier_or_null(u64 modifier) 362 { 363 int i; 364 365 for (i = 0; i < ARRAY_SIZE(intel_modifiers); i++) 366 if (intel_modifiers[i].modifier == modifier) 367 return &intel_modifiers[i]; 368 369 return NULL; 370 } 371 372 static const struct intel_modifier_desc *lookup_modifier(u64 modifier) 373 { 374 const struct intel_modifier_desc *md = lookup_modifier_or_null(modifier); 375 376 if (WARN_ON(!md)) 377 return &intel_modifiers[0]; 378 379 return md; 380 } 381 382 static const struct drm_format_info * 383 lookup_format_info(const struct drm_format_info formats[], 384 int num_formats, u32 format) 385 { 386 int i; 387 388 for (i = 0; i < num_formats; i++) { 389 if (formats[i].format == format) 390 return &formats[i]; 391 } 392 393 return NULL; 394 } 395 396 unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier) 397 { 398 const struct intel_modifier_desc *md; 399 u8 tiling_caps; 400 401 md = lookup_modifier_or_null(fb_modifier); 402 if (!md) 403 return I915_TILING_NONE; 404 405 tiling_caps = lookup_modifier_or_null(fb_modifier)->plane_caps & 406 INTEL_PLANE_CAP_TILING_MASK; 407 408 switch (tiling_caps) { 409 case INTEL_PLANE_CAP_TILING_Y: 410 return I915_TILING_Y; 411 case INTEL_PLANE_CAP_TILING_X: 412 return I915_TILING_X; 413 case INTEL_PLANE_CAP_TILING_4: 414 case INTEL_PLANE_CAP_TILING_Yf: 415 case INTEL_PLANE_CAP_TILING_NONE: 416 return I915_TILING_NONE; 417 default: 418 MISSING_CASE(tiling_caps); 419 return I915_TILING_NONE; 420 } 421 } 422 423 /** 424 * intel_fb_get_format_info: Get a modifier specific format information 425 * @pixel_format: pixel format 426 * @modifier: modifier 427 * 428 * Returns: 429 * Returns the format information for @pixel_format specific to @modifier, 430 * or %NULL if the modifier doesn't override the format. 431 */ 432 const struct drm_format_info * 433 intel_fb_get_format_info(u32 pixel_format, u64 modifier) 434 { 435 const struct intel_modifier_desc *md = lookup_modifier_or_null(modifier); 436 437 if (!md || !md->formats) 438 return NULL; 439 440 return lookup_format_info(md->formats, md->format_count, pixel_format); 441 } 442 443 static bool plane_caps_contain_any(u8 caps, u8 mask) 444 { 445 return caps & mask; 446 } 447 448 static bool plane_caps_contain_all(u8 caps, u8 mask) 449 { 450 return (caps & mask) == mask; 451 } 452 453 /** 454 * intel_fb_is_tiled_modifier: Check if a modifier is a tiled modifier type 455 * @modifier: Modifier to check 456 * 457 * Returns: 458 * Returns %true if @modifier is a tiled modifier. 459 */ 460 bool intel_fb_is_tiled_modifier(u64 modifier) 461 { 462 return plane_caps_contain_any(lookup_modifier(modifier)->plane_caps, 463 INTEL_PLANE_CAP_TILING_MASK); 464 } 465 466 /** 467 * intel_fb_is_ccs_modifier: Check if a modifier is a CCS modifier type 468 * @modifier: Modifier to check 469 * 470 * Returns: 471 * Returns %true if @modifier is a render, render with color clear or 472 * media compression modifier. 473 */ 474 bool intel_fb_is_ccs_modifier(u64 modifier) 475 { 476 return plane_caps_contain_any(lookup_modifier(modifier)->plane_caps, 477 INTEL_PLANE_CAP_CCS_MASK); 478 } 479 480 /** 481 * intel_fb_is_rc_ccs_cc_modifier: Check if a modifier is an RC CCS CC modifier type 482 * @modifier: Modifier to check 483 * 484 * Returns: 485 * Returns %true if @modifier is a render with color clear modifier. 486 */ 487 bool intel_fb_is_rc_ccs_cc_modifier(u64 modifier) 488 { 489 return plane_caps_contain_any(lookup_modifier(modifier)->plane_caps, 490 INTEL_PLANE_CAP_CCS_RC_CC); 491 } 492 493 /** 494 * intel_fb_is_mc_ccs_modifier: Check if a modifier is an MC CCS modifier type 495 * @modifier: Modifier to check 496 * 497 * Returns: 498 * Returns %true if @modifier is a media compression modifier. 499 */ 500 bool intel_fb_is_mc_ccs_modifier(u64 modifier) 501 { 502 return plane_caps_contain_any(lookup_modifier(modifier)->plane_caps, 503 INTEL_PLANE_CAP_CCS_MC); 504 } 505 506 /** 507 * intel_fb_needs_64k_phys: Check if modifier requires 64k physical placement. 508 * @modifier: Modifier to check 509 * 510 * Returns: 511 * Returns %true if @modifier requires 64k aligned physical pages. 512 */ 513 bool intel_fb_needs_64k_phys(u64 modifier) 514 { 515 const struct intel_modifier_desc *md = lookup_modifier_or_null(modifier); 516 517 if (!md) 518 return false; 519 520 return plane_caps_contain_any(md->plane_caps, 521 INTEL_PLANE_CAP_NEED64K_PHYS); 522 } 523 524 /** 525 * intel_fb_is_tile4_modifier: Check if a modifier is a tile4 modifier type 526 * @modifier: Modifier to check 527 * 528 * Returns: 529 * Returns %true if @modifier is a tile4 modifier. 530 */ 531 bool intel_fb_is_tile4_modifier(u64 modifier) 532 { 533 return plane_caps_contain_any(lookup_modifier(modifier)->plane_caps, 534 INTEL_PLANE_CAP_TILING_4); 535 } 536 537 static bool check_modifier_display_ver_range(const struct intel_modifier_desc *md, 538 u8 display_ver_from, u8 display_ver_until) 539 { 540 return md->display_ver.from <= display_ver_until && 541 display_ver_from <= md->display_ver.until; 542 } 543 544 static bool plane_has_modifier(struct intel_display *display, 545 u8 plane_caps, 546 const struct intel_modifier_desc *md) 547 { 548 if (!IS_DISPLAY_VER(display, md->display_ver.from, md->display_ver.until)) 549 return false; 550 551 if (!plane_caps_contain_all(plane_caps, md->plane_caps)) 552 return false; 553 554 /* 555 * Separate AuxCCS and Flat CCS modifiers to be run only on platforms 556 * where supported. 557 */ 558 if (intel_fb_is_ccs_modifier(md->modifier) && 559 intel_parent_has_auxccs(display) != !!md->ccs.packed_aux_planes) 560 return false; 561 562 if (md->modifier == I915_FORMAT_MOD_4_TILED_BMG_CCS && 563 (DISPLAY_VER(display) < 14 || !display->platform.dgfx)) 564 return false; 565 566 if (md->modifier == I915_FORMAT_MOD_4_TILED_LNL_CCS && 567 (DISPLAY_VER(display) < 20 || display->platform.dgfx)) 568 return false; 569 570 return true; 571 } 572 573 /** 574 * intel_fb_plane_get_modifiers: Get the modifiers for the given platform and plane capabilities 575 * @display: display instance 576 * @plane_caps: capabilities for the plane the modifiers are queried for 577 * 578 * Returns: 579 * Returns the list of modifiers allowed by the @display platform and @plane_caps. 580 * The caller must free the returned buffer. 581 */ 582 u64 *intel_fb_plane_get_modifiers(struct intel_display *display, 583 u8 plane_caps) 584 { 585 u64 *list, *p; 586 int count = 1; /* +1 for invalid modifier terminator */ 587 int i; 588 589 for (i = 0; i < ARRAY_SIZE(intel_modifiers); i++) { 590 if (plane_has_modifier(display, plane_caps, &intel_modifiers[i])) 591 count++; 592 } 593 594 list = kmalloc_array(count, sizeof(*list), GFP_KERNEL); 595 if (drm_WARN_ON(display->drm, !list)) 596 return NULL; 597 598 p = list; 599 for (i = 0; i < ARRAY_SIZE(intel_modifiers); i++) { 600 if (plane_has_modifier(display, plane_caps, &intel_modifiers[i])) 601 *p++ = intel_modifiers[i].modifier; 602 } 603 *p++ = DRM_FORMAT_MOD_INVALID; 604 605 return list; 606 } 607 608 /** 609 * intel_fb_plane_supports_modifier: Determine if a modifier is supported by the given plane 610 * @plane: Plane to check the modifier support for 611 * @modifier: The modifier to check the support for 612 * 613 * Returns: 614 * %true if the @modifier is supported on @plane. 615 */ 616 bool intel_fb_plane_supports_modifier(struct intel_plane *plane, u64 modifier) 617 { 618 int i; 619 620 for (i = 0; i < plane->base.modifier_count; i++) 621 if (plane->base.modifiers[i] == modifier) 622 return true; 623 624 return false; 625 } 626 627 static bool format_is_yuv_semiplanar(const struct intel_modifier_desc *md, 628 const struct drm_format_info *info) 629 { 630 if (!info->is_yuv) 631 return false; 632 633 if (hweight8(md->ccs.planar_aux_planes) == 2) 634 return info->num_planes == 4; 635 else 636 return info->num_planes == 2; 637 } 638 639 /** 640 * intel_format_info_is_yuv_semiplanar: Check if the given format is YUV semiplanar 641 * @info: format to check 642 * @modifier: modifier used with the format 643 * 644 * Returns: 645 * %true if @info / @modifier is YUV semiplanar. 646 */ 647 bool intel_format_info_is_yuv_semiplanar(const struct drm_format_info *info, 648 u64 modifier) 649 { 650 return format_is_yuv_semiplanar(lookup_modifier(modifier), info); 651 } 652 653 static u8 ccs_aux_plane_mask(const struct intel_modifier_desc *md, 654 const struct drm_format_info *format) 655 { 656 if (format_is_yuv_semiplanar(md, format)) 657 return md->ccs.planar_aux_planes; 658 else 659 return md->ccs.packed_aux_planes; 660 } 661 662 /** 663 * intel_fb_is_ccs_aux_plane: Check if a framebuffer color plane is a CCS AUX plane 664 * @fb: Framebuffer 665 * @color_plane: color plane index to check 666 * 667 * Returns: 668 * Returns %true if @fb's color plane at index @color_plane is a CCS AUX plane. 669 */ 670 bool intel_fb_is_ccs_aux_plane(const struct drm_framebuffer *fb, int color_plane) 671 { 672 const struct intel_modifier_desc *md = lookup_modifier(fb->modifier); 673 674 return ccs_aux_plane_mask(md, fb->format) & BIT(color_plane); 675 } 676 677 /** 678 * intel_fb_is_gen12_ccs_aux_plane: Check if a framebuffer color plane is a GEN12 CCS AUX plane 679 * @fb: Framebuffer 680 * @color_plane: color plane index to check 681 * 682 * Returns: 683 * Returns %true if @fb's color plane at index @color_plane is a GEN12 CCS AUX plane. 684 */ 685 static bool intel_fb_is_gen12_ccs_aux_plane(const struct drm_framebuffer *fb, int color_plane) 686 { 687 const struct intel_modifier_desc *md = lookup_modifier(fb->modifier); 688 689 return check_modifier_display_ver_range(md, 12, 14) && 690 ccs_aux_plane_mask(md, fb->format) & BIT(color_plane); 691 } 692 693 /** 694 * intel_fb_rc_ccs_cc_plane: Get the CCS CC color plane index for a framebuffer 695 * @fb: Framebuffer 696 * 697 * Returns: 698 * Returns the index of the color clear plane for @fb, or -1 if @fb is not a 699 * framebuffer using a render compression/color clear modifier. 700 */ 701 int intel_fb_rc_ccs_cc_plane(const struct drm_framebuffer *fb) 702 { 703 const struct intel_modifier_desc *md = lookup_modifier(fb->modifier); 704 705 if (!md->ccs.cc_planes) 706 return -1; 707 708 drm_WARN_ON_ONCE(fb->dev, hweight8(md->ccs.cc_planes) > 1); 709 710 return ilog2((int)md->ccs.cc_planes); 711 } 712 713 static bool is_gen12_ccs_cc_plane(const struct drm_framebuffer *fb, int color_plane) 714 { 715 return intel_fb_rc_ccs_cc_plane(fb) == color_plane; 716 } 717 718 bool is_surface_linear(const struct drm_framebuffer *fb, int color_plane) 719 { 720 return fb->modifier == DRM_FORMAT_MOD_LINEAR || 721 intel_fb_is_gen12_ccs_aux_plane(fb, color_plane) || 722 is_gen12_ccs_cc_plane(fb, color_plane); 723 } 724 725 int main_to_ccs_plane(const struct drm_framebuffer *fb, int main_plane) 726 { 727 drm_WARN_ON(fb->dev, !intel_fb_is_ccs_modifier(fb->modifier) || 728 (main_plane && main_plane >= fb->format->num_planes / 2)); 729 730 return fb->format->num_planes / 2 + main_plane; 731 } 732 733 int skl_ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane) 734 { 735 drm_WARN_ON(fb->dev, !intel_fb_is_ccs_modifier(fb->modifier) || 736 ccs_plane < fb->format->num_planes / 2); 737 738 if (is_gen12_ccs_cc_plane(fb, ccs_plane)) 739 return 0; 740 741 return ccs_plane - fb->format->num_planes / 2; 742 } 743 744 static unsigned int gen12_ccs_aux_stride(struct intel_framebuffer *fb, int ccs_plane) 745 { 746 int main_plane = skl_ccs_to_main_plane(&fb->base, ccs_plane); 747 unsigned int main_stride = fb->base.pitches[main_plane]; 748 unsigned int main_tile_width = intel_tile_width_bytes(&fb->base, main_plane); 749 750 return DIV_ROUND_UP(main_stride, 4 * main_tile_width) * 64; 751 } 752 753 int skl_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane) 754 { 755 const struct intel_modifier_desc *md = lookup_modifier(fb->modifier); 756 struct intel_display *display = to_intel_display(fb->dev); 757 758 if (md->ccs.packed_aux_planes | md->ccs.planar_aux_planes) 759 return main_to_ccs_plane(fb, main_plane); 760 else if (DISPLAY_VER(display) < 11 && 761 format_is_yuv_semiplanar(md, fb->format)) 762 return 1; 763 else 764 return 0; 765 } 766 767 unsigned int intel_tile_size(struct intel_display *display) 768 { 769 return DISPLAY_VER(display) == 2 ? 2048 : 4096; 770 } 771 772 unsigned int 773 intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane) 774 { 775 struct intel_display *display = to_intel_display(fb->dev); 776 unsigned int cpp = fb->format->cpp[color_plane]; 777 778 switch (fb->modifier) { 779 case DRM_FORMAT_MOD_LINEAR: 780 return intel_tile_size(display); 781 case I915_FORMAT_MOD_X_TILED: 782 if (DISPLAY_VER(display) == 2) 783 return 128; 784 else 785 return 512; 786 case I915_FORMAT_MOD_4_TILED_BMG_CCS: 787 case I915_FORMAT_MOD_4_TILED_LNL_CCS: 788 case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS: 789 case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC: 790 case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS: 791 case I915_FORMAT_MOD_4_TILED: 792 /* 793 * Each 4K tile consists of 64B(8*8) subtiles, with 794 * same shape as Y Tile(i.e 4*16B OWords) 795 */ 796 return 128; 797 case I915_FORMAT_MOD_Y_TILED_CCS: 798 if (intel_fb_is_ccs_aux_plane(fb, color_plane)) 799 return 128; 800 fallthrough; 801 case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS: 802 case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS_CC: 803 case I915_FORMAT_MOD_4_TILED_MTL_MC_CCS: 804 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: 805 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: 806 case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: 807 if (intel_fb_is_ccs_aux_plane(fb, color_plane) || 808 is_gen12_ccs_cc_plane(fb, color_plane)) 809 return 64; 810 fallthrough; 811 case I915_FORMAT_MOD_Y_TILED: 812 if (HAS_128B_Y_TILING(display)) 813 return 128; 814 else 815 return 512; 816 case I915_FORMAT_MOD_Yf_TILED_CCS: 817 if (intel_fb_is_ccs_aux_plane(fb, color_plane)) 818 return 128; 819 fallthrough; 820 case I915_FORMAT_MOD_Yf_TILED: 821 switch (cpp) { 822 case 1: 823 return 64; 824 case 2: 825 case 4: 826 return 128; 827 case 8: 828 case 16: 829 return 256; 830 default: 831 MISSING_CASE(cpp); 832 return cpp; 833 } 834 break; 835 default: 836 MISSING_CASE(fb->modifier); 837 return cpp; 838 } 839 } 840 841 unsigned int intel_tile_height(const struct drm_framebuffer *fb, int color_plane) 842 { 843 struct intel_display *display = to_intel_display(fb->dev); 844 845 return intel_tile_size(display) / 846 intel_tile_width_bytes(fb, color_plane); 847 } 848 849 /* 850 * Return the tile dimensions in pixel units, based on the (2 or 4 kbyte) GTT 851 * page tile size. 852 */ 853 static void intel_tile_dims(const struct drm_framebuffer *fb, int color_plane, 854 unsigned int *tile_width, 855 unsigned int *tile_height) 856 { 857 unsigned int tile_width_bytes = intel_tile_width_bytes(fb, color_plane); 858 unsigned int cpp = fb->format->cpp[color_plane]; 859 860 *tile_width = tile_width_bytes / cpp; 861 *tile_height = intel_tile_height(fb, color_plane); 862 } 863 864 /* 865 * Return the tile dimensions in pixel units, based on the tile block size. 866 * The block covers the full GTT page sized tile on all tiled surfaces and 867 * it's a 64 byte portion of the tile on TGL+ CCS surfaces. 868 */ 869 static void intel_tile_block_dims(const struct drm_framebuffer *fb, int color_plane, 870 unsigned int *tile_width, 871 unsigned int *tile_height) 872 { 873 intel_tile_dims(fb, color_plane, tile_width, tile_height); 874 875 if (intel_fb_is_gen12_ccs_aux_plane(fb, color_plane)) 876 *tile_height = 1; 877 } 878 879 unsigned int intel_tile_row_size(const struct drm_framebuffer *fb, int color_plane) 880 { 881 unsigned int tile_width, tile_height; 882 883 intel_tile_dims(fb, color_plane, &tile_width, &tile_height); 884 885 return fb->pitches[color_plane] * tile_height; 886 } 887 888 unsigned int 889 intel_fb_align_height(const struct drm_framebuffer *fb, 890 int color_plane, unsigned int height) 891 { 892 unsigned int tile_height = intel_tile_height(fb, color_plane); 893 894 return ALIGN(height, tile_height); 895 } 896 897 bool intel_fb_modifier_uses_dpt(struct intel_display *display, u64 modifier) 898 { 899 return HAS_DPT(display) && modifier != DRM_FORMAT_MOD_LINEAR; 900 } 901 902 bool intel_fb_uses_dpt(const struct drm_framebuffer *fb) 903 { 904 struct intel_display *display = to_intel_display(fb->dev); 905 906 return display->params.enable_dpt && 907 intel_fb_modifier_uses_dpt(display, fb->modifier); 908 } 909 910 void intel_fb_plane_get_subsampling(int *hsub, int *vsub, 911 const struct drm_framebuffer *fb, 912 int color_plane) 913 { 914 int main_plane; 915 916 if (color_plane == 0) { 917 *hsub = 1; 918 *vsub = 1; 919 920 return; 921 } 922 923 /* 924 * TODO: Deduct the subsampling from the char block for all CCS 925 * formats and planes. 926 */ 927 if (!intel_fb_is_gen12_ccs_aux_plane(fb, color_plane)) { 928 *hsub = fb->format->hsub; 929 *vsub = fb->format->vsub; 930 931 return; 932 } 933 934 main_plane = skl_ccs_to_main_plane(fb, color_plane); 935 *hsub = drm_format_info_block_width(fb->format, color_plane) / 936 drm_format_info_block_width(fb->format, main_plane); 937 938 /* 939 * The min stride check in the core framebuffer_check() function 940 * assumes that format->hsub applies to every plane except for the 941 * first plane. That's incorrect for the CCS AUX plane of the first 942 * plane, but for the above check to pass we must define the block 943 * width with that subsampling applied to it. Adjust the width here 944 * accordingly, so we can calculate the actual subsampling factor. 945 */ 946 if (main_plane == 0) 947 *hsub *= fb->format->hsub; 948 949 *vsub = 32; 950 } 951 952 static void intel_fb_plane_dims(const struct intel_framebuffer *fb, int color_plane, int *w, int *h) 953 { 954 int main_plane = intel_fb_is_ccs_aux_plane(&fb->base, color_plane) ? 955 skl_ccs_to_main_plane(&fb->base, color_plane) : 0; 956 unsigned int main_width = fb->base.width; 957 unsigned int main_height = fb->base.height; 958 int main_hsub, main_vsub; 959 int hsub, vsub; 960 961 intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, &fb->base, main_plane); 962 intel_fb_plane_get_subsampling(&hsub, &vsub, &fb->base, color_plane); 963 964 *w = DIV_ROUND_UP(main_width, main_hsub * hsub); 965 *h = DIV_ROUND_UP(main_height, main_vsub * vsub); 966 } 967 968 static u32 intel_adjust_tile_offset(int *x, int *y, 969 unsigned int tile_width, 970 unsigned int tile_height, 971 unsigned int tile_size, 972 unsigned int pitch_tiles, 973 u32 old_offset, 974 u32 new_offset) 975 { 976 unsigned int pitch_pixels = pitch_tiles * tile_width; 977 unsigned int tiles; 978 979 WARN_ON(old_offset & (tile_size - 1)); 980 WARN_ON(new_offset & (tile_size - 1)); 981 WARN_ON(new_offset > old_offset); 982 983 tiles = (old_offset - new_offset) / tile_size; 984 985 *y += tiles / pitch_tiles * tile_height; 986 *x += tiles % pitch_tiles * tile_width; 987 988 /* minimize x in case it got needlessly big */ 989 *y += *x / pitch_pixels * tile_height; 990 *x %= pitch_pixels; 991 992 return new_offset; 993 } 994 995 static u32 intel_adjust_linear_offset(int *x, int *y, 996 unsigned int cpp, 997 unsigned int pitch, 998 u32 old_offset, 999 u32 new_offset) 1000 { 1001 old_offset += *y * pitch + *x * cpp; 1002 1003 *y = (old_offset - new_offset) / pitch; 1004 *x = ((old_offset - new_offset) - *y * pitch) / cpp; 1005 1006 return new_offset; 1007 } 1008 1009 static u32 intel_adjust_aligned_offset(int *x, int *y, 1010 const struct drm_framebuffer *fb, 1011 int color_plane, 1012 unsigned int rotation, 1013 unsigned int pitch, 1014 u32 old_offset, u32 new_offset) 1015 { 1016 struct intel_display *display = to_intel_display(fb->dev); 1017 unsigned int cpp = fb->format->cpp[color_plane]; 1018 1019 drm_WARN_ON(display->drm, new_offset > old_offset); 1020 1021 if (!is_surface_linear(fb, color_plane)) { 1022 unsigned int tile_size, tile_width, tile_height; 1023 unsigned int pitch_tiles; 1024 1025 tile_size = intel_tile_size(display); 1026 intel_tile_dims(fb, color_plane, &tile_width, &tile_height); 1027 1028 if (drm_rotation_90_or_270(rotation)) { 1029 pitch_tiles = pitch / tile_height; 1030 swap(tile_width, tile_height); 1031 } else { 1032 pitch_tiles = pitch / (tile_width * cpp); 1033 } 1034 1035 intel_adjust_tile_offset(x, y, tile_width, tile_height, 1036 tile_size, pitch_tiles, 1037 old_offset, new_offset); 1038 } else { 1039 intel_adjust_linear_offset(x, y, cpp, pitch, 1040 old_offset, new_offset); 1041 } 1042 1043 return new_offset; 1044 } 1045 1046 /* 1047 * Adjust the tile offset by moving the difference into 1048 * the x/y offsets. 1049 */ 1050 u32 intel_plane_adjust_aligned_offset(int *x, int *y, 1051 const struct intel_plane_state *plane_state, 1052 int color_plane, 1053 u32 old_offset, u32 new_offset) 1054 { 1055 return intel_adjust_aligned_offset(x, y, plane_state->hw.fb, color_plane, 1056 plane_state->hw.rotation, 1057 plane_state->view.color_plane[color_plane].mapping_stride, 1058 old_offset, new_offset); 1059 } 1060 1061 /* 1062 * Computes the aligned offset to the base tile and adjusts 1063 * x, y. bytes per pixel is assumed to be a power-of-two. 1064 * 1065 * In the 90/270 rotated case, x and y are assumed 1066 * to be already rotated to match the rotated GTT view, and 1067 * pitch is the tile_height aligned framebuffer height. 1068 * 1069 * This function is used when computing the derived information 1070 * under intel_framebuffer, so using any of that information 1071 * here is not allowed. Anything under drm_framebuffer can be 1072 * used. This is why the user has to pass in the pitch since it 1073 * is specified in the rotated orientation. 1074 */ 1075 static u32 intel_compute_aligned_offset(struct intel_display *display, 1076 int *x, int *y, 1077 const struct drm_framebuffer *fb, 1078 int color_plane, 1079 unsigned int pitch, 1080 unsigned int rotation, 1081 unsigned int alignment) 1082 { 1083 unsigned int cpp = fb->format->cpp[color_plane]; 1084 u32 offset, offset_aligned; 1085 1086 if (!is_surface_linear(fb, color_plane)) { 1087 unsigned int tile_size, tile_width, tile_height; 1088 unsigned int tile_rows, tiles, pitch_tiles; 1089 1090 tile_size = intel_tile_size(display); 1091 intel_tile_dims(fb, color_plane, &tile_width, &tile_height); 1092 1093 if (drm_rotation_90_or_270(rotation)) { 1094 pitch_tiles = pitch / tile_height; 1095 swap(tile_width, tile_height); 1096 } else { 1097 pitch_tiles = pitch / (tile_width * cpp); 1098 } 1099 1100 tile_rows = *y / tile_height; 1101 *y %= tile_height; 1102 1103 tiles = *x / tile_width; 1104 *x %= tile_width; 1105 1106 offset = (tile_rows * pitch_tiles + tiles) * tile_size; 1107 1108 offset_aligned = offset; 1109 if (alignment) 1110 offset_aligned = rounddown(offset_aligned, alignment); 1111 1112 intel_adjust_tile_offset(x, y, tile_width, tile_height, 1113 tile_size, pitch_tiles, 1114 offset, offset_aligned); 1115 } else { 1116 offset = *y * pitch + *x * cpp; 1117 offset_aligned = offset; 1118 if (alignment) { 1119 offset_aligned = rounddown(offset_aligned, alignment); 1120 *y = (offset % alignment) / pitch; 1121 *x = ((offset % alignment) - *y * pitch) / cpp; 1122 } else { 1123 *y = *x = 0; 1124 } 1125 } 1126 1127 return offset_aligned; 1128 } 1129 1130 u32 intel_plane_compute_aligned_offset(int *x, int *y, 1131 const struct intel_plane_state *plane_state, 1132 int color_plane) 1133 { 1134 struct intel_display *display = to_intel_display(plane_state); 1135 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); 1136 const struct drm_framebuffer *fb = plane_state->hw.fb; 1137 unsigned int rotation = plane_state->hw.rotation; 1138 unsigned int pitch = plane_state->view.color_plane[color_plane].mapping_stride; 1139 unsigned int alignment = plane->min_alignment(plane, fb, color_plane); 1140 1141 return intel_compute_aligned_offset(display, x, y, fb, color_plane, 1142 pitch, rotation, alignment); 1143 } 1144 1145 /* Convert the fb->offset[] into x/y offsets */ 1146 static int intel_fb_offset_to_xy(int *x, int *y, 1147 const struct drm_framebuffer *fb, 1148 int color_plane) 1149 { 1150 struct intel_display *display = to_intel_display(fb->dev); 1151 unsigned int height, alignment, unused; 1152 1153 if (fb->modifier != DRM_FORMAT_MOD_LINEAR) 1154 alignment = intel_tile_size(display); 1155 else 1156 alignment = 0; 1157 1158 if (alignment != 0 && fb->offsets[color_plane] % alignment) { 1159 drm_dbg_kms(display->drm, 1160 "Misaligned offset 0x%08x for color plane %d\n", 1161 fb->offsets[color_plane], color_plane); 1162 return -EINVAL; 1163 } 1164 1165 height = drm_format_info_plane_height(fb->format, fb->height, color_plane); 1166 height = ALIGN(height, intel_tile_height(fb, color_plane)); 1167 1168 /* Catch potential overflows early */ 1169 if (check_add_overflow(mul_u32_u32(height, fb->pitches[color_plane]), 1170 fb->offsets[color_plane], &unused)) { 1171 drm_dbg_kms(display->drm, 1172 "Bad offset 0x%08x or pitch %d for color plane %d\n", 1173 fb->offsets[color_plane], fb->pitches[color_plane], 1174 color_plane); 1175 return -ERANGE; 1176 } 1177 1178 *x = 0; 1179 *y = 0; 1180 1181 intel_adjust_aligned_offset(x, y, 1182 fb, color_plane, DRM_MODE_ROTATE_0, 1183 fb->pitches[color_plane], 1184 fb->offsets[color_plane], 0); 1185 1186 return 0; 1187 } 1188 1189 static int intel_fb_check_ccs_xy(const struct drm_framebuffer *fb, int ccs_plane, int x, int y) 1190 { 1191 struct intel_display *display = to_intel_display(fb->dev); 1192 const struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); 1193 int main_plane; 1194 int hsub, vsub; 1195 int tile_width, tile_height; 1196 int ccs_x, ccs_y; 1197 int main_x, main_y; 1198 1199 if (!intel_fb_is_ccs_aux_plane(fb, ccs_plane)) 1200 return 0; 1201 1202 /* 1203 * While all the tile dimensions are based on a 2k or 4k GTT page size 1204 * here the main and CCS coordinates must match only within a (64 byte 1205 * on TGL+) block inside the tile. 1206 */ 1207 intel_tile_block_dims(fb, ccs_plane, &tile_width, &tile_height); 1208 intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs_plane); 1209 1210 tile_width *= hsub; 1211 tile_height *= vsub; 1212 1213 ccs_x = (x * hsub) % tile_width; 1214 ccs_y = (y * vsub) % tile_height; 1215 1216 main_plane = skl_ccs_to_main_plane(fb, ccs_plane); 1217 main_x = intel_fb->normal_view.color_plane[main_plane].x % tile_width; 1218 main_y = intel_fb->normal_view.color_plane[main_plane].y % tile_height; 1219 1220 /* 1221 * CCS doesn't have its own x/y offset register, so the intra CCS tile 1222 * x/y offsets must match between CCS and the main surface. 1223 */ 1224 if (main_x != ccs_x || main_y != ccs_y) { 1225 drm_dbg_kms(display->drm, 1226 "Bad CCS x/y (main %d,%d ccs %d,%d) full (main %d,%d ccs %d,%d)\n", 1227 main_x, main_y, ccs_x, ccs_y, 1228 intel_fb->normal_view.color_plane[main_plane].x, 1229 intel_fb->normal_view.color_plane[main_plane].y, 1230 x, y); 1231 return -EINVAL; 1232 } 1233 1234 return 0; 1235 } 1236 1237 static bool intel_plane_can_remap(const struct intel_plane_state *plane_state) 1238 { 1239 struct intel_display *display = to_intel_display(plane_state); 1240 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); 1241 const struct drm_framebuffer *fb = plane_state->hw.fb; 1242 int i; 1243 1244 /* We don't want to deal with remapping with cursors */ 1245 if (plane->id == PLANE_CURSOR) 1246 return false; 1247 1248 /* 1249 * The display engine limits already match/exceed the 1250 * render engine limits, so not much point in remapping. 1251 * Would also need to deal with the fence POT alignment 1252 * and gen2 2KiB GTT tile size. 1253 */ 1254 if (DISPLAY_VER(display) < 4) 1255 return false; 1256 1257 /* 1258 * The new CCS hash mode isn't compatible with remapping as 1259 * the virtual address of the pages affects the compressed data. 1260 */ 1261 if (intel_fb_is_ccs_modifier(fb->modifier)) 1262 return false; 1263 1264 /* Linear needs a page aligned stride for remapping */ 1265 if (fb->modifier == DRM_FORMAT_MOD_LINEAR) { 1266 unsigned int alignment = intel_tile_size(display) - 1; 1267 1268 for (i = 0; i < fb->format->num_planes; i++) { 1269 if (fb->pitches[i] & alignment) 1270 return false; 1271 } 1272 } 1273 1274 return true; 1275 } 1276 1277 bool intel_fb_needs_pot_stride_remap(const struct intel_framebuffer *fb) 1278 { 1279 struct intel_display *display = to_intel_display(fb->base.dev); 1280 1281 return (display->platform.alderlake_p || DISPLAY_VER(display) >= 14) && 1282 intel_fb_uses_dpt(&fb->base); 1283 } 1284 1285 bool intel_plane_uses_fence(const struct intel_plane_state *plane_state) 1286 { 1287 struct intel_display *display = to_intel_display(plane_state); 1288 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); 1289 1290 return DISPLAY_VER(display) < 4 || 1291 (plane->fbc && !plane_state->no_fbc_reason && 1292 plane_state->view.gtt.type == I915_GTT_VIEW_NORMAL); 1293 } 1294 1295 static int intel_fb_pitch(const struct intel_framebuffer *fb, int color_plane, unsigned int rotation) 1296 { 1297 if (drm_rotation_90_or_270(rotation)) 1298 return fb->rotated_view.color_plane[color_plane].mapping_stride; 1299 else if (intel_fb_needs_pot_stride_remap(fb)) 1300 return fb->remapped_view.color_plane[color_plane].mapping_stride; 1301 else 1302 return fb->normal_view.color_plane[color_plane].mapping_stride; 1303 } 1304 1305 static bool intel_plane_needs_remap(const struct intel_plane_state *plane_state) 1306 { 1307 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); 1308 const struct intel_framebuffer *fb = to_intel_framebuffer(plane_state->hw.fb); 1309 unsigned int rotation = plane_state->hw.rotation; 1310 u32 stride, max_stride; 1311 1312 /* 1313 * No remapping for invisible planes since we don't have 1314 * an actual source viewport to remap. 1315 */ 1316 if (!plane_state->uapi.visible) 1317 return false; 1318 1319 if (!intel_plane_can_remap(plane_state)) 1320 return false; 1321 1322 /* 1323 * FIXME: aux plane limits on gen9+ are 1324 * unclear in Bspec, for now no checking. 1325 */ 1326 stride = intel_fb_pitch(fb, 0, rotation); 1327 max_stride = plane->max_stride(plane, fb->base.format, 1328 fb->base.modifier, rotation); 1329 1330 return stride > max_stride; 1331 } 1332 1333 static int convert_plane_offset_to_xy(const struct intel_framebuffer *fb, int color_plane, 1334 int plane_width, int *x, int *y) 1335 { 1336 struct intel_display *display = to_intel_display(fb->base.dev); 1337 struct drm_gem_object *obj = intel_fb_bo(&fb->base); 1338 int ret; 1339 1340 ret = intel_fb_offset_to_xy(x, y, &fb->base, color_plane); 1341 if (ret) { 1342 drm_dbg_kms(display->drm, 1343 "bad fb plane %d offset: 0x%x\n", 1344 color_plane, fb->base.offsets[color_plane]); 1345 return ret; 1346 } 1347 1348 ret = intel_fb_check_ccs_xy(&fb->base, color_plane, *x, *y); 1349 if (ret) 1350 return ret; 1351 1352 /* 1353 * The fence (if used) is aligned to the start of the object 1354 * so having the framebuffer wrap around across the edge of the 1355 * fenced region doesn't really work. We have no API to configure 1356 * the fence start offset within the object (nor could we probably 1357 * on gen2/3). So it's just easier if we just require that the 1358 * fb layout agrees with the fence layout. We already check that the 1359 * fb stride matches the fence stride elsewhere. 1360 */ 1361 if (color_plane == 0 && intel_bo_is_tiled(obj) && 1362 (*x + plane_width) * fb->base.format->cpp[color_plane] > fb->base.pitches[color_plane]) { 1363 drm_dbg_kms(display->drm, 1364 "bad fb plane %d offset: 0x%x\n", 1365 color_plane, fb->base.offsets[color_plane]); 1366 return -EINVAL; 1367 } 1368 1369 return 0; 1370 } 1371 1372 static u32 calc_plane_aligned_offset(const struct intel_framebuffer *fb, int color_plane, int *x, int *y) 1373 { 1374 struct intel_display *display = to_intel_display(fb->base.dev); 1375 unsigned int tile_size = intel_tile_size(display); 1376 u32 offset; 1377 1378 offset = intel_compute_aligned_offset(display, x, y, &fb->base, color_plane, 1379 fb->base.pitches[color_plane], 1380 DRM_MODE_ROTATE_0, 1381 tile_size); 1382 1383 return offset / tile_size; 1384 } 1385 1386 struct fb_plane_view_dims { 1387 unsigned int width, height; 1388 unsigned int tile_width, tile_height; 1389 }; 1390 1391 static void init_plane_view_dims(const struct intel_framebuffer *fb, int color_plane, 1392 unsigned int width, unsigned int height, 1393 struct fb_plane_view_dims *dims) 1394 { 1395 dims->width = width; 1396 dims->height = height; 1397 1398 intel_tile_dims(&fb->base, color_plane, &dims->tile_width, &dims->tile_height); 1399 } 1400 1401 static unsigned int 1402 plane_view_src_stride_tiles(const struct intel_framebuffer *fb, int color_plane, 1403 const struct fb_plane_view_dims *dims) 1404 { 1405 return DIV_ROUND_UP(fb->base.pitches[color_plane], 1406 dims->tile_width * fb->base.format->cpp[color_plane]); 1407 } 1408 1409 static unsigned int 1410 plane_view_dst_stride_tiles(const struct intel_framebuffer *fb, int color_plane, 1411 unsigned int pitch_tiles) 1412 { 1413 if (intel_fb_needs_pot_stride_remap(fb)) { 1414 /* 1415 * ADL_P, the only platform needing a POT stride has a minimum 1416 * of 8 main surface tiles. 1417 */ 1418 return roundup_pow_of_two(max(pitch_tiles, 8u)); 1419 } else { 1420 return pitch_tiles; 1421 } 1422 } 1423 1424 static unsigned int 1425 plane_view_scanout_stride(const struct intel_framebuffer *fb, int color_plane, 1426 unsigned int tile_width, 1427 unsigned int src_stride_tiles, unsigned int dst_stride_tiles) 1428 { 1429 struct intel_display *display = to_intel_display(fb->base.dev); 1430 unsigned int stride_tiles; 1431 1432 if ((display->platform.alderlake_p || DISPLAY_VER(display) >= 14) && 1433 src_stride_tiles < dst_stride_tiles) 1434 stride_tiles = src_stride_tiles; 1435 else 1436 stride_tiles = dst_stride_tiles; 1437 1438 return stride_tiles * tile_width * fb->base.format->cpp[color_plane]; 1439 } 1440 1441 static unsigned int 1442 plane_view_width_tiles(const struct intel_framebuffer *fb, int color_plane, 1443 const struct fb_plane_view_dims *dims, 1444 int x) 1445 { 1446 return DIV_ROUND_UP(x + dims->width, dims->tile_width); 1447 } 1448 1449 static unsigned int 1450 plane_view_height_tiles(const struct intel_framebuffer *fb, int color_plane, 1451 const struct fb_plane_view_dims *dims, 1452 int y) 1453 { 1454 return DIV_ROUND_UP(y + dims->height, dims->tile_height); 1455 } 1456 1457 static unsigned int 1458 plane_view_linear_tiles(const struct intel_framebuffer *fb, int color_plane, 1459 const struct fb_plane_view_dims *dims, 1460 int x, int y) 1461 { 1462 struct intel_display *display = to_intel_display(fb->base.dev); 1463 unsigned int size; 1464 1465 size = (y + dims->height) * fb->base.pitches[color_plane] + 1466 x * fb->base.format->cpp[color_plane]; 1467 1468 return DIV_ROUND_UP(size, intel_tile_size(display)); 1469 } 1470 1471 #define assign_chk_ovf(display, var, val) ({ \ 1472 drm_WARN_ON((display)->drm, overflows_type(val, var)); \ 1473 (var) = (val); \ 1474 }) 1475 1476 #define assign_bfld_chk_ovf(display, var, val) ({ \ 1477 (var) = (val); \ 1478 drm_WARN_ON((display)->drm, (var) != (val)); \ 1479 (var); \ 1480 }) 1481 1482 static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_plane, 1483 const struct fb_plane_view_dims *dims, 1484 u32 obj_offset, u32 gtt_offset, int x, int y, 1485 struct intel_fb_view *view) 1486 { 1487 struct intel_display *display = to_intel_display(fb->base.dev); 1488 struct intel_remapped_plane_info *remap_info = &view->gtt.remapped.plane[color_plane]; 1489 struct i915_color_plane_view *color_plane_info = &view->color_plane[color_plane]; 1490 unsigned int tile_width = dims->tile_width; 1491 unsigned int tile_height = dims->tile_height; 1492 unsigned int tile_size = intel_tile_size(display); 1493 struct drm_rect r; 1494 u32 size = 0; 1495 1496 assign_bfld_chk_ovf(display, remap_info->offset, obj_offset); 1497 1498 if (intel_fb_is_gen12_ccs_aux_plane(&fb->base, color_plane)) { 1499 remap_info->linear = 1; 1500 1501 assign_chk_ovf(display, remap_info->size, 1502 plane_view_linear_tiles(fb, color_plane, dims, x, y)); 1503 } else { 1504 remap_info->linear = 0; 1505 1506 assign_chk_ovf(display, remap_info->src_stride, 1507 plane_view_src_stride_tiles(fb, color_plane, dims)); 1508 assign_chk_ovf(display, remap_info->width, 1509 plane_view_width_tiles(fb, color_plane, dims, x)); 1510 assign_chk_ovf(display, remap_info->height, 1511 plane_view_height_tiles(fb, color_plane, dims, y)); 1512 } 1513 1514 if (view->gtt.type == I915_GTT_VIEW_ROTATED) { 1515 drm_WARN_ON(display->drm, remap_info->linear); 1516 check_array_bounds(display, view->gtt.rotated.plane, color_plane); 1517 1518 assign_chk_ovf(display, remap_info->dst_stride, 1519 plane_view_dst_stride_tiles(fb, color_plane, remap_info->height)); 1520 1521 /* rotate the x/y offsets to match the GTT view */ 1522 drm_rect_init(&r, x, y, dims->width, dims->height); 1523 drm_rect_rotate(&r, 1524 remap_info->width * tile_width, 1525 remap_info->height * tile_height, 1526 DRM_MODE_ROTATE_270); 1527 1528 color_plane_info->x = r.x1; 1529 color_plane_info->y = r.y1; 1530 1531 color_plane_info->mapping_stride = remap_info->dst_stride * tile_height; 1532 color_plane_info->scanout_stride = color_plane_info->mapping_stride; 1533 1534 size += remap_info->dst_stride * remap_info->width; 1535 1536 /* rotate the tile dimensions to match the GTT view */ 1537 swap(tile_width, tile_height); 1538 } else { 1539 drm_WARN_ON(display->drm, view->gtt.type != I915_GTT_VIEW_REMAPPED); 1540 1541 check_array_bounds(display, view->gtt.remapped.plane, color_plane); 1542 1543 if (view->gtt.remapped.plane_alignment) { 1544 u32 aligned_offset = ALIGN(gtt_offset, 1545 view->gtt.remapped.plane_alignment); 1546 1547 size += aligned_offset - gtt_offset; 1548 gtt_offset = aligned_offset; 1549 } 1550 1551 color_plane_info->x = x; 1552 color_plane_info->y = y; 1553 1554 if (remap_info->linear) { 1555 color_plane_info->mapping_stride = fb->base.pitches[color_plane]; 1556 color_plane_info->scanout_stride = color_plane_info->mapping_stride; 1557 1558 size += remap_info->size; 1559 } else { 1560 unsigned int dst_stride; 1561 1562 /* 1563 * The hardware automagically calculates the CCS AUX surface 1564 * stride from the main surface stride so can't really remap a 1565 * smaller subset (unless we'd remap in whole AUX page units). 1566 */ 1567 if (intel_fb_needs_pot_stride_remap(fb) && 1568 intel_fb_is_ccs_modifier(fb->base.modifier)) 1569 dst_stride = remap_info->src_stride; 1570 else 1571 dst_stride = remap_info->width; 1572 1573 dst_stride = plane_view_dst_stride_tiles(fb, color_plane, dst_stride); 1574 1575 assign_chk_ovf(display, remap_info->dst_stride, dst_stride); 1576 color_plane_info->mapping_stride = dst_stride * 1577 tile_width * 1578 fb->base.format->cpp[color_plane]; 1579 color_plane_info->scanout_stride = 1580 plane_view_scanout_stride(fb, color_plane, tile_width, 1581 remap_info->src_stride, 1582 dst_stride); 1583 1584 size += dst_stride * remap_info->height; 1585 } 1586 } 1587 1588 /* 1589 * We only keep the x/y offsets, so push all of the gtt offset into 1590 * the x/y offsets. x,y will hold the first pixel of the framebuffer 1591 * plane from the start of the remapped/rotated gtt mapping. 1592 */ 1593 if (remap_info->linear) 1594 intel_adjust_linear_offset(&color_plane_info->x, &color_plane_info->y, 1595 fb->base.format->cpp[color_plane], 1596 color_plane_info->mapping_stride, 1597 gtt_offset * tile_size, 0); 1598 else 1599 intel_adjust_tile_offset(&color_plane_info->x, &color_plane_info->y, 1600 tile_width, tile_height, 1601 tile_size, remap_info->dst_stride, 1602 gtt_offset * tile_size, 0); 1603 1604 return size; 1605 } 1606 1607 #undef assign_chk_ovf 1608 1609 /* Return number of tiles @color_plane needs. */ 1610 static unsigned int 1611 calc_plane_normal_size(const struct intel_framebuffer *fb, int color_plane, 1612 const struct fb_plane_view_dims *dims, 1613 int x, int y) 1614 { 1615 unsigned int tiles; 1616 1617 if (is_surface_linear(&fb->base, color_plane)) { 1618 tiles = plane_view_linear_tiles(fb, color_plane, dims, x, y); 1619 } else { 1620 tiles = plane_view_src_stride_tiles(fb, color_plane, dims) * 1621 plane_view_height_tiles(fb, color_plane, dims, y); 1622 /* 1623 * If the plane isn't horizontally tile aligned, 1624 * we need one more tile. 1625 */ 1626 if (x != 0) 1627 tiles++; 1628 } 1629 1630 return tiles; 1631 } 1632 1633 static void intel_fb_view_init(struct intel_display *display, 1634 struct intel_fb_view *view, 1635 enum i915_gtt_view_type view_type) 1636 { 1637 memset(view, 0, sizeof(*view)); 1638 view->gtt.type = view_type; 1639 1640 if (view_type == I915_GTT_VIEW_REMAPPED && 1641 (display->platform.alderlake_p || DISPLAY_VER(display) >= 14)) 1642 view->gtt.remapped.plane_alignment = SZ_2M / PAGE_SIZE; 1643 } 1644 1645 bool intel_fb_supports_90_270_rotation(const struct intel_framebuffer *fb) 1646 { 1647 struct intel_display *display = to_intel_display(fb->base.dev); 1648 1649 if (DISPLAY_VER(display) >= 13) 1650 return false; 1651 1652 return fb->base.modifier == I915_FORMAT_MOD_Y_TILED || 1653 fb->base.modifier == I915_FORMAT_MOD_Yf_TILED; 1654 } 1655 1656 static unsigned int intel_fb_min_alignment(const struct drm_framebuffer *fb) 1657 { 1658 struct intel_display *display = to_intel_display(fb->dev); 1659 struct intel_plane *plane; 1660 unsigned int min_alignment = 0; 1661 1662 for_each_intel_plane(display->drm, plane) { 1663 unsigned int plane_min_alignment; 1664 1665 if (!drm_plane_has_format(&plane->base, fb->format->format, fb->modifier)) 1666 continue; 1667 1668 plane_min_alignment = plane->min_alignment(plane, fb, 0); 1669 1670 drm_WARN_ON(display->drm, plane_min_alignment && 1671 !is_power_of_2(plane_min_alignment)); 1672 1673 if (intel_plane_needs_physical(plane)) 1674 continue; 1675 1676 min_alignment = max(min_alignment, plane_min_alignment); 1677 } 1678 1679 return min_alignment; 1680 } 1681 1682 static unsigned int intel_fb_vtd_guard(const struct drm_framebuffer *fb) 1683 { 1684 struct intel_display *display = to_intel_display(fb->dev); 1685 struct intel_plane *plane; 1686 unsigned int vtd_guard = 0; 1687 1688 for_each_intel_plane(display->drm, plane) { 1689 if (!drm_plane_has_format(&plane->base, fb->format->format, fb->modifier)) 1690 continue; 1691 1692 vtd_guard = max_t(unsigned int, vtd_guard, plane->vtd_guard); 1693 } 1694 1695 return vtd_guard; 1696 } 1697 1698 int intel_fill_fb_info(struct intel_display *display, struct intel_framebuffer *fb) 1699 { 1700 struct drm_gem_object *obj = intel_fb_bo(&fb->base); 1701 u32 gtt_offset_rotated = 0; 1702 u32 gtt_offset_remapped = 0; 1703 unsigned int max_size = 0; 1704 int i, num_planes = fb->base.format->num_planes; 1705 unsigned int tile_size = intel_tile_size(display); 1706 1707 intel_fb_view_init(display, &fb->normal_view, I915_GTT_VIEW_NORMAL); 1708 1709 drm_WARN_ON(display->drm, 1710 intel_fb_supports_90_270_rotation(fb) && 1711 intel_fb_needs_pot_stride_remap(fb)); 1712 1713 if (intel_fb_supports_90_270_rotation(fb)) 1714 intel_fb_view_init(display, &fb->rotated_view, I915_GTT_VIEW_ROTATED); 1715 if (intel_fb_needs_pot_stride_remap(fb)) 1716 intel_fb_view_init(display, &fb->remapped_view, I915_GTT_VIEW_REMAPPED); 1717 1718 for (i = 0; i < num_planes; i++) { 1719 struct fb_plane_view_dims view_dims; 1720 unsigned int width, height; 1721 unsigned int size; 1722 u32 offset; 1723 int x, y; 1724 int ret; 1725 1726 /* 1727 * Plane 2 of Render Compression with Clear Color fb modifier 1728 * is consumed by the driver and not passed to DE. Skip the 1729 * arithmetic related to alignment and offset calculation. 1730 */ 1731 if (is_gen12_ccs_cc_plane(&fb->base, i)) { 1732 unsigned int end; 1733 1734 if (!IS_ALIGNED(fb->base.offsets[i], 64)) { 1735 drm_dbg_kms(display->drm, 1736 "fb misaligned clear color plane %d offset (0x%x)\n", 1737 i, fb->base.offsets[i]); 1738 return -EINVAL; 1739 } 1740 1741 if (check_add_overflow(fb->base.offsets[i], 64, &end)) { 1742 drm_dbg_kms(display->drm, 1743 "fb bad clear color plane %d offset (0x%x)\n", 1744 i, fb->base.offsets[i]); 1745 return -EINVAL; 1746 } 1747 1748 max_size = max(max_size, DIV_ROUND_UP(end, tile_size)); 1749 continue; 1750 } 1751 1752 intel_fb_plane_dims(fb, i, &width, &height); 1753 1754 ret = convert_plane_offset_to_xy(fb, i, width, &x, &y); 1755 if (ret) 1756 return ret; 1757 1758 init_plane_view_dims(fb, i, width, height, &view_dims); 1759 1760 /* 1761 * First pixel of the framebuffer from 1762 * the start of the normal gtt mapping. 1763 */ 1764 fb->normal_view.color_plane[i].x = x; 1765 fb->normal_view.color_plane[i].y = y; 1766 fb->normal_view.color_plane[i].mapping_stride = fb->base.pitches[i]; 1767 fb->normal_view.color_plane[i].scanout_stride = 1768 fb->normal_view.color_plane[i].mapping_stride; 1769 1770 offset = calc_plane_aligned_offset(fb, i, &x, &y); 1771 1772 if (intel_fb_supports_90_270_rotation(fb)) 1773 gtt_offset_rotated += calc_plane_remap_info(fb, i, &view_dims, 1774 offset, gtt_offset_rotated, x, y, 1775 &fb->rotated_view); 1776 1777 if (intel_fb_needs_pot_stride_remap(fb)) 1778 gtt_offset_remapped += calc_plane_remap_info(fb, i, &view_dims, 1779 offset, gtt_offset_remapped, x, y, 1780 &fb->remapped_view); 1781 1782 size = calc_plane_normal_size(fb, i, &view_dims, x, y); 1783 /* how many tiles in total needed in the bo */ 1784 max_size = max(max_size, offset + size); 1785 } 1786 1787 if (mul_u32_u32(max_size, tile_size) > obj->size) { 1788 drm_dbg_kms(display->drm, 1789 "fb too big for bo (need %llu bytes, have %zu bytes)\n", 1790 mul_u32_u32(max_size, tile_size), obj->size); 1791 return -EINVAL; 1792 } 1793 1794 fb->min_alignment = intel_fb_min_alignment(&fb->base); 1795 fb->vtd_guard = intel_fb_vtd_guard(&fb->base); 1796 1797 return 0; 1798 } 1799 1800 unsigned int intel_fb_view_vtd_guard(const struct drm_framebuffer *fb, 1801 const struct intel_fb_view *view, 1802 unsigned int rotation) 1803 { 1804 unsigned int vtd_guard; 1805 int color_plane; 1806 1807 vtd_guard = to_intel_framebuffer(fb)->vtd_guard; 1808 if (!vtd_guard) 1809 return 0; 1810 1811 for (color_plane = 0; color_plane < fb->format->num_planes; color_plane++) { 1812 unsigned int stride, tile; 1813 1814 if (intel_fb_is_ccs_aux_plane(fb, color_plane) || 1815 is_gen12_ccs_cc_plane(fb, color_plane)) 1816 continue; 1817 1818 stride = view->color_plane[color_plane].mapping_stride; 1819 1820 if (drm_rotation_90_or_270(rotation)) 1821 tile = intel_tile_height(fb, color_plane); 1822 else 1823 tile = intel_tile_width_bytes(fb, color_plane); 1824 1825 vtd_guard = max(vtd_guard, DIV_ROUND_UP(stride, tile)); 1826 } 1827 1828 return vtd_guard; 1829 } 1830 1831 static void intel_plane_remap_gtt(struct intel_plane_state *plane_state) 1832 { 1833 struct intel_display *display = to_intel_display(plane_state); 1834 struct drm_framebuffer *fb = plane_state->hw.fb; 1835 struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); 1836 unsigned int rotation = plane_state->hw.rotation; 1837 int i, num_planes = fb->format->num_planes; 1838 unsigned int src_x, src_y; 1839 unsigned int src_w, src_h; 1840 u32 gtt_offset = 0; 1841 1842 intel_fb_view_init(display, &plane_state->view, 1843 drm_rotation_90_or_270(rotation) ? I915_GTT_VIEW_ROTATED : 1844 I915_GTT_VIEW_REMAPPED); 1845 1846 src_x = plane_state->uapi.src.x1 >> 16; 1847 src_y = plane_state->uapi.src.y1 >> 16; 1848 src_w = drm_rect_width(&plane_state->uapi.src) >> 16; 1849 src_h = drm_rect_height(&plane_state->uapi.src) >> 16; 1850 1851 drm_WARN_ON(display->drm, intel_fb_is_ccs_modifier(fb->modifier)); 1852 1853 /* Make src coordinates relative to the viewport */ 1854 drm_rect_translate(&plane_state->uapi.src, 1855 -(src_x << 16), -(src_y << 16)); 1856 1857 /* Rotate src coordinates to match rotated GTT view */ 1858 if (drm_rotation_90_or_270(rotation)) 1859 drm_rect_rotate(&plane_state->uapi.src, 1860 src_w << 16, src_h << 16, 1861 DRM_MODE_ROTATE_270); 1862 1863 for (i = 0; i < num_planes; i++) { 1864 unsigned int hsub = i ? fb->format->hsub : 1; 1865 unsigned int vsub = i ? fb->format->vsub : 1; 1866 struct fb_plane_view_dims view_dims; 1867 unsigned int width, height; 1868 unsigned int x, y; 1869 u32 offset; 1870 1871 x = src_x / hsub; 1872 y = src_y / vsub; 1873 width = src_w / hsub; 1874 height = src_h / vsub; 1875 1876 init_plane_view_dims(intel_fb, i, width, height, &view_dims); 1877 1878 /* 1879 * First pixel of the src viewport from the 1880 * start of the normal gtt mapping. 1881 */ 1882 x += intel_fb->normal_view.color_plane[i].x; 1883 y += intel_fb->normal_view.color_plane[i].y; 1884 1885 offset = calc_plane_aligned_offset(intel_fb, i, &x, &y); 1886 1887 gtt_offset += calc_plane_remap_info(intel_fb, i, &view_dims, 1888 offset, gtt_offset, x, y, 1889 &plane_state->view); 1890 } 1891 } 1892 1893 unsigned int intel_rotation_info_size(const struct intel_rotation_info *rot_info) 1894 { 1895 unsigned int size = 0; 1896 int i; 1897 1898 for (i = 0 ; i < ARRAY_SIZE(rot_info->plane); i++) 1899 size += rot_info->plane[i].dst_stride * rot_info->plane[i].width; 1900 1901 return size; 1902 } 1903 1904 unsigned int intel_remapped_info_size(const struct intel_remapped_info *rem_info) 1905 { 1906 unsigned int size = 0; 1907 int i; 1908 1909 for (i = 0 ; i < ARRAY_SIZE(rem_info->plane); i++) { 1910 unsigned int plane_size; 1911 1912 if (rem_info->plane[i].linear) 1913 plane_size = rem_info->plane[i].size; 1914 else 1915 plane_size = rem_info->plane[i].dst_stride * rem_info->plane[i].height; 1916 1917 if (plane_size == 0) 1918 continue; 1919 1920 if (rem_info->plane_alignment) 1921 size = ALIGN(size, rem_info->plane_alignment); 1922 1923 size += plane_size; 1924 } 1925 1926 return size; 1927 } 1928 1929 void intel_fb_fill_view(const struct intel_framebuffer *fb, unsigned int rotation, 1930 struct intel_fb_view *view) 1931 { 1932 if (drm_rotation_90_or_270(rotation)) 1933 *view = fb->rotated_view; 1934 else if (intel_fb_needs_pot_stride_remap(fb)) 1935 *view = fb->remapped_view; 1936 else 1937 *view = fb->normal_view; 1938 } 1939 1940 /* 1941 * Convert the x/y offsets into a linear offset. 1942 * Only valid with 0/180 degree rotation, which is fine since linear 1943 * offset is only used with linear buffers on pre-hsw and tiled buffers 1944 * with gen2/3, and 90/270 degree rotations isn't supported on any of them. 1945 */ 1946 u32 intel_fb_xy_to_linear(int x, int y, 1947 const struct intel_plane_state *plane_state, 1948 int color_plane) 1949 { 1950 const struct drm_framebuffer *fb = plane_state->hw.fb; 1951 unsigned int cpp = fb->format->cpp[color_plane]; 1952 unsigned int pitch = plane_state->view.color_plane[color_plane].mapping_stride; 1953 1954 return y * pitch + x * cpp; 1955 } 1956 1957 /* 1958 * Add the x/y offsets derived from fb->offsets[] to the user 1959 * specified plane src x/y offsets. The resulting x/y offsets 1960 * specify the start of scanout from the beginning of the gtt mapping. 1961 */ 1962 void intel_add_fb_offsets(int *x, int *y, 1963 const struct intel_plane_state *plane_state, 1964 int color_plane) 1965 1966 { 1967 *x += plane_state->view.color_plane[color_plane].x; 1968 *y += plane_state->view.color_plane[color_plane].y; 1969 } 1970 1971 static 1972 u32 intel_fb_max_stride(struct intel_display *display, 1973 const struct drm_format_info *info, 1974 u64 modifier) 1975 { 1976 /* 1977 * Arbitrary limit for gen4+ chosen to match the 1978 * render engine max stride. 1979 * 1980 * The new CCS hash mode makes remapping impossible 1981 */ 1982 if (DISPLAY_VER(display) < 4 || intel_fb_is_ccs_modifier(modifier) || 1983 intel_fb_modifier_uses_dpt(display, modifier)) 1984 return intel_plane_fb_max_stride(display, info, modifier); 1985 else if (DISPLAY_VER(display) >= 7) 1986 return 256 * 1024; 1987 else 1988 return 128 * 1024; 1989 } 1990 1991 static unsigned int 1992 intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane) 1993 { 1994 struct intel_display *display = to_intel_display(fb->dev); 1995 unsigned int tile_width; 1996 1997 if (is_surface_linear(fb, color_plane)) { 1998 unsigned int max_stride = intel_plane_fb_max_stride(display, 1999 fb->format, 2000 fb->modifier); 2001 2002 /* 2003 * To make remapping with linear generally feasible 2004 * we need the stride to be page aligned. 2005 */ 2006 if (fb->pitches[color_plane] > max_stride && 2007 !intel_fb_is_ccs_modifier(fb->modifier)) 2008 return intel_tile_size(display); 2009 else 2010 return 64; 2011 } 2012 2013 tile_width = intel_tile_width_bytes(fb, color_plane); 2014 if (intel_fb_is_ccs_modifier(fb->modifier)) { 2015 /* 2016 * On TGL the surface stride must be 4 tile aligned, mapped by 2017 * one 64 byte cacheline on the CCS AUX surface. 2018 */ 2019 if (DISPLAY_VER(display) >= 12) 2020 tile_width *= 4; 2021 /* 2022 * Display WA #0531: skl,bxt,kbl,glk 2023 * 2024 * Render decompression and plane width > 3840 2025 * combined with horizontal panning requires the 2026 * plane stride to be a multiple of 4. We'll just 2027 * require the entire fb to accommodate that to avoid 2028 * potential runtime errors at plane configuration time. 2029 */ 2030 else if ((DISPLAY_VER(display) == 9 || display->platform.geminilake) && 2031 color_plane == 0 && fb->width > 3840) 2032 tile_width *= 4; 2033 } 2034 return tile_width; 2035 } 2036 2037 static int intel_plane_check_stride(const struct intel_plane_state *plane_state) 2038 { 2039 struct intel_display *display = to_intel_display(plane_state); 2040 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); 2041 const struct drm_framebuffer *fb = plane_state->hw.fb; 2042 unsigned int rotation = plane_state->hw.rotation; 2043 u32 stride, max_stride; 2044 2045 /* 2046 * We ignore stride for all invisible planes that 2047 * can be remapped. Otherwise we could end up 2048 * with a false positive when the remapping didn't 2049 * kick in due the plane being invisible. 2050 */ 2051 if (intel_plane_can_remap(plane_state) && 2052 !plane_state->uapi.visible) 2053 return 0; 2054 2055 /* FIXME other color planes? */ 2056 stride = plane_state->view.color_plane[0].mapping_stride; 2057 max_stride = plane->max_stride(plane, fb->format, 2058 fb->modifier, rotation); 2059 2060 if (stride > max_stride) { 2061 drm_dbg_kms(display->drm, 2062 "[FB:%d] stride (%d) exceeds [PLANE:%d:%s] max stride (%d)\n", 2063 fb->base.id, stride, 2064 plane->base.base.id, plane->base.name, max_stride); 2065 return -EINVAL; 2066 } 2067 2068 return 0; 2069 } 2070 2071 int intel_plane_compute_gtt(struct intel_plane_state *plane_state) 2072 { 2073 const struct intel_framebuffer *fb = 2074 to_intel_framebuffer(plane_state->hw.fb); 2075 unsigned int rotation = plane_state->hw.rotation; 2076 2077 if (!fb) 2078 return 0; 2079 2080 if (intel_plane_needs_remap(plane_state)) { 2081 intel_plane_remap_gtt(plane_state); 2082 2083 /* 2084 * Sometimes even remapping can't overcome 2085 * the stride limitations :( Can happen with 2086 * big plane sizes and suitably misaligned 2087 * offsets. 2088 */ 2089 return intel_plane_check_stride(plane_state); 2090 } 2091 2092 intel_fb_fill_view(fb, rotation, &plane_state->view); 2093 2094 /* Rotate src coordinates to match rotated GTT view */ 2095 if (drm_rotation_90_or_270(rotation)) 2096 drm_rect_rotate(&plane_state->uapi.src, 2097 fb->base.width << 16, fb->base.height << 16, 2098 DRM_MODE_ROTATE_270); 2099 2100 return intel_plane_check_stride(plane_state); 2101 } 2102 2103 static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) 2104 { 2105 struct intel_display *display = to_intel_display(fb->dev); 2106 struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); 2107 2108 drm_framebuffer_cleanup(fb); 2109 2110 if (intel_fb_uses_dpt(fb)) 2111 intel_parent_dpt_destroy(display, intel_fb->dpt); 2112 2113 intel_bo_framebuffer_fini(intel_fb_bo(fb)); 2114 2115 intel_parent_frontbuffer_put(display, intel_fb->frontbuffer); 2116 2117 kfree(intel_fb->panic); 2118 kfree(intel_fb); 2119 } 2120 2121 static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb, 2122 struct drm_file *file, 2123 unsigned int *handle) 2124 { 2125 struct drm_gem_object *obj = intel_fb_bo(fb); 2126 struct intel_display *display = to_intel_display(obj->dev); 2127 2128 if (intel_bo_is_userptr(obj)) { 2129 drm_dbg(display->drm, 2130 "attempting to use a userptr for a framebuffer, denied\n"); 2131 return -EINVAL; 2132 } 2133 2134 return drm_gem_handle_create(file, obj, handle); 2135 } 2136 2137 struct frontbuffer_fence_cb { 2138 struct dma_fence_cb base; 2139 struct intel_frontbuffer *front; 2140 }; 2141 2142 static void intel_user_framebuffer_fence_wake(struct dma_fence *dma, 2143 struct dma_fence_cb *data) 2144 { 2145 struct frontbuffer_fence_cb *cb = container_of(data, typeof(*cb), base); 2146 2147 intel_frontbuffer_queue_flush(cb->front); 2148 kfree(cb); 2149 dma_fence_put(dma); 2150 } 2151 2152 static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb, 2153 struct drm_file *file, 2154 unsigned int flags, unsigned int color, 2155 struct drm_clip_rect *clips, 2156 unsigned int num_clips) 2157 { 2158 struct drm_gem_object *obj = intel_fb_bo(fb); 2159 struct intel_frontbuffer *front = to_intel_frontbuffer(fb); 2160 struct dma_fence *fence; 2161 struct frontbuffer_fence_cb *cb; 2162 int ret = 0; 2163 2164 if (!atomic_read(&front->bits)) 2165 return 0; 2166 2167 if (dma_resv_test_signaled(obj->resv, dma_resv_usage_rw(false))) 2168 goto flush; 2169 2170 ret = dma_resv_get_singleton(obj->resv, dma_resv_usage_rw(false), 2171 &fence); 2172 if (ret || !fence) 2173 goto flush; 2174 2175 cb = kmalloc_obj(*cb); 2176 if (!cb) { 2177 dma_fence_put(fence); 2178 ret = -ENOMEM; 2179 goto flush; 2180 } 2181 2182 cb->front = front; 2183 2184 intel_frontbuffer_invalidate(front, ORIGIN_DIRTYFB); 2185 2186 ret = dma_fence_add_callback(fence, &cb->base, 2187 intel_user_framebuffer_fence_wake); 2188 if (ret) { 2189 intel_user_framebuffer_fence_wake(fence, &cb->base); 2190 if (ret == -ENOENT) 2191 ret = 0; 2192 } 2193 2194 return ret; 2195 2196 flush: 2197 intel_frontbuffer_flush(front, ORIGIN_DIRTYFB); 2198 return ret; 2199 } 2200 2201 static const struct drm_framebuffer_funcs intel_fb_funcs = { 2202 .destroy = intel_user_framebuffer_destroy, 2203 .create_handle = intel_user_framebuffer_create_handle, 2204 .dirty = intel_user_framebuffer_dirty, 2205 }; 2206 2207 int intel_framebuffer_init(struct intel_framebuffer *intel_fb, 2208 struct drm_gem_object *obj, 2209 const struct drm_format_info *info, 2210 struct drm_mode_fb_cmd2 *mode_cmd) 2211 { 2212 struct intel_display *display = to_intel_display(obj->dev); 2213 struct drm_framebuffer *fb = &intel_fb->base; 2214 u32 max_stride; 2215 int ret; 2216 int i; 2217 2218 intel_fb->panic = intel_parent_panic_alloc(display); 2219 if (!intel_fb->panic) 2220 return -ENOMEM; 2221 2222 /* 2223 * intel_parent_frontbuffer_get() must be done before 2224 * intel_bo_framebuffer_init() to avoid set_tiling vs. addfb race. 2225 */ 2226 intel_fb->frontbuffer = intel_parent_frontbuffer_get(display, obj); 2227 if (!intel_fb->frontbuffer) { 2228 ret = -ENOMEM; 2229 goto err_free_panic; 2230 } 2231 2232 ret = intel_bo_framebuffer_init(obj, mode_cmd); 2233 if (ret) 2234 goto err_frontbuffer_put; 2235 2236 if (!drm_any_plane_has_format(display->drm, 2237 mode_cmd->pixel_format, 2238 mode_cmd->modifier[0])) { 2239 drm_dbg_kms(display->drm, 2240 "unsupported pixel format %p4cc / modifier 0x%llx\n", 2241 &mode_cmd->pixel_format, mode_cmd->modifier[0]); 2242 ret = -EINVAL; 2243 goto err_bo_framebuffer_fini; 2244 } 2245 2246 max_stride = intel_fb_max_stride(display, info, mode_cmd->modifier[0]); 2247 if (mode_cmd->pitches[0] > max_stride) { 2248 drm_dbg_kms(display->drm, 2249 "%s pitch (%u) must be at most %d\n", 2250 mode_cmd->modifier[0] != DRM_FORMAT_MOD_LINEAR ? 2251 "tiled" : "linear", 2252 mode_cmd->pitches[0], max_stride); 2253 ret = -EINVAL; 2254 goto err_bo_framebuffer_fini; 2255 } 2256 2257 /* FIXME need to adjust LINOFF/TILEOFF accordingly. */ 2258 if (mode_cmd->offsets[0] != 0) { 2259 drm_dbg_kms(display->drm, 2260 "plane 0 offset (0x%08x) must be 0\n", 2261 mode_cmd->offsets[0]); 2262 ret = -EINVAL; 2263 goto err_bo_framebuffer_fini; 2264 } 2265 2266 drm_helper_mode_fill_fb_struct(display->drm, fb, info, mode_cmd); 2267 2268 for (i = 0; i < fb->format->num_planes; i++) { 2269 unsigned int stride_alignment; 2270 2271 if (mode_cmd->handles[i] != mode_cmd->handles[0]) { 2272 drm_dbg_kms(display->drm, "bad plane %d handle\n", i); 2273 ret = -EINVAL; 2274 goto err_bo_framebuffer_fini; 2275 } 2276 2277 stride_alignment = intel_fb_stride_alignment(fb, i); 2278 if (fb->pitches[i] & (stride_alignment - 1)) { 2279 drm_dbg_kms(display->drm, 2280 "plane %d pitch (%d) must be at least %u byte aligned\n", 2281 i, fb->pitches[i], stride_alignment); 2282 ret = -EINVAL; 2283 goto err_bo_framebuffer_fini; 2284 } 2285 2286 if (intel_fb_is_gen12_ccs_aux_plane(fb, i)) { 2287 unsigned int ccs_aux_stride = gen12_ccs_aux_stride(intel_fb, i); 2288 2289 if (fb->pitches[i] != ccs_aux_stride) { 2290 drm_dbg_kms(display->drm, 2291 "ccs aux plane %d pitch (%d) must be %d\n", 2292 i, fb->pitches[i], ccs_aux_stride); 2293 ret = -EINVAL; 2294 goto err_bo_framebuffer_fini; 2295 } 2296 } 2297 2298 fb->obj[i] = obj; 2299 } 2300 2301 ret = intel_fill_fb_info(display, intel_fb); 2302 if (ret) 2303 goto err_bo_framebuffer_fini; 2304 2305 if (intel_fb_uses_dpt(fb)) { 2306 struct drm_gem_object *obj = intel_fb_bo(&intel_fb->base); 2307 struct intel_dpt *dpt; 2308 size_t size = 0; 2309 2310 if (intel_fb_needs_pot_stride_remap(intel_fb)) 2311 size = intel_remapped_info_size(&intel_fb->remapped_view.gtt.remapped); 2312 2313 dpt = intel_parent_dpt_create(display, obj, size); 2314 if (IS_ERR(dpt)) { 2315 drm_dbg_kms(display->drm, "failed to create DPT\n"); 2316 ret = PTR_ERR(dpt); 2317 goto err_frontbuffer_put; 2318 } 2319 2320 intel_fb->dpt = dpt; 2321 } 2322 2323 ret = drm_framebuffer_init(display->drm, fb, &intel_fb_funcs); 2324 if (ret) { 2325 drm_err(display->drm, "framebuffer init failed %d\n", ret); 2326 goto err_free_dpt; 2327 } 2328 2329 return 0; 2330 2331 err_free_dpt: 2332 if (intel_fb_uses_dpt(fb)) 2333 intel_parent_dpt_destroy(display, intel_fb->dpt); 2334 err_bo_framebuffer_fini: 2335 intel_bo_framebuffer_fini(obj); 2336 err_frontbuffer_put: 2337 intel_parent_frontbuffer_put(display, intel_fb->frontbuffer); 2338 err_free_panic: 2339 kfree(intel_fb->panic); 2340 2341 return ret; 2342 } 2343 2344 struct drm_framebuffer * 2345 intel_user_framebuffer_create(struct drm_device *dev, 2346 struct drm_file *filp, 2347 const struct drm_format_info *info, 2348 const struct drm_mode_fb_cmd2 *user_mode_cmd) 2349 { 2350 struct intel_display *display = to_intel_display(dev); 2351 struct drm_framebuffer *fb; 2352 struct drm_gem_object *obj; 2353 struct drm_mode_fb_cmd2 mode_cmd = *user_mode_cmd; 2354 2355 obj = intel_bo_framebuffer_lookup(display, filp, &mode_cmd); 2356 if (IS_ERR(obj)) 2357 return ERR_CAST(obj); 2358 2359 fb = intel_framebuffer_create(obj, info, &mode_cmd); 2360 drm_gem_object_put(obj); 2361 2362 return fb; 2363 } 2364 2365 struct intel_framebuffer *intel_framebuffer_alloc(void) 2366 { 2367 struct intel_framebuffer *intel_fb; 2368 2369 intel_fb = kzalloc_obj(*intel_fb); 2370 if (!intel_fb) 2371 return NULL; 2372 2373 return intel_fb; 2374 } 2375 2376 struct drm_framebuffer * 2377 intel_framebuffer_create(struct drm_gem_object *obj, 2378 const struct drm_format_info *info, 2379 struct drm_mode_fb_cmd2 *mode_cmd) 2380 { 2381 struct intel_framebuffer *intel_fb; 2382 int ret; 2383 2384 intel_fb = intel_framebuffer_alloc(); 2385 if (!intel_fb) 2386 return ERR_PTR(-ENOMEM); 2387 2388 ret = intel_framebuffer_init(intel_fb, obj, info, mode_cmd); 2389 if (ret) 2390 goto err; 2391 2392 return &intel_fb->base; 2393 2394 err: 2395 kfree(intel_fb); 2396 return ERR_PTR(ret); 2397 } 2398 2399 struct drm_gem_object *intel_fb_bo(const struct drm_framebuffer *fb) 2400 { 2401 return fb ? fb->obj[0] : NULL; 2402 } 2403