1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. 3 */ 4 5 #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ 6 7 #include <uapi/drm/drm_fourcc.h> 8 9 #include "msm_media_info.h" 10 #include "dpu_kms.h" 11 #include "dpu_formats.h" 12 13 #define DPU_UBWC_META_MACRO_W_H 16 14 #define DPU_UBWC_META_BLOCK_SIZE 256 15 #define DPU_UBWC_PLANE_SIZE_ALIGNMENT 4096 16 17 #define DPU_TILE_HEIGHT_DEFAULT 1 18 #define DPU_TILE_HEIGHT_TILED 4 19 #define DPU_TILE_HEIGHT_UBWC 4 20 #define DPU_TILE_HEIGHT_NV12 8 21 22 #define DPU_MAX_IMG_WIDTH 0x3FFF 23 #define DPU_MAX_IMG_HEIGHT 0x3FFF 24 25 /* 26 * DPU supported format packing, bpp, and other format 27 * information. 28 * DPU currently only supports interleaved RGB formats 29 * UBWC support for a pixel format is indicated by the flag, 30 * there is additional meta data plane for such formats 31 */ 32 33 #define INTERLEAVED_RGB_FMT(fmt, a, r, g, b, e0, e1, e2, e3, uc, alpha, \ 34 bp, flg, fm, np) \ 35 { \ 36 .base.pixel_format = DRM_FORMAT_ ## fmt, \ 37 .fetch_planes = DPU_PLANE_INTERLEAVED, \ 38 .alpha_enable = alpha, \ 39 .element = { (e0), (e1), (e2), (e3) }, \ 40 .bits = { g, b, r, a }, \ 41 .chroma_sample = DPU_CHROMA_RGB, \ 42 .unpack_align_msb = 0, \ 43 .unpack_tight = 1, \ 44 .unpack_count = uc, \ 45 .bpp = bp, \ 46 .fetch_mode = fm, \ 47 .flag = {(flg)}, \ 48 .num_planes = np, \ 49 .tile_height = DPU_TILE_HEIGHT_DEFAULT \ 50 } 51 52 #define INTERLEAVED_RGB_FMT_TILED(fmt, a, r, g, b, e0, e1, e2, e3, uc, \ 53 alpha, bp, flg, fm, np, th) \ 54 { \ 55 .base.pixel_format = DRM_FORMAT_ ## fmt, \ 56 .fetch_planes = DPU_PLANE_INTERLEAVED, \ 57 .alpha_enable = alpha, \ 58 .element = { (e0), (e1), (e2), (e3) }, \ 59 .bits = { g, b, r, a }, \ 60 .chroma_sample = DPU_CHROMA_RGB, \ 61 .unpack_align_msb = 0, \ 62 .unpack_tight = 1, \ 63 .unpack_count = uc, \ 64 .bpp = bp, \ 65 .fetch_mode = fm, \ 66 .flag = {(flg)}, \ 67 .num_planes = np, \ 68 .tile_height = th \ 69 } 70 71 72 #define INTERLEAVED_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, e3, \ 73 alpha, chroma, count, bp, flg, fm, np) \ 74 { \ 75 .base.pixel_format = DRM_FORMAT_ ## fmt, \ 76 .fetch_planes = DPU_PLANE_INTERLEAVED, \ 77 .alpha_enable = alpha, \ 78 .element = { (e0), (e1), (e2), (e3)}, \ 79 .bits = { g, b, r, a }, \ 80 .chroma_sample = chroma, \ 81 .unpack_align_msb = 0, \ 82 .unpack_tight = 1, \ 83 .unpack_count = count, \ 84 .bpp = bp, \ 85 .fetch_mode = fm, \ 86 .flag = {(flg)}, \ 87 .num_planes = np, \ 88 .tile_height = DPU_TILE_HEIGHT_DEFAULT \ 89 } 90 91 #define PSEUDO_YUV_FMT(fmt, a, r, g, b, e0, e1, chroma, flg, fm, np) \ 92 { \ 93 .base.pixel_format = DRM_FORMAT_ ## fmt, \ 94 .fetch_planes = DPU_PLANE_PSEUDO_PLANAR, \ 95 .alpha_enable = false, \ 96 .element = { (e0), (e1), 0, 0 }, \ 97 .bits = { g, b, r, a }, \ 98 .chroma_sample = chroma, \ 99 .unpack_align_msb = 0, \ 100 .unpack_tight = 1, \ 101 .unpack_count = 2, \ 102 .bpp = 2, \ 103 .fetch_mode = fm, \ 104 .flag = {(flg)}, \ 105 .num_planes = np, \ 106 .tile_height = DPU_TILE_HEIGHT_DEFAULT \ 107 } 108 109 #define PSEUDO_YUV_FMT_TILED(fmt, a, r, g, b, e0, e1, chroma, \ 110 flg, fm, np, th) \ 111 { \ 112 .base.pixel_format = DRM_FORMAT_ ## fmt, \ 113 .fetch_planes = DPU_PLANE_PSEUDO_PLANAR, \ 114 .alpha_enable = false, \ 115 .element = { (e0), (e1), 0, 0 }, \ 116 .bits = { g, b, r, a }, \ 117 .chroma_sample = chroma, \ 118 .unpack_align_msb = 0, \ 119 .unpack_tight = 1, \ 120 .unpack_count = 2, \ 121 .bpp = 2, \ 122 .fetch_mode = fm, \ 123 .flag = {(flg)}, \ 124 .num_planes = np, \ 125 .tile_height = th \ 126 } 127 128 #define PSEUDO_YUV_FMT_LOOSE(fmt, a, r, g, b, e0, e1, chroma, flg, fm, np)\ 129 { \ 130 .base.pixel_format = DRM_FORMAT_ ## fmt, \ 131 .fetch_planes = DPU_PLANE_PSEUDO_PLANAR, \ 132 .alpha_enable = false, \ 133 .element = { (e0), (e1), 0, 0 }, \ 134 .bits = { g, b, r, a }, \ 135 .chroma_sample = chroma, \ 136 .unpack_align_msb = 1, \ 137 .unpack_tight = 0, \ 138 .unpack_count = 2, \ 139 .bpp = 2, \ 140 .fetch_mode = fm, \ 141 .flag = {(flg)}, \ 142 .num_planes = np, \ 143 .tile_height = DPU_TILE_HEIGHT_DEFAULT \ 144 } 145 146 #define PSEUDO_YUV_FMT_LOOSE_TILED(fmt, a, r, g, b, e0, e1, chroma, \ 147 flg, fm, np, th) \ 148 { \ 149 .base.pixel_format = DRM_FORMAT_ ## fmt, \ 150 .fetch_planes = DPU_PLANE_PSEUDO_PLANAR, \ 151 .alpha_enable = false, \ 152 .element = { (e0), (e1), 0, 0 }, \ 153 .bits = { g, b, r, a }, \ 154 .chroma_sample = chroma, \ 155 .unpack_align_msb = 1, \ 156 .unpack_tight = 0, \ 157 .unpack_count = 2, \ 158 .bpp = 2, \ 159 .fetch_mode = fm, \ 160 .flag = {(flg)}, \ 161 .num_planes = np, \ 162 .tile_height = th \ 163 } 164 165 166 #define PLANAR_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, alpha, chroma, bp, \ 167 flg, fm, np) \ 168 { \ 169 .base.pixel_format = DRM_FORMAT_ ## fmt, \ 170 .fetch_planes = DPU_PLANE_PLANAR, \ 171 .alpha_enable = alpha, \ 172 .element = { (e0), (e1), (e2), 0 }, \ 173 .bits = { g, b, r, a }, \ 174 .chroma_sample = chroma, \ 175 .unpack_align_msb = 0, \ 176 .unpack_tight = 1, \ 177 .unpack_count = 1, \ 178 .bpp = bp, \ 179 .fetch_mode = fm, \ 180 .flag = {(flg)}, \ 181 .num_planes = np, \ 182 .tile_height = DPU_TILE_HEIGHT_DEFAULT \ 183 } 184 185 /* 186 * struct dpu_media_color_map - maps drm format to media format 187 * @format: DRM base pixel format 188 * @color: Media API color related to DRM format 189 */ 190 struct dpu_media_color_map { 191 uint32_t format; 192 uint32_t color; 193 }; 194 195 static const struct dpu_format dpu_format_map[] = { 196 INTERLEAVED_RGB_FMT(ARGB8888, 197 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 198 C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, 199 true, 4, 0, 200 DPU_FETCH_LINEAR, 1), 201 202 INTERLEAVED_RGB_FMT(ABGR8888, 203 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 204 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, 205 true, 4, 0, 206 DPU_FETCH_LINEAR, 1), 207 208 INTERLEAVED_RGB_FMT(XBGR8888, 209 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 210 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, 211 false, 4, 0, 212 DPU_FETCH_LINEAR, 1), 213 214 INTERLEAVED_RGB_FMT(RGBA8888, 215 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 216 C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, 217 true, 4, 0, 218 DPU_FETCH_LINEAR, 1), 219 220 INTERLEAVED_RGB_FMT(BGRA8888, 221 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 222 C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, 223 true, 4, 0, 224 DPU_FETCH_LINEAR, 1), 225 226 INTERLEAVED_RGB_FMT(BGRX8888, 227 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 228 C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, 229 false, 4, 0, 230 DPU_FETCH_LINEAR, 1), 231 232 INTERLEAVED_RGB_FMT(XRGB8888, 233 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 234 C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, 235 false, 4, 0, 236 DPU_FETCH_LINEAR, 1), 237 238 INTERLEAVED_RGB_FMT(RGBX8888, 239 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 240 C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, 241 false, 4, 0, 242 DPU_FETCH_LINEAR, 1), 243 244 INTERLEAVED_RGB_FMT(RGB888, 245 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 246 C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3, 247 false, 3, 0, 248 DPU_FETCH_LINEAR, 1), 249 250 INTERLEAVED_RGB_FMT(BGR888, 251 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 252 C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3, 253 false, 3, 0, 254 DPU_FETCH_LINEAR, 1), 255 256 INTERLEAVED_RGB_FMT(RGB565, 257 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT, 258 C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3, 259 false, 2, 0, 260 DPU_FETCH_LINEAR, 1), 261 262 INTERLEAVED_RGB_FMT(BGR565, 263 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT, 264 C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3, 265 false, 2, 0, 266 DPU_FETCH_LINEAR, 1), 267 268 INTERLEAVED_RGB_FMT(ARGB1555, 269 COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, 270 C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, 271 true, 2, 0, 272 DPU_FETCH_LINEAR, 1), 273 274 INTERLEAVED_RGB_FMT(ABGR1555, 275 COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, 276 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, 277 true, 2, 0, 278 DPU_FETCH_LINEAR, 1), 279 280 INTERLEAVED_RGB_FMT(RGBA5551, 281 COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, 282 C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, 283 true, 2, 0, 284 DPU_FETCH_LINEAR, 1), 285 286 INTERLEAVED_RGB_FMT(BGRA5551, 287 COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, 288 C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, 289 true, 2, 0, 290 DPU_FETCH_LINEAR, 1), 291 292 INTERLEAVED_RGB_FMT(XRGB1555, 293 COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, 294 C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, 295 false, 2, 0, 296 DPU_FETCH_LINEAR, 1), 297 298 INTERLEAVED_RGB_FMT(XBGR1555, 299 COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, 300 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, 301 false, 2, 0, 302 DPU_FETCH_LINEAR, 1), 303 304 INTERLEAVED_RGB_FMT(RGBX5551, 305 COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, 306 C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, 307 false, 2, 0, 308 DPU_FETCH_LINEAR, 1), 309 310 INTERLEAVED_RGB_FMT(BGRX5551, 311 COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, 312 C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, 313 false, 2, 0, 314 DPU_FETCH_LINEAR, 1), 315 316 INTERLEAVED_RGB_FMT(ARGB4444, 317 COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, 318 C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, 319 true, 2, 0, 320 DPU_FETCH_LINEAR, 1), 321 322 INTERLEAVED_RGB_FMT(ABGR4444, 323 COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, 324 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, 325 true, 2, 0, 326 DPU_FETCH_LINEAR, 1), 327 328 INTERLEAVED_RGB_FMT(RGBA4444, 329 COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, 330 C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, 331 true, 2, 0, 332 DPU_FETCH_LINEAR, 1), 333 334 INTERLEAVED_RGB_FMT(BGRA4444, 335 COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, 336 C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, 337 true, 2, 0, 338 DPU_FETCH_LINEAR, 1), 339 340 INTERLEAVED_RGB_FMT(XRGB4444, 341 COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, 342 C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, 343 false, 2, 0, 344 DPU_FETCH_LINEAR, 1), 345 346 INTERLEAVED_RGB_FMT(XBGR4444, 347 COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, 348 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, 349 false, 2, 0, 350 DPU_FETCH_LINEAR, 1), 351 352 INTERLEAVED_RGB_FMT(RGBX4444, 353 COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, 354 C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, 355 false, 2, 0, 356 DPU_FETCH_LINEAR, 1), 357 358 INTERLEAVED_RGB_FMT(BGRX4444, 359 COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, 360 C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, 361 false, 2, 0, 362 DPU_FETCH_LINEAR, 1), 363 364 INTERLEAVED_RGB_FMT(BGRA1010102, 365 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 366 C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, 367 true, 4, DPU_FORMAT_FLAG_DX, 368 DPU_FETCH_LINEAR, 1), 369 370 INTERLEAVED_RGB_FMT(RGBA1010102, 371 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 372 C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, 373 true, 4, DPU_FORMAT_FLAG_DX, 374 DPU_FETCH_LINEAR, 1), 375 376 INTERLEAVED_RGB_FMT(ABGR2101010, 377 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 378 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, 379 true, 4, DPU_FORMAT_FLAG_DX, 380 DPU_FETCH_LINEAR, 1), 381 382 INTERLEAVED_RGB_FMT(ARGB2101010, 383 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 384 C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, 385 true, 4, DPU_FORMAT_FLAG_DX, 386 DPU_FETCH_LINEAR, 1), 387 388 INTERLEAVED_RGB_FMT(XRGB2101010, 389 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 390 C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, 391 false, 4, DPU_FORMAT_FLAG_DX, 392 DPU_FETCH_LINEAR, 1), 393 394 INTERLEAVED_RGB_FMT(BGRX1010102, 395 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 396 C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, 397 false, 4, DPU_FORMAT_FLAG_DX, 398 DPU_FETCH_LINEAR, 1), 399 400 INTERLEAVED_RGB_FMT(XBGR2101010, 401 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 402 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, 403 false, 4, DPU_FORMAT_FLAG_DX, 404 DPU_FETCH_LINEAR, 1), 405 406 INTERLEAVED_RGB_FMT(RGBX1010102, 407 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 408 C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, 409 false, 4, DPU_FORMAT_FLAG_DX, 410 DPU_FETCH_LINEAR, 1), 411 412 PSEUDO_YUV_FMT(NV12, 413 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 414 C1_B_Cb, C2_R_Cr, 415 DPU_CHROMA_420, DPU_FORMAT_FLAG_YUV, 416 DPU_FETCH_LINEAR, 2), 417 418 PSEUDO_YUV_FMT(NV21, 419 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 420 C2_R_Cr, C1_B_Cb, 421 DPU_CHROMA_420, DPU_FORMAT_FLAG_YUV, 422 DPU_FETCH_LINEAR, 2), 423 424 PSEUDO_YUV_FMT(NV16, 425 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 426 C1_B_Cb, C2_R_Cr, 427 DPU_CHROMA_H2V1, DPU_FORMAT_FLAG_YUV, 428 DPU_FETCH_LINEAR, 2), 429 430 PSEUDO_YUV_FMT(NV61, 431 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 432 C2_R_Cr, C1_B_Cb, 433 DPU_CHROMA_H2V1, DPU_FORMAT_FLAG_YUV, 434 DPU_FETCH_LINEAR, 2), 435 436 INTERLEAVED_YUV_FMT(VYUY, 437 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 438 C2_R_Cr, C0_G_Y, C1_B_Cb, C0_G_Y, 439 false, DPU_CHROMA_H2V1, 4, 2, DPU_FORMAT_FLAG_YUV, 440 DPU_FETCH_LINEAR, 2), 441 442 INTERLEAVED_YUV_FMT(UYVY, 443 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 444 C1_B_Cb, C0_G_Y, C2_R_Cr, C0_G_Y, 445 false, DPU_CHROMA_H2V1, 4, 2, DPU_FORMAT_FLAG_YUV, 446 DPU_FETCH_LINEAR, 2), 447 448 INTERLEAVED_YUV_FMT(YUYV, 449 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 450 C0_G_Y, C1_B_Cb, C0_G_Y, C2_R_Cr, 451 false, DPU_CHROMA_H2V1, 4, 2, DPU_FORMAT_FLAG_YUV, 452 DPU_FETCH_LINEAR, 2), 453 454 INTERLEAVED_YUV_FMT(YVYU, 455 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 456 C0_G_Y, C2_R_Cr, C0_G_Y, C1_B_Cb, 457 false, DPU_CHROMA_H2V1, 4, 2, DPU_FORMAT_FLAG_YUV, 458 DPU_FETCH_LINEAR, 2), 459 460 PLANAR_YUV_FMT(YUV420, 461 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 462 C2_R_Cr, C1_B_Cb, C0_G_Y, 463 false, DPU_CHROMA_420, 1, DPU_FORMAT_FLAG_YUV, 464 DPU_FETCH_LINEAR, 3), 465 466 PLANAR_YUV_FMT(YVU420, 467 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 468 C1_B_Cb, C2_R_Cr, C0_G_Y, 469 false, DPU_CHROMA_420, 1, DPU_FORMAT_FLAG_YUV, 470 DPU_FETCH_LINEAR, 3), 471 }; 472 473 /* 474 * UBWC formats table: 475 * This table holds the UBWC formats supported. 476 * If a compression ratio needs to be used for this or any other format, 477 * the data will be passed by user-space. 478 */ 479 static const struct dpu_format dpu_format_map_ubwc[] = { 480 INTERLEAVED_RGB_FMT_TILED(BGR565, 481 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT, 482 C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3, 483 false, 2, DPU_FORMAT_FLAG_COMPRESSED, 484 DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), 485 486 INTERLEAVED_RGB_FMT_TILED(ABGR8888, 487 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 488 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, 489 true, 4, DPU_FORMAT_FLAG_COMPRESSED, 490 DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), 491 492 /* ARGB8888 and ABGR8888 purposely have the same color 493 * ordering. The hardware only supports ABGR8888 UBWC 494 * natively. 495 */ 496 INTERLEAVED_RGB_FMT_TILED(ARGB8888, 497 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 498 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, 499 true, 4, DPU_FORMAT_FLAG_COMPRESSED, 500 DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), 501 502 INTERLEAVED_RGB_FMT_TILED(XBGR8888, 503 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 504 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, 505 false, 4, DPU_FORMAT_FLAG_COMPRESSED, 506 DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), 507 508 INTERLEAVED_RGB_FMT_TILED(XRGB8888, 509 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 510 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, 511 false, 4, DPU_FORMAT_FLAG_COMPRESSED, 512 DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), 513 514 INTERLEAVED_RGB_FMT_TILED(ABGR2101010, 515 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 516 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, 517 true, 4, DPU_FORMAT_FLAG_DX | DPU_FORMAT_FLAG_COMPRESSED, 518 DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), 519 520 INTERLEAVED_RGB_FMT_TILED(XBGR2101010, 521 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 522 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, 523 true, 4, DPU_FORMAT_FLAG_DX | DPU_FORMAT_FLAG_COMPRESSED, 524 DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), 525 526 PSEUDO_YUV_FMT_TILED(NV12, 527 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 528 C1_B_Cb, C2_R_Cr, 529 DPU_CHROMA_420, DPU_FORMAT_FLAG_YUV | 530 DPU_FORMAT_FLAG_COMPRESSED, 531 DPU_FETCH_UBWC, 4, DPU_TILE_HEIGHT_NV12), 532 }; 533 534 /* _dpu_get_v_h_subsample_rate - Get subsample rates for all formats we support 535 * Note: Not using the drm_format_*_subsampling since we have formats 536 */ 537 static void _dpu_get_v_h_subsample_rate( 538 enum dpu_chroma_samp_type chroma_sample, 539 uint32_t *v_sample, 540 uint32_t *h_sample) 541 { 542 if (!v_sample || !h_sample) 543 return; 544 545 switch (chroma_sample) { 546 case DPU_CHROMA_H2V1: 547 *v_sample = 1; 548 *h_sample = 2; 549 break; 550 case DPU_CHROMA_H1V2: 551 *v_sample = 2; 552 *h_sample = 1; 553 break; 554 case DPU_CHROMA_420: 555 *v_sample = 2; 556 *h_sample = 2; 557 break; 558 default: 559 *v_sample = 1; 560 *h_sample = 1; 561 break; 562 } 563 } 564 565 static int _dpu_format_get_media_color_ubwc(const struct dpu_format *fmt) 566 { 567 static const struct dpu_media_color_map dpu_media_ubwc_map[] = { 568 {DRM_FORMAT_ABGR8888, COLOR_FMT_RGBA8888_UBWC}, 569 {DRM_FORMAT_ARGB8888, COLOR_FMT_RGBA8888_UBWC}, 570 {DRM_FORMAT_XBGR8888, COLOR_FMT_RGBA8888_UBWC}, 571 {DRM_FORMAT_XRGB8888, COLOR_FMT_RGBA8888_UBWC}, 572 {DRM_FORMAT_ABGR2101010, COLOR_FMT_RGBA1010102_UBWC}, 573 {DRM_FORMAT_XBGR2101010, COLOR_FMT_RGBA1010102_UBWC}, 574 {DRM_FORMAT_BGR565, COLOR_FMT_RGB565_UBWC}, 575 }; 576 int color_fmt = -1; 577 int i; 578 579 if (fmt->base.pixel_format == DRM_FORMAT_NV12) { 580 if (DPU_FORMAT_IS_DX(fmt)) { 581 if (fmt->unpack_tight) 582 color_fmt = COLOR_FMT_NV12_BPP10_UBWC; 583 else 584 color_fmt = COLOR_FMT_P010_UBWC; 585 } else 586 color_fmt = COLOR_FMT_NV12_UBWC; 587 return color_fmt; 588 } 589 590 for (i = 0; i < ARRAY_SIZE(dpu_media_ubwc_map); ++i) 591 if (fmt->base.pixel_format == dpu_media_ubwc_map[i].format) { 592 color_fmt = dpu_media_ubwc_map[i].color; 593 break; 594 } 595 return color_fmt; 596 } 597 598 static int _dpu_format_get_plane_sizes_ubwc( 599 const struct dpu_format *fmt, 600 const uint32_t width, 601 const uint32_t height, 602 struct dpu_hw_fmt_layout *layout) 603 { 604 int i; 605 int color; 606 bool meta = DPU_FORMAT_IS_UBWC(fmt); 607 608 memset(layout, 0, sizeof(struct dpu_hw_fmt_layout)); 609 layout->format = fmt; 610 layout->width = width; 611 layout->height = height; 612 layout->num_planes = fmt->num_planes; 613 614 color = _dpu_format_get_media_color_ubwc(fmt); 615 if (color < 0) { 616 DRM_ERROR("UBWC format not supported for fmt: %4.4s\n", 617 (char *)&fmt->base.pixel_format); 618 return -EINVAL; 619 } 620 621 if (DPU_FORMAT_IS_YUV(layout->format)) { 622 uint32_t y_sclines, uv_sclines; 623 uint32_t y_meta_scanlines = 0; 624 uint32_t uv_meta_scanlines = 0; 625 626 layout->num_planes = 2; 627 layout->plane_pitch[0] = VENUS_Y_STRIDE(color, width); 628 y_sclines = VENUS_Y_SCANLINES(color, height); 629 layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] * 630 y_sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); 631 632 layout->plane_pitch[1] = VENUS_UV_STRIDE(color, width); 633 uv_sclines = VENUS_UV_SCANLINES(color, height); 634 layout->plane_size[1] = MSM_MEDIA_ALIGN(layout->plane_pitch[1] * 635 uv_sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); 636 637 if (!meta) 638 goto done; 639 640 layout->num_planes += 2; 641 layout->plane_pitch[2] = VENUS_Y_META_STRIDE(color, width); 642 y_meta_scanlines = VENUS_Y_META_SCANLINES(color, height); 643 layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] * 644 y_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); 645 646 layout->plane_pitch[3] = VENUS_UV_META_STRIDE(color, width); 647 uv_meta_scanlines = VENUS_UV_META_SCANLINES(color, height); 648 layout->plane_size[3] = MSM_MEDIA_ALIGN(layout->plane_pitch[3] * 649 uv_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); 650 651 } else { 652 uint32_t rgb_scanlines, rgb_meta_scanlines; 653 654 layout->num_planes = 1; 655 656 layout->plane_pitch[0] = VENUS_RGB_STRIDE(color, width); 657 rgb_scanlines = VENUS_RGB_SCANLINES(color, height); 658 layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] * 659 rgb_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); 660 661 if (!meta) 662 goto done; 663 layout->num_planes += 2; 664 layout->plane_pitch[2] = VENUS_RGB_META_STRIDE(color, width); 665 rgb_meta_scanlines = VENUS_RGB_META_SCANLINES(color, height); 666 layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] * 667 rgb_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); 668 } 669 670 done: 671 for (i = 0; i < DPU_MAX_PLANES; i++) 672 layout->total_size += layout->plane_size[i]; 673 674 return 0; 675 } 676 677 static int _dpu_format_get_plane_sizes_linear( 678 const struct dpu_format *fmt, 679 const uint32_t width, 680 const uint32_t height, 681 struct dpu_hw_fmt_layout *layout, 682 const uint32_t *pitches) 683 { 684 int i; 685 686 memset(layout, 0, sizeof(struct dpu_hw_fmt_layout)); 687 layout->format = fmt; 688 layout->width = width; 689 layout->height = height; 690 layout->num_planes = fmt->num_planes; 691 692 /* Due to memset above, only need to set planes of interest */ 693 if (fmt->fetch_planes == DPU_PLANE_INTERLEAVED) { 694 layout->num_planes = 1; 695 layout->plane_size[0] = width * height * layout->format->bpp; 696 layout->plane_pitch[0] = width * layout->format->bpp; 697 } else { 698 uint32_t v_subsample, h_subsample; 699 uint32_t chroma_samp; 700 uint32_t bpp = 1; 701 702 chroma_samp = fmt->chroma_sample; 703 _dpu_get_v_h_subsample_rate(chroma_samp, &v_subsample, 704 &h_subsample); 705 706 if (width % h_subsample || height % v_subsample) { 707 DRM_ERROR("mismatch in subsample vs dimensions\n"); 708 return -EINVAL; 709 } 710 711 if ((fmt->base.pixel_format == DRM_FORMAT_NV12) && 712 (DPU_FORMAT_IS_DX(fmt))) 713 bpp = 2; 714 layout->plane_pitch[0] = width * bpp; 715 layout->plane_pitch[1] = layout->plane_pitch[0] / h_subsample; 716 layout->plane_size[0] = layout->plane_pitch[0] * height; 717 layout->plane_size[1] = layout->plane_pitch[1] * 718 (height / v_subsample); 719 720 if (fmt->fetch_planes == DPU_PLANE_PSEUDO_PLANAR) { 721 layout->num_planes = 2; 722 layout->plane_size[1] *= 2; 723 layout->plane_pitch[1] *= 2; 724 } else { 725 /* planar */ 726 layout->num_planes = 3; 727 layout->plane_size[2] = layout->plane_size[1]; 728 layout->plane_pitch[2] = layout->plane_pitch[1]; 729 } 730 } 731 732 /* 733 * linear format: allow user allocated pitches if they are greater than 734 * the requirement. 735 * ubwc format: pitch values are computed uniformly across 736 * all the components based on ubwc specifications. 737 */ 738 for (i = 0; i < layout->num_planes && i < DPU_MAX_PLANES; ++i) { 739 if (pitches && layout->plane_pitch[i] < pitches[i]) 740 layout->plane_pitch[i] = pitches[i]; 741 } 742 743 for (i = 0; i < DPU_MAX_PLANES; i++) 744 layout->total_size += layout->plane_size[i]; 745 746 return 0; 747 } 748 749 static int dpu_format_get_plane_sizes( 750 const struct dpu_format *fmt, 751 const uint32_t w, 752 const uint32_t h, 753 struct dpu_hw_fmt_layout *layout, 754 const uint32_t *pitches) 755 { 756 if (!layout || !fmt) { 757 DRM_ERROR("invalid pointer\n"); 758 return -EINVAL; 759 } 760 761 if ((w > DPU_MAX_IMG_WIDTH) || (h > DPU_MAX_IMG_HEIGHT)) { 762 DRM_ERROR("image dimensions outside max range\n"); 763 return -ERANGE; 764 } 765 766 if (DPU_FORMAT_IS_UBWC(fmt) || DPU_FORMAT_IS_TILE(fmt)) 767 return _dpu_format_get_plane_sizes_ubwc(fmt, w, h, layout); 768 769 return _dpu_format_get_plane_sizes_linear(fmt, w, h, layout, pitches); 770 } 771 772 static int _dpu_format_populate_addrs_ubwc( 773 struct msm_gem_address_space *aspace, 774 struct drm_framebuffer *fb, 775 struct dpu_hw_fmt_layout *layout) 776 { 777 uint32_t base_addr = 0; 778 bool meta; 779 780 if (!fb || !layout) { 781 DRM_ERROR("invalid pointers\n"); 782 return -EINVAL; 783 } 784 785 if (aspace) 786 base_addr = msm_framebuffer_iova(fb, aspace, 0); 787 if (!base_addr) { 788 DRM_ERROR("failed to retrieve base addr\n"); 789 return -EFAULT; 790 } 791 792 meta = DPU_FORMAT_IS_UBWC(layout->format); 793 794 /* Per-format logic for verifying active planes */ 795 if (DPU_FORMAT_IS_YUV(layout->format)) { 796 /************************************************/ 797 /* UBWC ** */ 798 /* buffer ** DPU PLANE */ 799 /* format ** */ 800 /************************************************/ 801 /* ------------------- ** -------------------- */ 802 /* | Y meta | ** | Y bitstream | */ 803 /* | data | ** | plane | */ 804 /* ------------------- ** -------------------- */ 805 /* | Y bitstream | ** | CbCr bitstream | */ 806 /* | data | ** | plane | */ 807 /* ------------------- ** -------------------- */ 808 /* | Cbcr metadata | ** | Y meta | */ 809 /* | data | ** | plane | */ 810 /* ------------------- ** -------------------- */ 811 /* | CbCr bitstream | ** | CbCr meta | */ 812 /* | data | ** | plane | */ 813 /* ------------------- ** -------------------- */ 814 /************************************************/ 815 816 /* configure Y bitstream plane */ 817 layout->plane_addr[0] = base_addr + layout->plane_size[2]; 818 819 /* configure CbCr bitstream plane */ 820 layout->plane_addr[1] = base_addr + layout->plane_size[0] 821 + layout->plane_size[2] + layout->plane_size[3]; 822 823 if (!meta) 824 return 0; 825 826 /* configure Y metadata plane */ 827 layout->plane_addr[2] = base_addr; 828 829 /* configure CbCr metadata plane */ 830 layout->plane_addr[3] = base_addr + layout->plane_size[0] 831 + layout->plane_size[2]; 832 833 } else { 834 /************************************************/ 835 /* UBWC ** */ 836 /* buffer ** DPU PLANE */ 837 /* format ** */ 838 /************************************************/ 839 /* ------------------- ** -------------------- */ 840 /* | RGB meta | ** | RGB bitstream | */ 841 /* | data | ** | plane | */ 842 /* ------------------- ** -------------------- */ 843 /* | RGB bitstream | ** | NONE | */ 844 /* | data | ** | | */ 845 /* ------------------- ** -------------------- */ 846 /* ** | RGB meta | */ 847 /* ** | plane | */ 848 /* ** -------------------- */ 849 /************************************************/ 850 851 layout->plane_addr[0] = base_addr + layout->plane_size[2]; 852 layout->plane_addr[1] = 0; 853 854 if (!meta) 855 return 0; 856 857 layout->plane_addr[2] = base_addr; 858 layout->plane_addr[3] = 0; 859 } 860 return 0; 861 } 862 863 static int _dpu_format_populate_addrs_linear( 864 struct msm_gem_address_space *aspace, 865 struct drm_framebuffer *fb, 866 struct dpu_hw_fmt_layout *layout) 867 { 868 unsigned int i; 869 870 /* Can now check the pitches given vs pitches expected */ 871 for (i = 0; i < layout->num_planes; ++i) { 872 if (layout->plane_pitch[i] > fb->pitches[i]) { 873 DRM_ERROR("plane %u expected pitch %u, fb %u\n", 874 i, layout->plane_pitch[i], fb->pitches[i]); 875 return -EINVAL; 876 } 877 } 878 879 /* Populate addresses for simple formats here */ 880 for (i = 0; i < layout->num_planes; ++i) { 881 if (aspace) 882 layout->plane_addr[i] = 883 msm_framebuffer_iova(fb, aspace, i); 884 if (!layout->plane_addr[i]) { 885 DRM_ERROR("failed to retrieve base addr\n"); 886 return -EFAULT; 887 } 888 } 889 890 return 0; 891 } 892 893 int dpu_format_populate_layout( 894 struct msm_gem_address_space *aspace, 895 struct drm_framebuffer *fb, 896 struct dpu_hw_fmt_layout *layout) 897 { 898 uint32_t plane_addr[DPU_MAX_PLANES]; 899 int i, ret; 900 901 if (!fb || !layout) { 902 DRM_ERROR("invalid arguments\n"); 903 return -EINVAL; 904 } 905 906 if ((fb->width > DPU_MAX_IMG_WIDTH) || 907 (fb->height > DPU_MAX_IMG_HEIGHT)) { 908 DRM_ERROR("image dimensions outside max range\n"); 909 return -ERANGE; 910 } 911 912 layout->format = to_dpu_format(msm_framebuffer_format(fb)); 913 914 /* Populate the plane sizes etc via get_format */ 915 ret = dpu_format_get_plane_sizes(layout->format, fb->width, fb->height, 916 layout, fb->pitches); 917 if (ret) 918 return ret; 919 920 for (i = 0; i < DPU_MAX_PLANES; ++i) 921 plane_addr[i] = layout->plane_addr[i]; 922 923 /* Populate the addresses given the fb */ 924 if (DPU_FORMAT_IS_UBWC(layout->format) || 925 DPU_FORMAT_IS_TILE(layout->format)) 926 ret = _dpu_format_populate_addrs_ubwc(aspace, fb, layout); 927 else 928 ret = _dpu_format_populate_addrs_linear(aspace, fb, layout); 929 930 /* check if anything changed */ 931 if (!ret && !memcmp(plane_addr, layout->plane_addr, sizeof(plane_addr))) 932 ret = -EAGAIN; 933 934 return ret; 935 } 936 937 int dpu_format_check_modified_format( 938 const struct msm_kms *kms, 939 const struct msm_format *msm_fmt, 940 const struct drm_mode_fb_cmd2 *cmd, 941 struct drm_gem_object **bos) 942 { 943 const struct drm_format_info *info; 944 const struct dpu_format *fmt; 945 struct dpu_hw_fmt_layout layout; 946 uint32_t bos_total_size = 0; 947 int ret, i; 948 949 if (!msm_fmt || !cmd || !bos) { 950 DRM_ERROR("invalid arguments\n"); 951 return -EINVAL; 952 } 953 954 fmt = to_dpu_format(msm_fmt); 955 info = drm_format_info(fmt->base.pixel_format); 956 if (!info) 957 return -EINVAL; 958 959 ret = dpu_format_get_plane_sizes(fmt, cmd->width, cmd->height, 960 &layout, cmd->pitches); 961 if (ret) 962 return ret; 963 964 for (i = 0; i < info->num_planes; i++) { 965 if (!bos[i]) { 966 DRM_ERROR("invalid handle for plane %d\n", i); 967 return -EINVAL; 968 } 969 if ((i == 0) || (bos[i] != bos[0])) 970 bos_total_size += bos[i]->size; 971 } 972 973 if (bos_total_size < layout.total_size) { 974 DRM_ERROR("buffers total size too small %u expected %u\n", 975 bos_total_size, layout.total_size); 976 return -EINVAL; 977 } 978 979 return 0; 980 } 981 982 const struct dpu_format *dpu_get_dpu_format_ext( 983 const uint32_t format, 984 const uint64_t modifier) 985 { 986 uint32_t i = 0; 987 const struct dpu_format *fmt = NULL; 988 const struct dpu_format *map = NULL; 989 ssize_t map_size = 0; 990 991 /* 992 * Currently only support exactly zero or one modifier. 993 * All planes use the same modifier. 994 */ 995 DRM_DEBUG_ATOMIC("plane format modifier 0x%llX\n", modifier); 996 997 switch (modifier) { 998 case 0: 999 map = dpu_format_map; 1000 map_size = ARRAY_SIZE(dpu_format_map); 1001 break; 1002 case DRM_FORMAT_MOD_QCOM_COMPRESSED: 1003 map = dpu_format_map_ubwc; 1004 map_size = ARRAY_SIZE(dpu_format_map_ubwc); 1005 DRM_DEBUG_ATOMIC("found fmt: %4.4s DRM_FORMAT_MOD_QCOM_COMPRESSED\n", 1006 (char *)&format); 1007 break; 1008 default: 1009 DPU_ERROR("unsupported format modifier %llX\n", modifier); 1010 return NULL; 1011 } 1012 1013 for (i = 0; i < map_size; i++) { 1014 if (format == map[i].base.pixel_format) { 1015 fmt = &map[i]; 1016 break; 1017 } 1018 } 1019 1020 if (fmt == NULL) 1021 DPU_ERROR("unsupported fmt: %4.4s modifier 0x%llX\n", 1022 (char *)&format, modifier); 1023 else 1024 DRM_DEBUG_ATOMIC("fmt %4.4s mod 0x%llX ubwc %d yuv %d\n", 1025 (char *)&format, modifier, 1026 DPU_FORMAT_IS_UBWC(fmt), 1027 DPU_FORMAT_IS_YUV(fmt)); 1028 1029 return fmt; 1030 } 1031 1032 const struct msm_format *dpu_get_msm_format( 1033 struct msm_kms *kms, 1034 const uint32_t format, 1035 const uint64_t modifiers) 1036 { 1037 const struct dpu_format *fmt = dpu_get_dpu_format_ext(format, 1038 modifiers); 1039 if (fmt) 1040 return &fmt->base; 1041 return NULL; 1042 } 1043