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 >> 8); 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 hsub = 1; 596 int vsub = 1; 597 int ret; 598 int i; 599 600 if (!state->base.crtc || !fb) 601 return 0; 602 603 crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc); 604 mode = &crtc_state->adjusted_mode; 605 606 ret = drm_atomic_helper_check_plane_state(s, crtc_state, 607 (1 << 16) / 2048, 608 INT_MAX, true, true); 609 if (ret || !s->visible) 610 return ret; 611 612 state->src_x = s->src.x1; 613 state->src_y = s->src.y1; 614 state->src_w = drm_rect_width(&s->src); 615 state->src_h = drm_rect_height(&s->src); 616 state->crtc_x = s->dst.x1; 617 state->crtc_y = s->dst.y1; 618 state->crtc_w = drm_rect_width(&s->dst); 619 state->crtc_h = drm_rect_height(&s->dst); 620 621 if ((state->src_x | state->src_y | state->src_w | state->src_h) & 622 SUBPIXEL_MASK) 623 return -EINVAL; 624 625 state->src_x >>= 16; 626 state->src_y >>= 16; 627 state->src_w >>= 16; 628 state->src_h >>= 16; 629 630 state->nplanes = fb->format->num_planes; 631 if (state->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES) 632 return -EINVAL; 633 634 hsub = drm_format_horz_chroma_subsampling(fb->format->format); 635 vsub = drm_format_vert_chroma_subsampling(fb->format->format); 636 637 for (i = 0; i < state->nplanes; i++) { 638 unsigned int offset = 0; 639 int xdiv = i ? hsub : 1; 640 int ydiv = i ? vsub : 1; 641 642 state->bpp[i] = fb->format->cpp[i]; 643 if (!state->bpp[i]) 644 return -EINVAL; 645 646 switch (state->base.rotation & DRM_MODE_ROTATE_MASK) { 647 case DRM_MODE_ROTATE_90: 648 offset = (state->src_y / ydiv) * 649 fb->pitches[i]; 650 offset += ((state->src_x + state->src_w - 1) / 651 xdiv) * state->bpp[i]; 652 state->xstride[i] = -(((state->src_h - 1) / ydiv) * 653 fb->pitches[i]) - 654 (2 * state->bpp[i]); 655 state->pstride[i] = fb->pitches[i] - state->bpp[i]; 656 break; 657 case DRM_MODE_ROTATE_180: 658 offset = ((state->src_y + state->src_h - 1) / 659 ydiv) * fb->pitches[i]; 660 offset += ((state->src_x + state->src_w - 1) / 661 xdiv) * state->bpp[i]; 662 state->xstride[i] = ((((state->src_w - 1) / xdiv) - 1) * 663 state->bpp[i]) - fb->pitches[i]; 664 state->pstride[i] = -2 * state->bpp[i]; 665 break; 666 case DRM_MODE_ROTATE_270: 667 offset = ((state->src_y + state->src_h - 1) / 668 ydiv) * fb->pitches[i]; 669 offset += (state->src_x / xdiv) * state->bpp[i]; 670 state->xstride[i] = ((state->src_h - 1) / ydiv) * 671 fb->pitches[i]; 672 state->pstride[i] = -fb->pitches[i] - state->bpp[i]; 673 break; 674 case DRM_MODE_ROTATE_0: 675 default: 676 offset = (state->src_y / ydiv) * fb->pitches[i]; 677 offset += (state->src_x / xdiv) * state->bpp[i]; 678 state->xstride[i] = fb->pitches[i] - 679 ((state->src_w / xdiv) * 680 state->bpp[i]); 681 state->pstride[i] = 0; 682 break; 683 } 684 685 state->offsets[i] = offset + fb->offsets[i]; 686 } 687 688 /* 689 * Swap width and size in case of 90 or 270 degrees rotation 690 */ 691 if (drm_rotation_90_or_270(state->base.rotation)) { 692 tmp = state->src_w; 693 state->src_w = state->src_h; 694 state->src_h = tmp; 695 } 696 697 if (!desc->layout.size && 698 (mode->hdisplay != state->crtc_w || 699 mode->vdisplay != state->crtc_h)) 700 return -EINVAL; 701 702 if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) && 703 (!desc->layout.memsize || 704 state->base.fb->format->has_alpha)) 705 return -EINVAL; 706 707 return 0; 708 } 709 710 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p, 711 struct drm_plane_state *old_state) 712 { 713 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); 714 715 /* Disable interrupts */ 716 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR, 717 0xffffffff); 718 719 /* Disable the layer */ 720 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR, 721 ATMEL_HLCDC_LAYER_RST | 722 ATMEL_HLCDC_LAYER_A2Q | 723 ATMEL_HLCDC_LAYER_UPDATE); 724 725 /* Clear all pending interrupts */ 726 atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR); 727 } 728 729 static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p, 730 struct drm_plane_state *old_s) 731 { 732 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); 733 struct atmel_hlcdc_plane_state *state = 734 drm_plane_state_to_atmel_hlcdc_plane_state(p->state); 735 u32 sr; 736 737 if (!p->state->crtc || !p->state->fb) 738 return; 739 740 if (!state->base.visible) { 741 atmel_hlcdc_plane_atomic_disable(p, old_s); 742 return; 743 } 744 745 atmel_hlcdc_plane_update_pos_and_size(plane, state); 746 atmel_hlcdc_plane_update_general_settings(plane, state); 747 atmel_hlcdc_plane_update_format(plane, state); 748 atmel_hlcdc_plane_update_clut(plane, state); 749 atmel_hlcdc_plane_update_buffers(plane, state); 750 atmel_hlcdc_plane_update_disc_area(plane, state); 751 752 /* Enable the overrun interrupts. */ 753 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER, 754 ATMEL_HLCDC_LAYER_OVR_IRQ(0) | 755 ATMEL_HLCDC_LAYER_OVR_IRQ(1) | 756 ATMEL_HLCDC_LAYER_OVR_IRQ(2)); 757 758 /* Apply the new config at the next SOF event. */ 759 sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR); 760 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER, 761 ATMEL_HLCDC_LAYER_UPDATE | 762 (sr & ATMEL_HLCDC_LAYER_EN ? 763 ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN)); 764 } 765 766 static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane) 767 { 768 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc; 769 770 if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER || 771 desc->type == ATMEL_HLCDC_CURSOR_LAYER) { 772 int ret; 773 774 ret = drm_plane_create_alpha_property(&plane->base); 775 if (ret) 776 return ret; 777 } 778 779 if (desc->layout.xstride[0] && desc->layout.pstride[0]) { 780 int ret; 781 782 ret = drm_plane_create_rotation_property(&plane->base, 783 DRM_MODE_ROTATE_0, 784 DRM_MODE_ROTATE_0 | 785 DRM_MODE_ROTATE_90 | 786 DRM_MODE_ROTATE_180 | 787 DRM_MODE_ROTATE_270); 788 if (ret) 789 return ret; 790 } 791 792 if (desc->layout.csc) { 793 /* 794 * TODO: decare a "yuv-to-rgb-conv-factors" property to let 795 * userspace modify these factors (using a BLOB property ?). 796 */ 797 atmel_hlcdc_layer_write_cfg(&plane->layer, 798 desc->layout.csc, 799 0x4c900091); 800 atmel_hlcdc_layer_write_cfg(&plane->layer, 801 desc->layout.csc + 1, 802 0x7a5f5090); 803 atmel_hlcdc_layer_write_cfg(&plane->layer, 804 desc->layout.csc + 2, 805 0x40040890); 806 } 807 808 return 0; 809 } 810 811 void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane) 812 { 813 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc; 814 u32 isr; 815 816 isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR); 817 818 /* 819 * There's not much we can do in case of overrun except informing 820 * the user. However, we are in interrupt context here, hence the 821 * use of dev_dbg(). 822 */ 823 if (isr & 824 (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) | 825 ATMEL_HLCDC_LAYER_OVR_IRQ(2))) 826 dev_dbg(plane->base.dev->dev, "overrun on plane %s\n", 827 desc->name); 828 } 829 830 static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = { 831 .atomic_check = atmel_hlcdc_plane_atomic_check, 832 .atomic_update = atmel_hlcdc_plane_atomic_update, 833 .atomic_disable = atmel_hlcdc_plane_atomic_disable, 834 }; 835 836 static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p, 837 struct atmel_hlcdc_plane_state *state) 838 { 839 struct atmel_hlcdc_dc *dc = p->dev->dev_private; 840 int i; 841 842 for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) { 843 struct atmel_hlcdc_dma_channel_dscr *dscr; 844 dma_addr_t dscr_dma; 845 846 dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma); 847 if (!dscr) 848 goto err; 849 850 dscr->addr = 0; 851 dscr->next = dscr_dma; 852 dscr->self = dscr_dma; 853 dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH; 854 855 state->dscrs[i] = dscr; 856 } 857 858 return 0; 859 860 err: 861 for (i--; i >= 0; i--) { 862 dma_pool_free(dc->dscrpool, state->dscrs[i], 863 state->dscrs[i]->self); 864 } 865 866 return -ENOMEM; 867 } 868 869 static void atmel_hlcdc_plane_reset(struct drm_plane *p) 870 { 871 struct atmel_hlcdc_plane_state *state; 872 873 if (p->state) { 874 state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state); 875 876 if (state->base.fb) 877 drm_framebuffer_put(state->base.fb); 878 879 kfree(state); 880 p->state = NULL; 881 } 882 883 state = kzalloc(sizeof(*state), GFP_KERNEL); 884 if (state) { 885 if (atmel_hlcdc_plane_alloc_dscrs(p, state)) { 886 kfree(state); 887 dev_err(p->dev->dev, 888 "Failed to allocate initial plane state\n"); 889 return; 890 } 891 __drm_atomic_helper_plane_reset(p, &state->base); 892 } 893 } 894 895 static struct drm_plane_state * 896 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p) 897 { 898 struct atmel_hlcdc_plane_state *state = 899 drm_plane_state_to_atmel_hlcdc_plane_state(p->state); 900 struct atmel_hlcdc_plane_state *copy; 901 902 copy = kmemdup(state, sizeof(*state), GFP_KERNEL); 903 if (!copy) 904 return NULL; 905 906 if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) { 907 kfree(copy); 908 return NULL; 909 } 910 911 if (copy->base.fb) 912 drm_framebuffer_get(copy->base.fb); 913 914 return ©->base; 915 } 916 917 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p, 918 struct drm_plane_state *s) 919 { 920 struct atmel_hlcdc_plane_state *state = 921 drm_plane_state_to_atmel_hlcdc_plane_state(s); 922 struct atmel_hlcdc_dc *dc = p->dev->dev_private; 923 int i; 924 925 for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) { 926 dma_pool_free(dc->dscrpool, state->dscrs[i], 927 state->dscrs[i]->self); 928 } 929 930 if (s->fb) 931 drm_framebuffer_put(s->fb); 932 933 kfree(state); 934 } 935 936 static const struct drm_plane_funcs layer_plane_funcs = { 937 .update_plane = drm_atomic_helper_update_plane, 938 .disable_plane = drm_atomic_helper_disable_plane, 939 .destroy = drm_plane_cleanup, 940 .reset = atmel_hlcdc_plane_reset, 941 .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state, 942 .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state, 943 }; 944 945 static int atmel_hlcdc_plane_create(struct drm_device *dev, 946 const struct atmel_hlcdc_layer_desc *desc) 947 { 948 struct atmel_hlcdc_dc *dc = dev->dev_private; 949 struct atmel_hlcdc_plane *plane; 950 enum drm_plane_type type; 951 int ret; 952 953 plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL); 954 if (!plane) 955 return -ENOMEM; 956 957 atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap); 958 959 if (desc->type == ATMEL_HLCDC_BASE_LAYER) 960 type = DRM_PLANE_TYPE_PRIMARY; 961 else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER) 962 type = DRM_PLANE_TYPE_CURSOR; 963 else 964 type = DRM_PLANE_TYPE_OVERLAY; 965 966 ret = drm_universal_plane_init(dev, &plane->base, 0, 967 &layer_plane_funcs, 968 desc->formats->formats, 969 desc->formats->nformats, 970 NULL, type, NULL); 971 if (ret) 972 return ret; 973 974 drm_plane_helper_add(&plane->base, 975 &atmel_hlcdc_layer_plane_helper_funcs); 976 977 /* Set default property values*/ 978 ret = atmel_hlcdc_plane_init_properties(plane); 979 if (ret) 980 return ret; 981 982 dc->layers[desc->id] = &plane->layer; 983 984 return 0; 985 } 986 987 int atmel_hlcdc_create_planes(struct drm_device *dev) 988 { 989 struct atmel_hlcdc_dc *dc = dev->dev_private; 990 const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers; 991 int nlayers = dc->desc->nlayers; 992 int i, ret; 993 994 dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev, 995 sizeof(struct atmel_hlcdc_dma_channel_dscr), 996 sizeof(u64), 0); 997 if (!dc->dscrpool) 998 return -ENOMEM; 999 1000 for (i = 0; i < nlayers; i++) { 1001 if (descs[i].type != ATMEL_HLCDC_BASE_LAYER && 1002 descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER && 1003 descs[i].type != ATMEL_HLCDC_CURSOR_LAYER) 1004 continue; 1005 1006 ret = atmel_hlcdc_plane_create(dev, &descs[i]); 1007 if (ret) 1008 return ret; 1009 } 1010 1011 return 0; 1012 } 1013