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