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