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