1 /* 2 * Copyright (C) 2014 Free Electrons 3 * Copyright (C) 2014 Atmel 4 * 5 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 as published by 9 * the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 * more details. 15 * 16 * You should have received a copy of the GNU General Public License along with 17 * this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "atmel_hlcdc_dc.h" 21 22 /** 23 * Atmel HLCDC Plane state structure. 24 * 25 * @base: DRM plane state 26 * @crtc_x: x position of the plane relative to the CRTC 27 * @crtc_y: y position of the plane relative to the CRTC 28 * @crtc_w: visible width of the plane 29 * @crtc_h: visible height of the plane 30 * @src_x: x buffer position 31 * @src_y: y buffer position 32 * @src_w: buffer width 33 * @src_h: buffer height 34 * @alpha: alpha blending of the plane 35 * @bpp: bytes per pixel deduced from pixel_format 36 * @offsets: offsets to apply to the GEM buffers 37 * @xstride: value to add to the pixel pointer between each line 38 * @pstride: value to add to the pixel pointer between each pixel 39 * @nplanes: number of planes (deduced from pixel_format) 40 */ 41 struct atmel_hlcdc_plane_state { 42 struct drm_plane_state base; 43 int crtc_x; 44 int crtc_y; 45 unsigned int crtc_w; 46 unsigned int crtc_h; 47 uint32_t src_x; 48 uint32_t src_y; 49 uint32_t src_w; 50 uint32_t src_h; 51 52 u8 alpha; 53 54 bool disc_updated; 55 56 int disc_x; 57 int disc_y; 58 int disc_w; 59 int disc_h; 60 61 /* These fields are private and should not be touched */ 62 int bpp[ATMEL_HLCDC_MAX_PLANES]; 63 unsigned int offsets[ATMEL_HLCDC_MAX_PLANES]; 64 int xstride[ATMEL_HLCDC_MAX_PLANES]; 65 int pstride[ATMEL_HLCDC_MAX_PLANES]; 66 int nplanes; 67 }; 68 69 static inline struct atmel_hlcdc_plane_state * 70 drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s) 71 { 72 return container_of(s, struct atmel_hlcdc_plane_state, base); 73 } 74 75 #define SUBPIXEL_MASK 0xffff 76 77 static uint32_t rgb_formats[] = { 78 DRM_FORMAT_XRGB4444, 79 DRM_FORMAT_ARGB4444, 80 DRM_FORMAT_RGBA4444, 81 DRM_FORMAT_ARGB1555, 82 DRM_FORMAT_RGB565, 83 DRM_FORMAT_RGB888, 84 DRM_FORMAT_XRGB8888, 85 DRM_FORMAT_ARGB8888, 86 DRM_FORMAT_RGBA8888, 87 }; 88 89 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = { 90 .formats = rgb_formats, 91 .nformats = ARRAY_SIZE(rgb_formats), 92 }; 93 94 static uint32_t rgb_and_yuv_formats[] = { 95 DRM_FORMAT_XRGB4444, 96 DRM_FORMAT_ARGB4444, 97 DRM_FORMAT_RGBA4444, 98 DRM_FORMAT_ARGB1555, 99 DRM_FORMAT_RGB565, 100 DRM_FORMAT_RGB888, 101 DRM_FORMAT_XRGB8888, 102 DRM_FORMAT_ARGB8888, 103 DRM_FORMAT_RGBA8888, 104 DRM_FORMAT_AYUV, 105 DRM_FORMAT_YUYV, 106 DRM_FORMAT_UYVY, 107 DRM_FORMAT_YVYU, 108 DRM_FORMAT_VYUY, 109 DRM_FORMAT_NV21, 110 DRM_FORMAT_NV61, 111 DRM_FORMAT_YUV422, 112 DRM_FORMAT_YUV420, 113 }; 114 115 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = { 116 .formats = rgb_and_yuv_formats, 117 .nformats = ARRAY_SIZE(rgb_and_yuv_formats), 118 }; 119 120 static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode) 121 { 122 switch (format) { 123 case DRM_FORMAT_XRGB4444: 124 *mode = ATMEL_HLCDC_XRGB4444_MODE; 125 break; 126 case DRM_FORMAT_ARGB4444: 127 *mode = ATMEL_HLCDC_ARGB4444_MODE; 128 break; 129 case DRM_FORMAT_RGBA4444: 130 *mode = ATMEL_HLCDC_RGBA4444_MODE; 131 break; 132 case DRM_FORMAT_RGB565: 133 *mode = ATMEL_HLCDC_RGB565_MODE; 134 break; 135 case DRM_FORMAT_RGB888: 136 *mode = ATMEL_HLCDC_RGB888_MODE; 137 break; 138 case DRM_FORMAT_ARGB1555: 139 *mode = ATMEL_HLCDC_ARGB1555_MODE; 140 break; 141 case DRM_FORMAT_XRGB8888: 142 *mode = ATMEL_HLCDC_XRGB8888_MODE; 143 break; 144 case DRM_FORMAT_ARGB8888: 145 *mode = ATMEL_HLCDC_ARGB8888_MODE; 146 break; 147 case DRM_FORMAT_RGBA8888: 148 *mode = ATMEL_HLCDC_RGBA8888_MODE; 149 break; 150 case DRM_FORMAT_AYUV: 151 *mode = ATMEL_HLCDC_AYUV_MODE; 152 break; 153 case DRM_FORMAT_YUYV: 154 *mode = ATMEL_HLCDC_YUYV_MODE; 155 break; 156 case DRM_FORMAT_UYVY: 157 *mode = ATMEL_HLCDC_UYVY_MODE; 158 break; 159 case DRM_FORMAT_YVYU: 160 *mode = ATMEL_HLCDC_YVYU_MODE; 161 break; 162 case DRM_FORMAT_VYUY: 163 *mode = ATMEL_HLCDC_VYUY_MODE; 164 break; 165 case DRM_FORMAT_NV21: 166 *mode = ATMEL_HLCDC_NV21_MODE; 167 break; 168 case DRM_FORMAT_NV61: 169 *mode = ATMEL_HLCDC_NV61_MODE; 170 break; 171 case DRM_FORMAT_YUV420: 172 *mode = ATMEL_HLCDC_YUV420_MODE; 173 break; 174 case DRM_FORMAT_YUV422: 175 *mode = ATMEL_HLCDC_YUV422_MODE; 176 break; 177 default: 178 return -ENOTSUPP; 179 } 180 181 return 0; 182 } 183 184 static bool atmel_hlcdc_format_embeds_alpha(u32 format) 185 { 186 int i; 187 188 for (i = 0; i < sizeof(format); i++) { 189 char tmp = (format >> (8 * i)) & 0xff; 190 191 if (tmp == 'A') 192 return true; 193 } 194 195 return false; 196 } 197 198 static u32 heo_downscaling_xcoef[] = { 199 0x11343311, 200 0x000000f7, 201 0x1635300c, 202 0x000000f9, 203 0x1b362c08, 204 0x000000fb, 205 0x1f372804, 206 0x000000fe, 207 0x24382400, 208 0x00000000, 209 0x28371ffe, 210 0x00000004, 211 0x2c361bfb, 212 0x00000008, 213 0x303516f9, 214 0x0000000c, 215 }; 216 217 static u32 heo_downscaling_ycoef[] = { 218 0x00123737, 219 0x00173732, 220 0x001b382d, 221 0x001f3928, 222 0x00243824, 223 0x0028391f, 224 0x002d381b, 225 0x00323717, 226 }; 227 228 static u32 heo_upscaling_xcoef[] = { 229 0xf74949f7, 230 0x00000000, 231 0xf55f33fb, 232 0x000000fe, 233 0xf5701efe, 234 0x000000ff, 235 0xf87c0dff, 236 0x00000000, 237 0x00800000, 238 0x00000000, 239 0x0d7cf800, 240 0x000000ff, 241 0x1e70f5ff, 242 0x000000fe, 243 0x335ff5fe, 244 0x000000fb, 245 }; 246 247 static u32 heo_upscaling_ycoef[] = { 248 0x00004040, 249 0x00075920, 250 0x00056f0c, 251 0x00027b03, 252 0x00008000, 253 0x00037b02, 254 0x000c6f05, 255 0x00205907, 256 }; 257 258 static void 259 atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane, 260 struct atmel_hlcdc_plane_state *state) 261 { 262 const struct atmel_hlcdc_layer_cfg_layout *layout = 263 &plane->layer.desc->layout; 264 265 if (layout->size) 266 atmel_hlcdc_layer_update_cfg(&plane->layer, 267 layout->size, 268 0xffffffff, 269 (state->crtc_w - 1) | 270 ((state->crtc_h - 1) << 16)); 271 272 if (layout->memsize) 273 atmel_hlcdc_layer_update_cfg(&plane->layer, 274 layout->memsize, 275 0xffffffff, 276 (state->src_w - 1) | 277 ((state->src_h - 1) << 16)); 278 279 if (layout->pos) 280 atmel_hlcdc_layer_update_cfg(&plane->layer, 281 layout->pos, 282 0xffffffff, 283 state->crtc_x | 284 (state->crtc_y << 16)); 285 286 /* TODO: rework the rescaling part */ 287 if (state->crtc_w != state->src_w || state->crtc_h != state->src_h) { 288 u32 factor_reg = 0; 289 290 if (state->crtc_w != state->src_w) { 291 int i; 292 u32 factor; 293 u32 *coeff_tab = heo_upscaling_xcoef; 294 u32 max_memsize; 295 296 if (state->crtc_w < state->src_w) 297 coeff_tab = heo_downscaling_xcoef; 298 for (i = 0; i < ARRAY_SIZE(heo_upscaling_xcoef); i++) 299 atmel_hlcdc_layer_update_cfg(&plane->layer, 300 17 + i, 301 0xffffffff, 302 coeff_tab[i]); 303 factor = ((8 * 256 * state->src_w) - (256 * 4)) / 304 state->crtc_w; 305 factor++; 306 max_memsize = ((factor * state->crtc_w) + (256 * 4)) / 307 2048; 308 if (max_memsize > state->src_w) 309 factor--; 310 factor_reg |= factor | 0x80000000; 311 } 312 313 if (state->crtc_h != state->src_h) { 314 int i; 315 u32 factor; 316 u32 *coeff_tab = heo_upscaling_ycoef; 317 u32 max_memsize; 318 319 if (state->crtc_w < state->src_w) 320 coeff_tab = heo_downscaling_ycoef; 321 for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++) 322 atmel_hlcdc_layer_update_cfg(&plane->layer, 323 33 + i, 324 0xffffffff, 325 coeff_tab[i]); 326 factor = ((8 * 256 * state->src_w) - (256 * 4)) / 327 state->crtc_w; 328 factor++; 329 max_memsize = ((factor * state->crtc_w) + (256 * 4)) / 330 2048; 331 if (max_memsize > state->src_w) 332 factor--; 333 factor_reg |= (factor << 16) | 0x80000000; 334 } 335 336 atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff, 337 factor_reg); 338 } 339 } 340 341 static void 342 atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane, 343 struct atmel_hlcdc_plane_state *state) 344 { 345 const struct atmel_hlcdc_layer_cfg_layout *layout = 346 &plane->layer.desc->layout; 347 unsigned int cfg = ATMEL_HLCDC_LAYER_DMA; 348 349 if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) { 350 cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL | 351 ATMEL_HLCDC_LAYER_ITER; 352 353 if (atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format)) 354 cfg |= ATMEL_HLCDC_LAYER_LAEN; 355 else 356 cfg |= ATMEL_HLCDC_LAYER_GAEN | 357 ATMEL_HLCDC_LAYER_GA(state->alpha); 358 } 359 360 atmel_hlcdc_layer_update_cfg(&plane->layer, 361 ATMEL_HLCDC_LAYER_DMA_CFG_ID, 362 ATMEL_HLCDC_LAYER_DMA_BLEN_MASK, 363 ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16); 364 365 atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config, 366 ATMEL_HLCDC_LAYER_ITER2BL | 367 ATMEL_HLCDC_LAYER_ITER | 368 ATMEL_HLCDC_LAYER_GAEN | 369 ATMEL_HLCDC_LAYER_GA_MASK | 370 ATMEL_HLCDC_LAYER_LAEN | 371 ATMEL_HLCDC_LAYER_OVR | 372 ATMEL_HLCDC_LAYER_DMA, cfg); 373 } 374 375 static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane, 376 struct atmel_hlcdc_plane_state *state) 377 { 378 u32 cfg; 379 int ret; 380 381 ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->pixel_format, 382 &cfg); 383 if (ret) 384 return; 385 386 if ((state->base.fb->pixel_format == DRM_FORMAT_YUV422 || 387 state->base.fb->pixel_format == DRM_FORMAT_NV61) && 388 (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270)))) 389 cfg |= ATMEL_HLCDC_YUV422ROT; 390 391 atmel_hlcdc_layer_update_cfg(&plane->layer, 392 ATMEL_HLCDC_LAYER_FORMAT_CFG_ID, 393 0xffffffff, 394 cfg); 395 396 /* 397 * Rotation optimization is not working on RGB888 (rotation is still 398 * working but without any optimization). 399 */ 400 if (state->base.fb->pixel_format == DRM_FORMAT_RGB888) 401 cfg = ATMEL_HLCDC_LAYER_DMA_ROTDIS; 402 else 403 cfg = 0; 404 405 atmel_hlcdc_layer_update_cfg(&plane->layer, 406 ATMEL_HLCDC_LAYER_DMA_CFG_ID, 407 ATMEL_HLCDC_LAYER_DMA_ROTDIS, cfg); 408 } 409 410 static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane, 411 struct atmel_hlcdc_plane_state *state) 412 { 413 struct atmel_hlcdc_layer *layer = &plane->layer; 414 const struct atmel_hlcdc_layer_cfg_layout *layout = 415 &layer->desc->layout; 416 int i; 417 418 atmel_hlcdc_layer_update_set_fb(&plane->layer, state->base.fb, 419 state->offsets); 420 421 for (i = 0; i < state->nplanes; i++) { 422 if (layout->xstride[i]) { 423 atmel_hlcdc_layer_update_cfg(&plane->layer, 424 layout->xstride[i], 425 0xffffffff, 426 state->xstride[i]); 427 } 428 429 if (layout->pstride[i]) { 430 atmel_hlcdc_layer_update_cfg(&plane->layer, 431 layout->pstride[i], 432 0xffffffff, 433 state->pstride[i]); 434 } 435 } 436 } 437 438 int 439 atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state) 440 { 441 int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0; 442 const struct atmel_hlcdc_layer_cfg_layout *layout; 443 struct atmel_hlcdc_plane_state *primary_state; 444 struct drm_plane_state *primary_s; 445 struct atmel_hlcdc_plane *primary; 446 struct drm_plane *ovl; 447 448 primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary); 449 layout = &primary->layer.desc->layout; 450 if (!layout->disc_pos || !layout->disc_size) 451 return 0; 452 453 primary_s = drm_atomic_get_plane_state(c_state->state, 454 &primary->base); 455 if (IS_ERR(primary_s)) 456 return PTR_ERR(primary_s); 457 458 primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s); 459 460 drm_atomic_crtc_state_for_each_plane(ovl, c_state) { 461 struct atmel_hlcdc_plane_state *ovl_state; 462 struct drm_plane_state *ovl_s; 463 464 if (ovl == c_state->crtc->primary) 465 continue; 466 467 ovl_s = drm_atomic_get_plane_state(c_state->state, ovl); 468 if (IS_ERR(ovl_s)) 469 return PTR_ERR(ovl_s); 470 471 ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s); 472 473 if (!ovl_s->fb || 474 atmel_hlcdc_format_embeds_alpha(ovl_s->fb->pixel_format) || 475 ovl_state->alpha != 255) 476 continue; 477 478 /* TODO: implement a smarter hidden area detection */ 479 if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w) 480 continue; 481 482 disc_x = ovl_state->crtc_x; 483 disc_y = ovl_state->crtc_y; 484 disc_h = ovl_state->crtc_h; 485 disc_w = ovl_state->crtc_w; 486 } 487 488 if (disc_x == primary_state->disc_x && 489 disc_y == primary_state->disc_y && 490 disc_w == primary_state->disc_w && 491 disc_h == primary_state->disc_h) 492 return 0; 493 494 495 primary_state->disc_x = disc_x; 496 primary_state->disc_y = disc_y; 497 primary_state->disc_w = disc_w; 498 primary_state->disc_h = disc_h; 499 primary_state->disc_updated = true; 500 501 return 0; 502 } 503 504 static void 505 atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane, 506 struct atmel_hlcdc_plane_state *state) 507 { 508 const struct atmel_hlcdc_layer_cfg_layout *layout = 509 &plane->layer.desc->layout; 510 int disc_surface = 0; 511 512 if (!state->disc_updated) 513 return; 514 515 disc_surface = state->disc_h * state->disc_w; 516 517 atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config, 518 ATMEL_HLCDC_LAYER_DISCEN, 519 disc_surface ? ATMEL_HLCDC_LAYER_DISCEN : 0); 520 521 if (!disc_surface) 522 return; 523 524 atmel_hlcdc_layer_update_cfg(&plane->layer, 525 layout->disc_pos, 526 0xffffffff, 527 state->disc_x | (state->disc_y << 16)); 528 529 atmel_hlcdc_layer_update_cfg(&plane->layer, 530 layout->disc_size, 531 0xffffffff, 532 (state->disc_w - 1) | 533 ((state->disc_h - 1) << 16)); 534 } 535 536 static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p, 537 struct drm_plane_state *s) 538 { 539 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); 540 struct atmel_hlcdc_plane_state *state = 541 drm_plane_state_to_atmel_hlcdc_plane_state(s); 542 const struct atmel_hlcdc_layer_cfg_layout *layout = 543 &plane->layer.desc->layout; 544 struct drm_framebuffer *fb = state->base.fb; 545 const struct drm_display_mode *mode; 546 struct drm_crtc_state *crtc_state; 547 unsigned int patched_crtc_w; 548 unsigned int patched_crtc_h; 549 unsigned int patched_src_w; 550 unsigned int patched_src_h; 551 unsigned int tmp; 552 int x_offset = 0; 553 int y_offset = 0; 554 int hsub = 1; 555 int vsub = 1; 556 int i; 557 558 if (!state->base.crtc || !fb) 559 return 0; 560 561 crtc_state = s->state->crtc_states[drm_crtc_index(s->crtc)]; 562 mode = &crtc_state->adjusted_mode; 563 564 state->src_x = s->src_x; 565 state->src_y = s->src_y; 566 state->src_h = s->src_h; 567 state->src_w = s->src_w; 568 state->crtc_x = s->crtc_x; 569 state->crtc_y = s->crtc_y; 570 state->crtc_h = s->crtc_h; 571 state->crtc_w = s->crtc_w; 572 if ((state->src_x | state->src_y | state->src_w | state->src_h) & 573 SUBPIXEL_MASK) 574 return -EINVAL; 575 576 state->src_x >>= 16; 577 state->src_y >>= 16; 578 state->src_w >>= 16; 579 state->src_h >>= 16; 580 581 state->nplanes = drm_format_num_planes(fb->pixel_format); 582 if (state->nplanes > ATMEL_HLCDC_MAX_PLANES) 583 return -EINVAL; 584 585 /* 586 * Swap width and size in case of 90 or 270 degrees rotation 587 */ 588 if (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) { 589 tmp = state->crtc_w; 590 state->crtc_w = state->crtc_h; 591 state->crtc_h = tmp; 592 tmp = state->src_w; 593 state->src_w = state->src_h; 594 state->src_h = tmp; 595 } 596 597 if (state->crtc_x + state->crtc_w > mode->hdisplay) 598 patched_crtc_w = mode->hdisplay - state->crtc_x; 599 else 600 patched_crtc_w = state->crtc_w; 601 602 if (state->crtc_x < 0) { 603 patched_crtc_w += state->crtc_x; 604 x_offset = -state->crtc_x; 605 state->crtc_x = 0; 606 } 607 608 if (state->crtc_y + state->crtc_h > mode->vdisplay) 609 patched_crtc_h = mode->vdisplay - state->crtc_y; 610 else 611 patched_crtc_h = state->crtc_h; 612 613 if (state->crtc_y < 0) { 614 patched_crtc_h += state->crtc_y; 615 y_offset = -state->crtc_y; 616 state->crtc_y = 0; 617 } 618 619 patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w, 620 state->crtc_w); 621 patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h, 622 state->crtc_h); 623 624 hsub = drm_format_horz_chroma_subsampling(fb->pixel_format); 625 vsub = drm_format_vert_chroma_subsampling(fb->pixel_format); 626 627 for (i = 0; i < state->nplanes; i++) { 628 unsigned int offset = 0; 629 int xdiv = i ? hsub : 1; 630 int ydiv = i ? vsub : 1; 631 632 state->bpp[i] = drm_format_plane_cpp(fb->pixel_format, i); 633 if (!state->bpp[i]) 634 return -EINVAL; 635 636 switch (state->base.rotation & DRM_ROTATE_MASK) { 637 case BIT(DRM_ROTATE_90): 638 offset = ((y_offset + state->src_y + patched_src_w - 1) / 639 ydiv) * fb->pitches[i]; 640 offset += ((x_offset + state->src_x) / xdiv) * 641 state->bpp[i]; 642 state->xstride[i] = ((patched_src_w - 1) / ydiv) * 643 fb->pitches[i]; 644 state->pstride[i] = -fb->pitches[i] - state->bpp[i]; 645 break; 646 case BIT(DRM_ROTATE_180): 647 offset = ((y_offset + state->src_y + patched_src_h - 1) / 648 ydiv) * fb->pitches[i]; 649 offset += ((x_offset + state->src_x + patched_src_w - 1) / 650 xdiv) * state->bpp[i]; 651 state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) * 652 state->bpp[i]) - fb->pitches[i]; 653 state->pstride[i] = -2 * state->bpp[i]; 654 break; 655 case BIT(DRM_ROTATE_270): 656 offset = ((y_offset + state->src_y) / ydiv) * 657 fb->pitches[i]; 658 offset += ((x_offset + state->src_x + patched_src_h - 1) / 659 xdiv) * state->bpp[i]; 660 state->xstride[i] = -(((patched_src_w - 1) / ydiv) * 661 fb->pitches[i]) - 662 (2 * state->bpp[i]); 663 state->pstride[i] = fb->pitches[i] - state->bpp[i]; 664 break; 665 case BIT(DRM_ROTATE_0): 666 default: 667 offset = ((y_offset + state->src_y) / ydiv) * 668 fb->pitches[i]; 669 offset += ((x_offset + state->src_x) / xdiv) * 670 state->bpp[i]; 671 state->xstride[i] = fb->pitches[i] - 672 ((patched_src_w / xdiv) * 673 state->bpp[i]); 674 state->pstride[i] = 0; 675 break; 676 } 677 678 state->offsets[i] = offset + fb->offsets[i]; 679 } 680 681 state->src_w = patched_src_w; 682 state->src_h = patched_src_h; 683 state->crtc_w = patched_crtc_w; 684 state->crtc_h = patched_crtc_h; 685 686 if (!layout->size && 687 (mode->hdisplay != state->crtc_w || 688 mode->vdisplay != state->crtc_h)) 689 return -EINVAL; 690 691 if (plane->layer.desc->max_height && 692 state->crtc_h > plane->layer.desc->max_height) 693 return -EINVAL; 694 695 if (plane->layer.desc->max_width && 696 state->crtc_w > plane->layer.desc->max_width) 697 return -EINVAL; 698 699 if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) && 700 (!layout->memsize || 701 atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format))) 702 return -EINVAL; 703 704 if (state->crtc_x < 0 || state->crtc_y < 0) 705 return -EINVAL; 706 707 if (state->crtc_w + state->crtc_x > mode->hdisplay || 708 state->crtc_h + state->crtc_y > mode->vdisplay) 709 return -EINVAL; 710 711 return 0; 712 } 713 714 static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p, 715 const struct drm_plane_state *new_state) 716 { 717 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); 718 719 if (!new_state->fb) 720 return 0; 721 722 return atmel_hlcdc_layer_update_start(&plane->layer); 723 } 724 725 static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p, 726 struct drm_plane_state *old_s) 727 { 728 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); 729 struct atmel_hlcdc_plane_state *state = 730 drm_plane_state_to_atmel_hlcdc_plane_state(p->state); 731 732 if (!p->state->crtc || !p->state->fb) 733 return; 734 735 atmel_hlcdc_plane_update_pos_and_size(plane, state); 736 atmel_hlcdc_plane_update_general_settings(plane, state); 737 atmel_hlcdc_plane_update_format(plane, state); 738 atmel_hlcdc_plane_update_buffers(plane, state); 739 atmel_hlcdc_plane_update_disc_area(plane, state); 740 741 atmel_hlcdc_layer_update_commit(&plane->layer); 742 } 743 744 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p, 745 struct drm_plane_state *old_state) 746 { 747 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); 748 749 atmel_hlcdc_layer_disable(&plane->layer); 750 } 751 752 static void atmel_hlcdc_plane_destroy(struct drm_plane *p) 753 { 754 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); 755 756 if (plane->base.fb) 757 drm_framebuffer_unreference(plane->base.fb); 758 759 atmel_hlcdc_layer_cleanup(p->dev, &plane->layer); 760 761 drm_plane_cleanup(p); 762 devm_kfree(p->dev->dev, plane); 763 } 764 765 static int atmel_hlcdc_plane_atomic_set_property(struct drm_plane *p, 766 struct drm_plane_state *s, 767 struct drm_property *property, 768 uint64_t val) 769 { 770 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); 771 struct atmel_hlcdc_plane_properties *props = plane->properties; 772 struct atmel_hlcdc_plane_state *state = 773 drm_plane_state_to_atmel_hlcdc_plane_state(s); 774 775 if (property == props->alpha) 776 state->alpha = val; 777 else 778 return -EINVAL; 779 780 return 0; 781 } 782 783 static int atmel_hlcdc_plane_atomic_get_property(struct drm_plane *p, 784 const struct drm_plane_state *s, 785 struct drm_property *property, 786 uint64_t *val) 787 { 788 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); 789 struct atmel_hlcdc_plane_properties *props = plane->properties; 790 const struct atmel_hlcdc_plane_state *state = 791 container_of(s, const struct atmel_hlcdc_plane_state, base); 792 793 if (property == props->alpha) 794 *val = state->alpha; 795 else 796 return -EINVAL; 797 798 return 0; 799 } 800 801 static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane, 802 const struct atmel_hlcdc_layer_desc *desc, 803 struct atmel_hlcdc_plane_properties *props) 804 { 805 struct regmap *regmap = plane->layer.hlcdc->regmap; 806 807 if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER || 808 desc->type == ATMEL_HLCDC_CURSOR_LAYER) { 809 drm_object_attach_property(&plane->base.base, 810 props->alpha, 255); 811 812 /* Set default alpha value */ 813 regmap_update_bits(regmap, 814 desc->regs_offset + 815 ATMEL_HLCDC_LAYER_GENERAL_CFG(&plane->layer), 816 ATMEL_HLCDC_LAYER_GA_MASK, 817 ATMEL_HLCDC_LAYER_GA_MASK); 818 } 819 820 if (desc->layout.xstride && desc->layout.pstride) 821 drm_object_attach_property(&plane->base.base, 822 plane->base.dev->mode_config.rotation_property, 823 BIT(DRM_ROTATE_0)); 824 825 if (desc->layout.csc) { 826 /* 827 * TODO: decare a "yuv-to-rgb-conv-factors" property to let 828 * userspace modify these factors (using a BLOB property ?). 829 */ 830 regmap_write(regmap, 831 desc->regs_offset + 832 ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 0), 833 0x4c900091); 834 regmap_write(regmap, 835 desc->regs_offset + 836 ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 1), 837 0x7a5f5090); 838 regmap_write(regmap, 839 desc->regs_offset + 840 ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 2), 841 0x40040890); 842 } 843 } 844 845 static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = { 846 .prepare_fb = atmel_hlcdc_plane_prepare_fb, 847 .atomic_check = atmel_hlcdc_plane_atomic_check, 848 .atomic_update = atmel_hlcdc_plane_atomic_update, 849 .atomic_disable = atmel_hlcdc_plane_atomic_disable, 850 }; 851 852 static void atmel_hlcdc_plane_reset(struct drm_plane *p) 853 { 854 struct atmel_hlcdc_plane_state *state; 855 856 if (p->state) { 857 state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state); 858 859 if (state->base.fb) 860 drm_framebuffer_unreference(state->base.fb); 861 862 kfree(state); 863 p->state = NULL; 864 } 865 866 state = kzalloc(sizeof(*state), GFP_KERNEL); 867 if (state) { 868 state->alpha = 255; 869 p->state = &state->base; 870 p->state->plane = p; 871 } 872 } 873 874 static struct drm_plane_state * 875 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p) 876 { 877 struct atmel_hlcdc_plane_state *state = 878 drm_plane_state_to_atmel_hlcdc_plane_state(p->state); 879 struct atmel_hlcdc_plane_state *copy; 880 881 copy = kmemdup(state, sizeof(*state), GFP_KERNEL); 882 if (!copy) 883 return NULL; 884 885 copy->disc_updated = false; 886 887 if (copy->base.fb) 888 drm_framebuffer_reference(copy->base.fb); 889 890 return ©->base; 891 } 892 893 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *plane, 894 struct drm_plane_state *s) 895 { 896 struct atmel_hlcdc_plane_state *state = 897 drm_plane_state_to_atmel_hlcdc_plane_state(s); 898 899 if (s->fb) 900 drm_framebuffer_unreference(s->fb); 901 902 kfree(state); 903 } 904 905 static struct drm_plane_funcs layer_plane_funcs = { 906 .update_plane = drm_atomic_helper_update_plane, 907 .disable_plane = drm_atomic_helper_disable_plane, 908 .set_property = drm_atomic_helper_plane_set_property, 909 .destroy = atmel_hlcdc_plane_destroy, 910 .reset = atmel_hlcdc_plane_reset, 911 .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state, 912 .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state, 913 .atomic_set_property = atmel_hlcdc_plane_atomic_set_property, 914 .atomic_get_property = atmel_hlcdc_plane_atomic_get_property, 915 }; 916 917 static struct atmel_hlcdc_plane * 918 atmel_hlcdc_plane_create(struct drm_device *dev, 919 const struct atmel_hlcdc_layer_desc *desc, 920 struct atmel_hlcdc_plane_properties *props) 921 { 922 struct atmel_hlcdc_plane *plane; 923 enum drm_plane_type type; 924 int ret; 925 926 plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL); 927 if (!plane) 928 return ERR_PTR(-ENOMEM); 929 930 ret = atmel_hlcdc_layer_init(dev, &plane->layer, desc); 931 if (ret) 932 return ERR_PTR(ret); 933 934 if (desc->type == ATMEL_HLCDC_BASE_LAYER) 935 type = DRM_PLANE_TYPE_PRIMARY; 936 else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER) 937 type = DRM_PLANE_TYPE_CURSOR; 938 else 939 type = DRM_PLANE_TYPE_OVERLAY; 940 941 ret = drm_universal_plane_init(dev, &plane->base, 0, 942 &layer_plane_funcs, 943 desc->formats->formats, 944 desc->formats->nformats, type); 945 if (ret) 946 return ERR_PTR(ret); 947 948 drm_plane_helper_add(&plane->base, 949 &atmel_hlcdc_layer_plane_helper_funcs); 950 951 /* Set default property values*/ 952 atmel_hlcdc_plane_init_properties(plane, desc, props); 953 954 return plane; 955 } 956 957 static struct atmel_hlcdc_plane_properties * 958 atmel_hlcdc_plane_create_properties(struct drm_device *dev) 959 { 960 struct atmel_hlcdc_plane_properties *props; 961 962 props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL); 963 if (!props) 964 return ERR_PTR(-ENOMEM); 965 966 props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255); 967 if (!props->alpha) 968 return ERR_PTR(-ENOMEM); 969 970 dev->mode_config.rotation_property = 971 drm_mode_create_rotation_property(dev, 972 BIT(DRM_ROTATE_0) | 973 BIT(DRM_ROTATE_90) | 974 BIT(DRM_ROTATE_180) | 975 BIT(DRM_ROTATE_270)); 976 if (!dev->mode_config.rotation_property) 977 return ERR_PTR(-ENOMEM); 978 979 return props; 980 } 981 982 struct atmel_hlcdc_planes * 983 atmel_hlcdc_create_planes(struct drm_device *dev) 984 { 985 struct atmel_hlcdc_dc *dc = dev->dev_private; 986 struct atmel_hlcdc_plane_properties *props; 987 struct atmel_hlcdc_planes *planes; 988 const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers; 989 int nlayers = dc->desc->nlayers; 990 int i; 991 992 planes = devm_kzalloc(dev->dev, sizeof(*planes), GFP_KERNEL); 993 if (!planes) 994 return ERR_PTR(-ENOMEM); 995 996 for (i = 0; i < nlayers; i++) { 997 if (descs[i].type == ATMEL_HLCDC_OVERLAY_LAYER) 998 planes->noverlays++; 999 } 1000 1001 if (planes->noverlays) { 1002 planes->overlays = devm_kzalloc(dev->dev, 1003 planes->noverlays * 1004 sizeof(*planes->overlays), 1005 GFP_KERNEL); 1006 if (!planes->overlays) 1007 return ERR_PTR(-ENOMEM); 1008 } 1009 1010 props = atmel_hlcdc_plane_create_properties(dev); 1011 if (IS_ERR(props)) 1012 return ERR_CAST(props); 1013 1014 planes->noverlays = 0; 1015 for (i = 0; i < nlayers; i++) { 1016 struct atmel_hlcdc_plane *plane; 1017 1018 if (descs[i].type == ATMEL_HLCDC_PP_LAYER) 1019 continue; 1020 1021 plane = atmel_hlcdc_plane_create(dev, &descs[i], props); 1022 if (IS_ERR(plane)) 1023 return ERR_CAST(plane); 1024 1025 plane->properties = props; 1026 1027 switch (descs[i].type) { 1028 case ATMEL_HLCDC_BASE_LAYER: 1029 if (planes->primary) 1030 return ERR_PTR(-EINVAL); 1031 planes->primary = plane; 1032 break; 1033 1034 case ATMEL_HLCDC_OVERLAY_LAYER: 1035 planes->overlays[planes->noverlays++] = plane; 1036 break; 1037 1038 case ATMEL_HLCDC_CURSOR_LAYER: 1039 if (planes->cursor) 1040 return ERR_PTR(-EINVAL); 1041 planes->cursor = plane; 1042 break; 1043 1044 default: 1045 break; 1046 } 1047 } 1048 1049 return planes; 1050 } 1051