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