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