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 C2_R_Cr, C0_G_Y, C1_B_Cb, 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 C1_B_Cb, C0_G_Y, C2_R_Cr, 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 INTERLEAVED_RGB_FMT_TILED(XBGR8888, 493 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 494 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, 495 false, 4, DPU_FORMAT_FLAG_COMPRESSED, 496 DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), 497 498 INTERLEAVED_RGB_FMT_TILED(ABGR2101010, 499 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 500 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, 501 true, 4, DPU_FORMAT_FLAG_DX | DPU_FORMAT_FLAG_COMPRESSED, 502 DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), 503 504 INTERLEAVED_RGB_FMT_TILED(XBGR2101010, 505 COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 506 C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, 507 true, 4, DPU_FORMAT_FLAG_DX | DPU_FORMAT_FLAG_COMPRESSED, 508 DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), 509 510 PSEUDO_YUV_FMT_TILED(NV12, 511 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, 512 C1_B_Cb, C2_R_Cr, 513 DPU_CHROMA_420, DPU_FORMAT_FLAG_YUV | 514 DPU_FORMAT_FLAG_COMPRESSED, 515 DPU_FETCH_UBWC, 4, DPU_TILE_HEIGHT_NV12), 516 }; 517 518 /* _dpu_get_v_h_subsample_rate - Get subsample rates for all formats we support 519 * Note: Not using the drm_format_*_subsampling since we have formats 520 */ 521 static void _dpu_get_v_h_subsample_rate( 522 enum dpu_chroma_samp_type chroma_sample, 523 uint32_t *v_sample, 524 uint32_t *h_sample) 525 { 526 if (!v_sample || !h_sample) 527 return; 528 529 switch (chroma_sample) { 530 case DPU_CHROMA_H2V1: 531 *v_sample = 1; 532 *h_sample = 2; 533 break; 534 case DPU_CHROMA_H1V2: 535 *v_sample = 2; 536 *h_sample = 1; 537 break; 538 case DPU_CHROMA_420: 539 *v_sample = 2; 540 *h_sample = 2; 541 break; 542 default: 543 *v_sample = 1; 544 *h_sample = 1; 545 break; 546 } 547 } 548 549 static int _dpu_format_get_media_color_ubwc(const struct dpu_format *fmt) 550 { 551 static const struct dpu_media_color_map dpu_media_ubwc_map[] = { 552 {DRM_FORMAT_ABGR8888, COLOR_FMT_RGBA8888_UBWC}, 553 {DRM_FORMAT_XBGR8888, COLOR_FMT_RGBA8888_UBWC}, 554 {DRM_FORMAT_ABGR2101010, COLOR_FMT_RGBA1010102_UBWC}, 555 {DRM_FORMAT_XBGR2101010, COLOR_FMT_RGBA1010102_UBWC}, 556 {DRM_FORMAT_BGR565, COLOR_FMT_RGB565_UBWC}, 557 }; 558 int color_fmt = -1; 559 int i; 560 561 if (fmt->base.pixel_format == DRM_FORMAT_NV12) { 562 if (DPU_FORMAT_IS_DX(fmt)) { 563 if (fmt->unpack_tight) 564 color_fmt = COLOR_FMT_NV12_BPP10_UBWC; 565 else 566 color_fmt = COLOR_FMT_P010_UBWC; 567 } else 568 color_fmt = COLOR_FMT_NV12_UBWC; 569 return color_fmt; 570 } 571 572 for (i = 0; i < ARRAY_SIZE(dpu_media_ubwc_map); ++i) 573 if (fmt->base.pixel_format == dpu_media_ubwc_map[i].format) { 574 color_fmt = dpu_media_ubwc_map[i].color; 575 break; 576 } 577 return color_fmt; 578 } 579 580 static int _dpu_format_get_plane_sizes_ubwc( 581 const struct dpu_format *fmt, 582 const uint32_t width, 583 const uint32_t height, 584 struct dpu_hw_fmt_layout *layout) 585 { 586 int i; 587 int color; 588 bool meta = DPU_FORMAT_IS_UBWC(fmt); 589 590 memset(layout, 0, sizeof(struct dpu_hw_fmt_layout)); 591 layout->format = fmt; 592 layout->width = width; 593 layout->height = height; 594 layout->num_planes = fmt->num_planes; 595 596 color = _dpu_format_get_media_color_ubwc(fmt); 597 if (color < 0) { 598 DRM_ERROR("UBWC format not supported for fmt: %4.4s\n", 599 (char *)&fmt->base.pixel_format); 600 return -EINVAL; 601 } 602 603 if (DPU_FORMAT_IS_YUV(layout->format)) { 604 uint32_t y_sclines, uv_sclines; 605 uint32_t y_meta_scanlines = 0; 606 uint32_t uv_meta_scanlines = 0; 607 608 layout->num_planes = 2; 609 layout->plane_pitch[0] = VENUS_Y_STRIDE(color, width); 610 y_sclines = VENUS_Y_SCANLINES(color, height); 611 layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] * 612 y_sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); 613 614 layout->plane_pitch[1] = VENUS_UV_STRIDE(color, width); 615 uv_sclines = VENUS_UV_SCANLINES(color, height); 616 layout->plane_size[1] = MSM_MEDIA_ALIGN(layout->plane_pitch[1] * 617 uv_sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); 618 619 if (!meta) 620 goto done; 621 622 layout->num_planes += 2; 623 layout->plane_pitch[2] = VENUS_Y_META_STRIDE(color, width); 624 y_meta_scanlines = VENUS_Y_META_SCANLINES(color, height); 625 layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] * 626 y_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); 627 628 layout->plane_pitch[3] = VENUS_UV_META_STRIDE(color, width); 629 uv_meta_scanlines = VENUS_UV_META_SCANLINES(color, height); 630 layout->plane_size[3] = MSM_MEDIA_ALIGN(layout->plane_pitch[3] * 631 uv_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); 632 633 } else { 634 uint32_t rgb_scanlines, rgb_meta_scanlines; 635 636 layout->num_planes = 1; 637 638 layout->plane_pitch[0] = VENUS_RGB_STRIDE(color, width); 639 rgb_scanlines = VENUS_RGB_SCANLINES(color, height); 640 layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] * 641 rgb_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); 642 643 if (!meta) 644 goto done; 645 layout->num_planes += 2; 646 layout->plane_pitch[2] = VENUS_RGB_META_STRIDE(color, width); 647 rgb_meta_scanlines = VENUS_RGB_META_SCANLINES(color, height); 648 layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] * 649 rgb_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); 650 } 651 652 done: 653 for (i = 0; i < DPU_MAX_PLANES; i++) 654 layout->total_size += layout->plane_size[i]; 655 656 return 0; 657 } 658 659 static int _dpu_format_get_plane_sizes_linear( 660 const struct dpu_format *fmt, 661 const uint32_t width, 662 const uint32_t height, 663 struct dpu_hw_fmt_layout *layout, 664 const uint32_t *pitches) 665 { 666 int i; 667 668 memset(layout, 0, sizeof(struct dpu_hw_fmt_layout)); 669 layout->format = fmt; 670 layout->width = width; 671 layout->height = height; 672 layout->num_planes = fmt->num_planes; 673 674 /* Due to memset above, only need to set planes of interest */ 675 if (fmt->fetch_planes == DPU_PLANE_INTERLEAVED) { 676 layout->num_planes = 1; 677 layout->plane_size[0] = width * height * layout->format->bpp; 678 layout->plane_pitch[0] = width * layout->format->bpp; 679 } else { 680 uint32_t v_subsample, h_subsample; 681 uint32_t chroma_samp; 682 uint32_t bpp = 1; 683 684 chroma_samp = fmt->chroma_sample; 685 _dpu_get_v_h_subsample_rate(chroma_samp, &v_subsample, 686 &h_subsample); 687 688 if (width % h_subsample || height % v_subsample) { 689 DRM_ERROR("mismatch in subsample vs dimensions\n"); 690 return -EINVAL; 691 } 692 693 if ((fmt->base.pixel_format == DRM_FORMAT_NV12) && 694 (DPU_FORMAT_IS_DX(fmt))) 695 bpp = 2; 696 layout->plane_pitch[0] = width * bpp; 697 layout->plane_pitch[1] = layout->plane_pitch[0] / h_subsample; 698 layout->plane_size[0] = layout->plane_pitch[0] * height; 699 layout->plane_size[1] = layout->plane_pitch[1] * 700 (height / v_subsample); 701 702 if (fmt->fetch_planes == DPU_PLANE_PSEUDO_PLANAR) { 703 layout->num_planes = 2; 704 layout->plane_size[1] *= 2; 705 layout->plane_pitch[1] *= 2; 706 } else { 707 /* planar */ 708 layout->num_planes = 3; 709 layout->plane_size[2] = layout->plane_size[1]; 710 layout->plane_pitch[2] = layout->plane_pitch[1]; 711 } 712 } 713 714 /* 715 * linear format: allow user allocated pitches if they are greater than 716 * the requirement. 717 * ubwc format: pitch values are computed uniformly across 718 * all the components based on ubwc specifications. 719 */ 720 for (i = 0; i < layout->num_planes && i < DPU_MAX_PLANES; ++i) { 721 if (pitches && layout->plane_pitch[i] < pitches[i]) 722 layout->plane_pitch[i] = pitches[i]; 723 } 724 725 for (i = 0; i < DPU_MAX_PLANES; i++) 726 layout->total_size += layout->plane_size[i]; 727 728 return 0; 729 } 730 731 static int dpu_format_get_plane_sizes( 732 const struct dpu_format *fmt, 733 const uint32_t w, 734 const uint32_t h, 735 struct dpu_hw_fmt_layout *layout, 736 const uint32_t *pitches) 737 { 738 if (!layout || !fmt) { 739 DRM_ERROR("invalid pointer\n"); 740 return -EINVAL; 741 } 742 743 if ((w > DPU_MAX_IMG_WIDTH) || (h > DPU_MAX_IMG_HEIGHT)) { 744 DRM_ERROR("image dimensions outside max range\n"); 745 return -ERANGE; 746 } 747 748 if (DPU_FORMAT_IS_UBWC(fmt) || DPU_FORMAT_IS_TILE(fmt)) 749 return _dpu_format_get_plane_sizes_ubwc(fmt, w, h, layout); 750 751 return _dpu_format_get_plane_sizes_linear(fmt, w, h, layout, pitches); 752 } 753 754 static int _dpu_format_populate_addrs_ubwc( 755 struct msm_gem_address_space *aspace, 756 struct drm_framebuffer *fb, 757 struct dpu_hw_fmt_layout *layout) 758 { 759 uint32_t base_addr = 0; 760 bool meta; 761 762 if (!fb || !layout) { 763 DRM_ERROR("invalid pointers\n"); 764 return -EINVAL; 765 } 766 767 if (aspace) 768 base_addr = msm_framebuffer_iova(fb, aspace, 0); 769 if (!base_addr) { 770 DRM_ERROR("failed to retrieve base addr\n"); 771 return -EFAULT; 772 } 773 774 meta = DPU_FORMAT_IS_UBWC(layout->format); 775 776 /* Per-format logic for verifying active planes */ 777 if (DPU_FORMAT_IS_YUV(layout->format)) { 778 /************************************************/ 779 /* UBWC ** */ 780 /* buffer ** DPU PLANE */ 781 /* format ** */ 782 /************************************************/ 783 /* ------------------- ** -------------------- */ 784 /* | Y meta | ** | Y bitstream | */ 785 /* | data | ** | plane | */ 786 /* ------------------- ** -------------------- */ 787 /* | Y bitstream | ** | CbCr bitstream | */ 788 /* | data | ** | plane | */ 789 /* ------------------- ** -------------------- */ 790 /* | Cbcr metadata | ** | Y meta | */ 791 /* | data | ** | plane | */ 792 /* ------------------- ** -------------------- */ 793 /* | CbCr bitstream | ** | CbCr meta | */ 794 /* | data | ** | plane | */ 795 /* ------------------- ** -------------------- */ 796 /************************************************/ 797 798 /* configure Y bitstream plane */ 799 layout->plane_addr[0] = base_addr + layout->plane_size[2]; 800 801 /* configure CbCr bitstream plane */ 802 layout->plane_addr[1] = base_addr + layout->plane_size[0] 803 + layout->plane_size[2] + layout->plane_size[3]; 804 805 if (!meta) 806 return 0; 807 808 /* configure Y metadata plane */ 809 layout->plane_addr[2] = base_addr; 810 811 /* configure CbCr metadata plane */ 812 layout->plane_addr[3] = base_addr + layout->plane_size[0] 813 + layout->plane_size[2]; 814 815 } else { 816 /************************************************/ 817 /* UBWC ** */ 818 /* buffer ** DPU PLANE */ 819 /* format ** */ 820 /************************************************/ 821 /* ------------------- ** -------------------- */ 822 /* | RGB meta | ** | RGB bitstream | */ 823 /* | data | ** | plane | */ 824 /* ------------------- ** -------------------- */ 825 /* | RGB bitstream | ** | NONE | */ 826 /* | data | ** | | */ 827 /* ------------------- ** -------------------- */ 828 /* ** | RGB meta | */ 829 /* ** | plane | */ 830 /* ** -------------------- */ 831 /************************************************/ 832 833 layout->plane_addr[0] = base_addr + layout->plane_size[2]; 834 layout->plane_addr[1] = 0; 835 836 if (!meta) 837 return 0; 838 839 layout->plane_addr[2] = base_addr; 840 layout->plane_addr[3] = 0; 841 } 842 return 0; 843 } 844 845 static int _dpu_format_populate_addrs_linear( 846 struct msm_gem_address_space *aspace, 847 struct drm_framebuffer *fb, 848 struct dpu_hw_fmt_layout *layout) 849 { 850 unsigned int i; 851 852 /* Can now check the pitches given vs pitches expected */ 853 for (i = 0; i < layout->num_planes; ++i) { 854 if (layout->plane_pitch[i] > fb->pitches[i]) { 855 DRM_ERROR("plane %u expected pitch %u, fb %u\n", 856 i, layout->plane_pitch[i], fb->pitches[i]); 857 return -EINVAL; 858 } 859 } 860 861 /* Populate addresses for simple formats here */ 862 for (i = 0; i < layout->num_planes; ++i) { 863 if (aspace) 864 layout->plane_addr[i] = 865 msm_framebuffer_iova(fb, aspace, i); 866 if (!layout->plane_addr[i]) { 867 DRM_ERROR("failed to retrieve base addr\n"); 868 return -EFAULT; 869 } 870 } 871 872 return 0; 873 } 874 875 int dpu_format_populate_layout( 876 struct msm_gem_address_space *aspace, 877 struct drm_framebuffer *fb, 878 struct dpu_hw_fmt_layout *layout) 879 { 880 uint32_t plane_addr[DPU_MAX_PLANES]; 881 int i, ret; 882 883 if (!fb || !layout) { 884 DRM_ERROR("invalid arguments\n"); 885 return -EINVAL; 886 } 887 888 if ((fb->width > DPU_MAX_IMG_WIDTH) || 889 (fb->height > DPU_MAX_IMG_HEIGHT)) { 890 DRM_ERROR("image dimensions outside max range\n"); 891 return -ERANGE; 892 } 893 894 layout->format = to_dpu_format(msm_framebuffer_format(fb)); 895 896 /* Populate the plane sizes etc via get_format */ 897 ret = dpu_format_get_plane_sizes(layout->format, fb->width, fb->height, 898 layout, fb->pitches); 899 if (ret) 900 return ret; 901 902 for (i = 0; i < DPU_MAX_PLANES; ++i) 903 plane_addr[i] = layout->plane_addr[i]; 904 905 /* Populate the addresses given the fb */ 906 if (DPU_FORMAT_IS_UBWC(layout->format) || 907 DPU_FORMAT_IS_TILE(layout->format)) 908 ret = _dpu_format_populate_addrs_ubwc(aspace, fb, layout); 909 else 910 ret = _dpu_format_populate_addrs_linear(aspace, fb, layout); 911 912 /* check if anything changed */ 913 if (!ret && !memcmp(plane_addr, layout->plane_addr, sizeof(plane_addr))) 914 ret = -EAGAIN; 915 916 return ret; 917 } 918 919 int dpu_format_check_modified_format( 920 const struct msm_kms *kms, 921 const struct msm_format *msm_fmt, 922 const struct drm_mode_fb_cmd2 *cmd, 923 struct drm_gem_object **bos) 924 { 925 const struct drm_format_info *info; 926 const struct dpu_format *fmt; 927 struct dpu_hw_fmt_layout layout; 928 uint32_t bos_total_size = 0; 929 int ret, i; 930 931 if (!msm_fmt || !cmd || !bos) { 932 DRM_ERROR("invalid arguments\n"); 933 return -EINVAL; 934 } 935 936 fmt = to_dpu_format(msm_fmt); 937 info = drm_format_info(fmt->base.pixel_format); 938 if (!info) 939 return -EINVAL; 940 941 ret = dpu_format_get_plane_sizes(fmt, cmd->width, cmd->height, 942 &layout, cmd->pitches); 943 if (ret) 944 return ret; 945 946 for (i = 0; i < info->num_planes; i++) { 947 if (!bos[i]) { 948 DRM_ERROR("invalid handle for plane %d\n", i); 949 return -EINVAL; 950 } 951 if ((i == 0) || (bos[i] != bos[0])) 952 bos_total_size += bos[i]->size; 953 } 954 955 if (bos_total_size < layout.total_size) { 956 DRM_ERROR("buffers total size too small %u expected %u\n", 957 bos_total_size, layout.total_size); 958 return -EINVAL; 959 } 960 961 return 0; 962 } 963 964 const struct dpu_format *dpu_get_dpu_format_ext( 965 const uint32_t format, 966 const uint64_t modifier) 967 { 968 uint32_t i = 0; 969 const struct dpu_format *fmt = NULL; 970 const struct dpu_format *map = NULL; 971 ssize_t map_size = 0; 972 973 /* 974 * Currently only support exactly zero or one modifier. 975 * All planes use the same modifier. 976 */ 977 DPU_DEBUG("plane format modifier 0x%llX\n", modifier); 978 979 switch (modifier) { 980 case 0: 981 map = dpu_format_map; 982 map_size = ARRAY_SIZE(dpu_format_map); 983 break; 984 case DRM_FORMAT_MOD_QCOM_COMPRESSED: 985 map = dpu_format_map_ubwc; 986 map_size = ARRAY_SIZE(dpu_format_map_ubwc); 987 DPU_DEBUG("found fmt: %4.4s DRM_FORMAT_MOD_QCOM_COMPRESSED\n", 988 (char *)&format); 989 break; 990 default: 991 DPU_ERROR("unsupported format modifier %llX\n", modifier); 992 return NULL; 993 } 994 995 for (i = 0; i < map_size; i++) { 996 if (format == map[i].base.pixel_format) { 997 fmt = &map[i]; 998 break; 999 } 1000 } 1001 1002 if (fmt == NULL) 1003 DPU_ERROR("unsupported fmt: %4.4s modifier 0x%llX\n", 1004 (char *)&format, modifier); 1005 else 1006 DPU_DEBUG("fmt %4.4s mod 0x%llX ubwc %d yuv %d\n", 1007 (char *)&format, modifier, 1008 DPU_FORMAT_IS_UBWC(fmt), 1009 DPU_FORMAT_IS_YUV(fmt)); 1010 1011 return fmt; 1012 } 1013 1014 const struct msm_format *dpu_get_msm_format( 1015 struct msm_kms *kms, 1016 const uint32_t format, 1017 const uint64_t modifiers) 1018 { 1019 const struct dpu_format *fmt = dpu_get_dpu_format_ext(format, 1020 modifiers); 1021 if (fmt) 1022 return &fmt->base; 1023 return NULL; 1024 } 1025