1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2022 MediaTek Inc. 4 * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com> 5 */ 6 7 #include <media/v4l2-common.h> 8 #include <media/videobuf2-v4l2.h> 9 #include <media/videobuf2-dma-contig.h> 10 #include "mtk-mdp3-core.h" 11 #include "mtk-mdp3-regs.h" 12 #include "mtk-mdp3-m2m.h" 13 14 /* 15 * All 10-bit related formats are not added in the basic format list, 16 * please add the corresponding format settings before use. 17 */ 18 static const struct mdp_format mdp_formats[] = { 19 { 20 .pixelformat = V4L2_PIX_FMT_GREY, 21 .mdp_color = MDP_COLOR_GREY, 22 .depth = { 8 }, 23 .row_depth = { 8 }, 24 .num_planes = 1, 25 .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, 26 }, { 27 .pixelformat = V4L2_PIX_FMT_RGB565X, 28 .mdp_color = MDP_COLOR_BGR565, 29 .depth = { 16 }, 30 .row_depth = { 16 }, 31 .num_planes = 1, 32 .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, 33 }, { 34 .pixelformat = V4L2_PIX_FMT_RGB565, 35 .mdp_color = MDP_COLOR_RGB565, 36 .depth = { 16 }, 37 .row_depth = { 16 }, 38 .num_planes = 1, 39 .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, 40 }, { 41 .pixelformat = V4L2_PIX_FMT_RGB24, 42 .mdp_color = MDP_COLOR_RGB888, 43 .depth = { 24 }, 44 .row_depth = { 24 }, 45 .num_planes = 1, 46 .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, 47 }, { 48 .pixelformat = V4L2_PIX_FMT_BGR24, 49 .mdp_color = MDP_COLOR_BGR888, 50 .depth = { 24 }, 51 .row_depth = { 24 }, 52 .num_planes = 1, 53 .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, 54 }, { 55 .pixelformat = V4L2_PIX_FMT_ABGR32, 56 .mdp_color = MDP_COLOR_BGRA8888, 57 .depth = { 32 }, 58 .row_depth = { 32 }, 59 .num_planes = 1, 60 .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, 61 }, { 62 .pixelformat = V4L2_PIX_FMT_ARGB32, 63 .mdp_color = MDP_COLOR_ARGB8888, 64 .depth = { 32 }, 65 .row_depth = { 32 }, 66 .num_planes = 1, 67 .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, 68 }, { 69 .pixelformat = V4L2_PIX_FMT_UYVY, 70 .mdp_color = MDP_COLOR_UYVY, 71 .depth = { 16 }, 72 .row_depth = { 16 }, 73 .num_planes = 1, 74 .walign = 1, 75 .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, 76 }, { 77 .pixelformat = V4L2_PIX_FMT_VYUY, 78 .mdp_color = MDP_COLOR_VYUY, 79 .depth = { 16 }, 80 .row_depth = { 16 }, 81 .num_planes = 1, 82 .walign = 1, 83 .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, 84 }, { 85 .pixelformat = V4L2_PIX_FMT_YUYV, 86 .mdp_color = MDP_COLOR_YUYV, 87 .depth = { 16 }, 88 .row_depth = { 16 }, 89 .num_planes = 1, 90 .walign = 1, 91 .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, 92 }, { 93 .pixelformat = V4L2_PIX_FMT_YVYU, 94 .mdp_color = MDP_COLOR_YVYU, 95 .depth = { 16 }, 96 .row_depth = { 16 }, 97 .num_planes = 1, 98 .walign = 1, 99 .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, 100 }, { 101 .pixelformat = V4L2_PIX_FMT_YUV420, 102 .mdp_color = MDP_COLOR_I420, 103 .depth = { 12 }, 104 .row_depth = { 8 }, 105 .num_planes = 1, 106 .walign = 1, 107 .halign = 1, 108 .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, 109 }, { 110 .pixelformat = V4L2_PIX_FMT_YVU420, 111 .mdp_color = MDP_COLOR_YV12, 112 .depth = { 12 }, 113 .row_depth = { 8 }, 114 .num_planes = 1, 115 .walign = 1, 116 .halign = 1, 117 .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, 118 }, { 119 .pixelformat = V4L2_PIX_FMT_NV12, 120 .mdp_color = MDP_COLOR_NV12, 121 .depth = { 12 }, 122 .row_depth = { 8 }, 123 .num_planes = 1, 124 .walign = 1, 125 .halign = 1, 126 .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, 127 }, { 128 .pixelformat = V4L2_PIX_FMT_NV21, 129 .mdp_color = MDP_COLOR_NV21, 130 .depth = { 12 }, 131 .row_depth = { 8 }, 132 .num_planes = 1, 133 .walign = 1, 134 .halign = 1, 135 .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, 136 }, { 137 .pixelformat = V4L2_PIX_FMT_NV16, 138 .mdp_color = MDP_COLOR_NV16, 139 .depth = { 16 }, 140 .row_depth = { 8 }, 141 .num_planes = 1, 142 .walign = 1, 143 .flags = MDP_FMT_FLAG_OUTPUT, 144 }, { 145 .pixelformat = V4L2_PIX_FMT_NV61, 146 .mdp_color = MDP_COLOR_NV61, 147 .depth = { 16 }, 148 .row_depth = { 8 }, 149 .num_planes = 1, 150 .walign = 1, 151 .flags = MDP_FMT_FLAG_OUTPUT, 152 }, { 153 .pixelformat = V4L2_PIX_FMT_NV24, 154 .mdp_color = MDP_COLOR_NV24, 155 .depth = { 24 }, 156 .row_depth = { 8 }, 157 .num_planes = 1, 158 .flags = MDP_FMT_FLAG_OUTPUT, 159 }, { 160 .pixelformat = V4L2_PIX_FMT_NV42, 161 .mdp_color = MDP_COLOR_NV42, 162 .depth = { 24 }, 163 .row_depth = { 8 }, 164 .num_planes = 1, 165 .flags = MDP_FMT_FLAG_OUTPUT, 166 }, { 167 .pixelformat = V4L2_PIX_FMT_MT21C, 168 .mdp_color = MDP_COLOR_420_BLK_UFO, 169 .depth = { 8, 4 }, 170 .row_depth = { 8, 8 }, 171 .num_planes = 2, 172 .walign = 4, 173 .halign = 5, 174 .flags = MDP_FMT_FLAG_OUTPUT, 175 }, { 176 .pixelformat = V4L2_PIX_FMT_MM21, 177 .mdp_color = MDP_COLOR_420_BLK, 178 .depth = { 8, 4 }, 179 .row_depth = { 8, 8 }, 180 .num_planes = 2, 181 .walign = 4, 182 .halign = 5, 183 .flags = MDP_FMT_FLAG_OUTPUT, 184 }, { 185 .pixelformat = V4L2_PIX_FMT_NV12M, 186 .mdp_color = MDP_COLOR_NV12, 187 .depth = { 8, 4 }, 188 .row_depth = { 8, 8 }, 189 .num_planes = 2, 190 .walign = 1, 191 .halign = 1, 192 .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, 193 }, { 194 .pixelformat = V4L2_PIX_FMT_NV21M, 195 .mdp_color = MDP_COLOR_NV21, 196 .depth = { 8, 4 }, 197 .row_depth = { 8, 8 }, 198 .num_planes = 2, 199 .walign = 1, 200 .halign = 1, 201 .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, 202 }, { 203 .pixelformat = V4L2_PIX_FMT_NV16M, 204 .mdp_color = MDP_COLOR_NV16, 205 .depth = { 8, 8 }, 206 .row_depth = { 8, 8 }, 207 .num_planes = 2, 208 .walign = 1, 209 .flags = MDP_FMT_FLAG_OUTPUT, 210 }, { 211 .pixelformat = V4L2_PIX_FMT_NV61M, 212 .mdp_color = MDP_COLOR_NV61, 213 .depth = { 8, 8 }, 214 .row_depth = { 8, 8 }, 215 .num_planes = 2, 216 .walign = 1, 217 .flags = MDP_FMT_FLAG_OUTPUT, 218 }, { 219 .pixelformat = V4L2_PIX_FMT_YUV420M, 220 .mdp_color = MDP_COLOR_I420, 221 .depth = { 8, 2, 2 }, 222 .row_depth = { 8, 4, 4 }, 223 .num_planes = 3, 224 .walign = 1, 225 .halign = 1, 226 .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, 227 }, { 228 .pixelformat = V4L2_PIX_FMT_YVU420M, 229 .mdp_color = MDP_COLOR_YV12, 230 .depth = { 8, 2, 2 }, 231 .row_depth = { 8, 4, 4 }, 232 .num_planes = 3, 233 .walign = 1, 234 .halign = 1, 235 .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, 236 } 237 }; 238 239 static const struct mdp_limit mdp_def_limit = { 240 .out_limit = { 241 .wmin = 16, 242 .hmin = 16, 243 .wmax = 8176, 244 .hmax = 8176, 245 }, 246 .cap_limit = { 247 .wmin = 2, 248 .hmin = 2, 249 .wmax = 8176, 250 .hmax = 8176, 251 }, 252 .h_scale_up_max = 32, 253 .v_scale_up_max = 32, 254 .h_scale_down_max = 20, 255 .v_scale_down_max = 128, 256 }; 257 258 static const struct mdp_format *mdp_find_fmt(u32 pixelformat, u32 type) 259 { 260 u32 i, flag; 261 262 flag = V4L2_TYPE_IS_OUTPUT(type) ? MDP_FMT_FLAG_OUTPUT : 263 MDP_FMT_FLAG_CAPTURE; 264 for (i = 0; i < ARRAY_SIZE(mdp_formats); ++i) { 265 if (!(mdp_formats[i].flags & flag)) 266 continue; 267 if (mdp_formats[i].pixelformat == pixelformat) 268 return &mdp_formats[i]; 269 } 270 return NULL; 271 } 272 273 static const struct mdp_format *mdp_find_fmt_by_index(u32 index, u32 type) 274 { 275 u32 i, flag, num = 0; 276 277 flag = V4L2_TYPE_IS_OUTPUT(type) ? MDP_FMT_FLAG_OUTPUT : 278 MDP_FMT_FLAG_CAPTURE; 279 for (i = 0; i < ARRAY_SIZE(mdp_formats); ++i) { 280 if (!(mdp_formats[i].flags & flag)) 281 continue; 282 if (index == num) 283 return &mdp_formats[i]; 284 num++; 285 } 286 return NULL; 287 } 288 289 enum mdp_ycbcr_profile mdp_map_ycbcr_prof_mplane(struct v4l2_format *f, 290 u32 mdp_color) 291 { 292 struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; 293 294 if (MDP_COLOR_IS_RGB(mdp_color)) 295 return MDP_YCBCR_PROFILE_FULL_BT601; 296 297 switch (pix_mp->colorspace) { 298 case V4L2_COLORSPACE_JPEG: 299 return MDP_YCBCR_PROFILE_JPEG; 300 case V4L2_COLORSPACE_REC709: 301 case V4L2_COLORSPACE_DCI_P3: 302 if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE) 303 return MDP_YCBCR_PROFILE_FULL_BT709; 304 return MDP_YCBCR_PROFILE_BT709; 305 case V4L2_COLORSPACE_BT2020: 306 if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE) 307 return MDP_YCBCR_PROFILE_FULL_BT2020; 308 return MDP_YCBCR_PROFILE_BT2020; 309 default: 310 if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE) 311 return MDP_YCBCR_PROFILE_FULL_BT601; 312 return MDP_YCBCR_PROFILE_BT601; 313 } 314 } 315 316 static void mdp_bound_align_image(u32 *w, u32 *h, 317 struct v4l2_frmsize_stepwise *s, 318 unsigned int salign) 319 { 320 unsigned int org_w, org_h; 321 322 org_w = *w; 323 org_h = *h; 324 v4l_bound_align_image(w, s->min_width, s->max_width, s->step_width, 325 h, s->min_height, s->max_height, s->step_height, 326 salign); 327 328 s->min_width = org_w; 329 s->min_height = org_h; 330 v4l2_apply_frmsize_constraints(w, h, s); 331 } 332 333 static int mdp_clamp_align(s32 *x, int min, int max, unsigned int align) 334 { 335 unsigned int mask; 336 337 if (min < 0 || max < 0) 338 return -ERANGE; 339 340 /* Bits that must be zero to be aligned */ 341 mask = ~((1 << align) - 1); 342 343 min = 0 ? 0 : ((min + ~mask) & mask); 344 max = max & mask; 345 if ((unsigned int)min > (unsigned int)max) 346 return -ERANGE; 347 348 /* Clamp to aligned min and max */ 349 *x = clamp(*x, min, max); 350 351 /* Round to nearest aligned value */ 352 if (align) 353 *x = (*x + (1 << (align - 1))) & mask; 354 return 0; 355 } 356 357 int mdp_enum_fmt_mplane(struct v4l2_fmtdesc *f) 358 { 359 const struct mdp_format *fmt; 360 361 fmt = mdp_find_fmt_by_index(f->index, f->type); 362 if (!fmt) 363 return -EINVAL; 364 365 f->pixelformat = fmt->pixelformat; 366 return 0; 367 } 368 369 const struct mdp_format *mdp_try_fmt_mplane(struct v4l2_format *f, 370 struct mdp_frameparam *param, 371 u32 ctx_id) 372 { 373 struct device *dev = ¶m->ctx->mdp_dev->pdev->dev; 374 struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; 375 const struct mdp_format *fmt; 376 const struct mdp_pix_limit *pix_limit; 377 struct v4l2_frmsize_stepwise s; 378 u32 org_w, org_h; 379 unsigned int i; 380 381 fmt = mdp_find_fmt(pix_mp->pixelformat, f->type); 382 if (!fmt) { 383 fmt = mdp_find_fmt_by_index(0, f->type); 384 if (!fmt) { 385 dev_dbg(dev, "%d: pixelformat %c%c%c%c invalid", ctx_id, 386 (pix_mp->pixelformat & 0xff), 387 (pix_mp->pixelformat >> 8) & 0xff, 388 (pix_mp->pixelformat >> 16) & 0xff, 389 (pix_mp->pixelformat >> 24) & 0xff); 390 return NULL; 391 } 392 } 393 394 pix_mp->field = V4L2_FIELD_NONE; 395 pix_mp->flags = 0; 396 pix_mp->pixelformat = fmt->pixelformat; 397 if (V4L2_TYPE_IS_CAPTURE(f->type)) { 398 pix_mp->colorspace = param->colorspace; 399 pix_mp->xfer_func = param->xfer_func; 400 pix_mp->ycbcr_enc = param->ycbcr_enc; 401 pix_mp->quantization = param->quant; 402 } 403 404 pix_limit = V4L2_TYPE_IS_OUTPUT(f->type) ? ¶m->limit->out_limit : 405 ¶m->limit->cap_limit; 406 s.min_width = pix_limit->wmin; 407 s.max_width = pix_limit->wmax; 408 s.step_width = fmt->walign; 409 s.min_height = pix_limit->hmin; 410 s.max_height = pix_limit->hmax; 411 s.step_height = fmt->halign; 412 org_w = pix_mp->width; 413 org_h = pix_mp->height; 414 415 mdp_bound_align_image(&pix_mp->width, &pix_mp->height, &s, fmt->salign); 416 if (org_w != pix_mp->width || org_h != pix_mp->height) 417 dev_dbg(dev, "%d: size change: %ux%u to %ux%u", ctx_id, 418 org_w, org_h, pix_mp->width, pix_mp->height); 419 420 if (pix_mp->num_planes && pix_mp->num_planes != fmt->num_planes) 421 dev_dbg(dev, "%d num of planes change: %u to %u", ctx_id, 422 pix_mp->num_planes, fmt->num_planes); 423 pix_mp->num_planes = fmt->num_planes; 424 425 for (i = 0; i < pix_mp->num_planes; ++i) { 426 u32 min_bpl = (pix_mp->width * fmt->row_depth[i]) >> 3; 427 u32 max_bpl = (pix_limit->wmax * fmt->row_depth[i]) >> 3; 428 u32 bpl = pix_mp->plane_fmt[i].bytesperline; 429 u32 min_si, max_si; 430 u32 si = pix_mp->plane_fmt[i].sizeimage; 431 432 bpl = clamp(bpl, min_bpl, max_bpl); 433 pix_mp->plane_fmt[i].bytesperline = bpl; 434 435 min_si = (bpl * pix_mp->height * fmt->depth[i]) / 436 fmt->row_depth[i]; 437 max_si = (bpl * s.max_height * fmt->depth[i]) / 438 fmt->row_depth[i]; 439 440 si = clamp(si, min_si, max_si); 441 pix_mp->plane_fmt[i].sizeimage = si; 442 443 dev_dbg(dev, "%d: p%u, bpl:%u [%u, %u], sizeimage:%u [%u, %u]", 444 ctx_id, i, bpl, min_bpl, max_bpl, si, min_si, max_si); 445 } 446 447 return fmt; 448 } 449 450 static int mdp_clamp_start(s32 *x, int min, int max, unsigned int align, 451 u32 flags) 452 { 453 if (flags & V4L2_SEL_FLAG_GE) 454 max = *x; 455 if (flags & V4L2_SEL_FLAG_LE) 456 min = *x; 457 return mdp_clamp_align(x, min, max, align); 458 } 459 460 static int mdp_clamp_end(s32 *x, int min, int max, unsigned int align, 461 u32 flags) 462 { 463 if (flags & V4L2_SEL_FLAG_GE) 464 min = *x; 465 if (flags & V4L2_SEL_FLAG_LE) 466 max = *x; 467 return mdp_clamp_align(x, min, max, align); 468 } 469 470 int mdp_try_crop(struct mdp_m2m_ctx *ctx, struct v4l2_rect *r, 471 const struct v4l2_selection *s, struct mdp_frame *frame) 472 { 473 struct device *dev = &ctx->mdp_dev->pdev->dev; 474 s32 left, top, right, bottom; 475 u32 framew, frameh, walign, halign; 476 int ret; 477 478 dev_dbg(dev, "%d target:%d, set:(%d,%d) %ux%u", ctx->id, 479 s->target, s->r.left, s->r.top, s->r.width, s->r.height); 480 481 left = s->r.left; 482 top = s->r.top; 483 right = s->r.left + s->r.width; 484 bottom = s->r.top + s->r.height; 485 framew = frame->format.fmt.pix_mp.width; 486 frameh = frame->format.fmt.pix_mp.height; 487 488 if (mdp_target_is_crop(s->target)) { 489 walign = 1; 490 halign = 1; 491 } else { 492 walign = frame->mdp_fmt->walign; 493 halign = frame->mdp_fmt->halign; 494 } 495 496 dev_dbg(dev, "%d align:%u,%u, bound:%ux%u", ctx->id, 497 walign, halign, framew, frameh); 498 499 ret = mdp_clamp_start(&left, 0, right, walign, s->flags); 500 if (ret) 501 return ret; 502 ret = mdp_clamp_start(&top, 0, bottom, halign, s->flags); 503 if (ret) 504 return ret; 505 ret = mdp_clamp_end(&right, left, framew, walign, s->flags); 506 if (ret) 507 return ret; 508 ret = mdp_clamp_end(&bottom, top, frameh, halign, s->flags); 509 if (ret) 510 return ret; 511 512 r->left = left; 513 r->top = top; 514 r->width = right - left; 515 r->height = bottom - top; 516 517 dev_dbg(dev, "%d crop:(%d,%d) %ux%u", ctx->id, 518 r->left, r->top, r->width, r->height); 519 return 0; 520 } 521 522 int mdp_check_scaling_ratio(const struct v4l2_rect *crop, 523 const struct v4l2_rect *compose, s32 rotation, 524 const struct mdp_limit *limit) 525 { 526 u32 crop_w, crop_h, comp_w, comp_h; 527 528 crop_w = crop->width; 529 crop_h = crop->height; 530 if (90 == rotation || 270 == rotation) { 531 comp_w = compose->height; 532 comp_h = compose->width; 533 } else { 534 comp_w = compose->width; 535 comp_h = compose->height; 536 } 537 538 if ((crop_w / comp_w) > limit->h_scale_down_max || 539 (crop_h / comp_h) > limit->v_scale_down_max || 540 (comp_w / crop_w) > limit->h_scale_up_max || 541 (comp_h / crop_h) > limit->v_scale_up_max) 542 return -ERANGE; 543 return 0; 544 } 545 546 /* Stride that is accepted by MDP HW */ 547 static u32 mdp_fmt_get_stride(const struct mdp_format *fmt, 548 u32 bytesperline, unsigned int plane) 549 { 550 enum mdp_color c = fmt->mdp_color; 551 u32 stride; 552 553 stride = (bytesperline * MDP_COLOR_BITS_PER_PIXEL(c)) 554 / fmt->row_depth[0]; 555 if (plane == 0) 556 return stride; 557 if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) { 558 if (MDP_COLOR_IS_BLOCK_MODE(c)) 559 stride = stride / 2; 560 return stride; 561 } 562 return 0; 563 } 564 565 /* Stride that is accepted by MDP HW of format with contiguous planes */ 566 static u32 mdp_fmt_get_stride_contig(const struct mdp_format *fmt, 567 u32 pix_stride, unsigned int plane) 568 { 569 enum mdp_color c = fmt->mdp_color; 570 u32 stride = pix_stride; 571 572 if (plane == 0) 573 return stride; 574 if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) { 575 stride = stride >> MDP_COLOR_GET_H_SUBSAMPLE(c); 576 if (MDP_COLOR_IS_UV_COPLANE(c) && !MDP_COLOR_IS_BLOCK_MODE(c)) 577 stride = stride * 2; 578 return stride; 579 } 580 return 0; 581 } 582 583 /* Plane size that is accepted by MDP HW */ 584 static u32 mdp_fmt_get_plane_size(const struct mdp_format *fmt, 585 u32 stride, u32 height, unsigned int plane) 586 { 587 enum mdp_color c = fmt->mdp_color; 588 u32 bytesperline; 589 590 bytesperline = (stride * fmt->row_depth[0]) 591 / MDP_COLOR_BITS_PER_PIXEL(c); 592 if (plane == 0) 593 return bytesperline * height; 594 if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) { 595 height = height >> MDP_COLOR_GET_V_SUBSAMPLE(c); 596 if (MDP_COLOR_IS_BLOCK_MODE(c)) 597 bytesperline = bytesperline * 2; 598 return bytesperline * height; 599 } 600 return 0; 601 } 602 603 static void mdp_prepare_buffer(struct img_image_buffer *b, 604 struct mdp_frame *frame, struct vb2_buffer *vb) 605 { 606 struct v4l2_pix_format_mplane *pix_mp = &frame->format.fmt.pix_mp; 607 unsigned int i; 608 609 b->format.colorformat = frame->mdp_fmt->mdp_color; 610 b->format.ycbcr_prof = frame->ycbcr_prof; 611 for (i = 0; i < pix_mp->num_planes; ++i) { 612 u32 stride = mdp_fmt_get_stride(frame->mdp_fmt, 613 pix_mp->plane_fmt[i].bytesperline, i); 614 615 b->format.plane_fmt[i].stride = stride; 616 b->format.plane_fmt[i].size = 617 mdp_fmt_get_plane_size(frame->mdp_fmt, stride, 618 pix_mp->height, i); 619 b->iova[i] = vb2_dma_contig_plane_dma_addr(vb, i); 620 } 621 for (; i < MDP_COLOR_GET_PLANE_COUNT(b->format.colorformat); ++i) { 622 u32 stride = mdp_fmt_get_stride_contig(frame->mdp_fmt, 623 b->format.plane_fmt[0].stride, i); 624 625 b->format.plane_fmt[i].stride = stride; 626 b->format.plane_fmt[i].size = 627 mdp_fmt_get_plane_size(frame->mdp_fmt, stride, 628 pix_mp->height, i); 629 b->iova[i] = b->iova[i - 1] + b->format.plane_fmt[i - 1].size; 630 } 631 b->usage = frame->usage; 632 } 633 634 void mdp_set_src_config(struct img_input *in, 635 struct mdp_frame *frame, struct vb2_buffer *vb) 636 { 637 in->buffer.format.width = frame->format.fmt.pix_mp.width; 638 in->buffer.format.height = frame->format.fmt.pix_mp.height; 639 mdp_prepare_buffer(&in->buffer, frame, vb); 640 } 641 642 static u32 mdp_to_fixed(u32 *r, struct v4l2_fract *f) 643 { 644 u32 q; 645 646 if (f->denominator == 0) { 647 *r = 0; 648 return 0; 649 } 650 651 q = f->numerator / f->denominator; 652 *r = div_u64(((u64)f->numerator - q * f->denominator) << 653 IMG_SUBPIXEL_SHIFT, f->denominator); 654 return q; 655 } 656 657 static void mdp_set_src_crop(struct img_crop *c, struct mdp_crop *crop) 658 { 659 c->left = crop->c.left 660 + mdp_to_fixed(&c->left_subpix, &crop->left_subpix); 661 c->top = crop->c.top 662 + mdp_to_fixed(&c->top_subpix, &crop->top_subpix); 663 c->width = crop->c.width 664 + mdp_to_fixed(&c->width_subpix, &crop->width_subpix); 665 c->height = crop->c.height 666 + mdp_to_fixed(&c->height_subpix, &crop->height_subpix); 667 } 668 669 static void mdp_set_orientation(struct img_output *out, 670 s32 rotation, bool hflip, bool vflip) 671 { 672 u8 flip = 0; 673 674 if (hflip) 675 flip ^= 1; 676 if (vflip) { 677 /* 678 * A vertical flip is equivalent to 679 * a 180-degree rotation with a horizontal flip 680 */ 681 rotation += 180; 682 flip ^= 1; 683 } 684 685 out->rotation = rotation % 360; 686 if (flip != 0) 687 out->flags |= IMG_CTRL_FLAG_HFLIP; 688 else 689 out->flags &= ~IMG_CTRL_FLAG_HFLIP; 690 } 691 692 void mdp_set_dst_config(struct img_output *out, 693 struct mdp_frame *frame, struct vb2_buffer *vb) 694 { 695 out->buffer.format.width = frame->compose.width; 696 out->buffer.format.height = frame->compose.height; 697 mdp_prepare_buffer(&out->buffer, frame, vb); 698 mdp_set_src_crop(&out->crop, &frame->crop); 699 mdp_set_orientation(out, frame->rotation, frame->hflip, frame->vflip); 700 } 701 702 int mdp_frameparam_init(struct mdp_frameparam *param) 703 { 704 struct mdp_frame *frame; 705 706 if (!param) 707 return -EINVAL; 708 709 INIT_LIST_HEAD(¶m->list); 710 param->limit = &mdp_def_limit; 711 param->type = MDP_STREAM_TYPE_BITBLT; 712 713 frame = ¶m->output; 714 frame->format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; 715 frame->mdp_fmt = mdp_try_fmt_mplane(&frame->format, param, 0); 716 frame->ycbcr_prof = 717 mdp_map_ycbcr_prof_mplane(&frame->format, 718 frame->mdp_fmt->mdp_color); 719 frame->usage = MDP_BUFFER_USAGE_HW_READ; 720 721 param->num_captures = 1; 722 frame = ¶m->captures[0]; 723 frame->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 724 frame->mdp_fmt = mdp_try_fmt_mplane(&frame->format, param, 0); 725 frame->ycbcr_prof = 726 mdp_map_ycbcr_prof_mplane(&frame->format, 727 frame->mdp_fmt->mdp_color); 728 frame->usage = MDP_BUFFER_USAGE_MDP; 729 frame->crop.c.width = param->output.format.fmt.pix_mp.width; 730 frame->crop.c.height = param->output.format.fmt.pix_mp.height; 731 frame->compose.width = frame->format.fmt.pix_mp.width; 732 frame->compose.height = frame->format.fmt.pix_mp.height; 733 734 return 0; 735 } 736