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