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 <linux/dmapool.h> 10 #include <linux/mfd/atmel-hlcdc.h> 11 12 #include <drm/drm_atomic.h> 13 #include <drm/drm_atomic_helper.h> 14 #include <drm/drm_fb_cma_helper.h> 15 #include <drm/drm_fourcc.h> 16 #include <drm/drm_gem_cma_helper.h> 17 #include <drm/drm_plane_helper.h> 18 19 #include "atmel_hlcdc_dc.h" 20 21 /** 22 * struct atmel_hlcdc_plane_state - Atmel HLCDC Plane state structure. 23 * 24 * @base: DRM plane state 25 * @crtc_x: x position of the plane relative to the CRTC 26 * @crtc_y: y position of the plane relative to the CRTC 27 * @crtc_w: visible width of the plane 28 * @crtc_h: visible height of the plane 29 * @src_x: x buffer position 30 * @src_y: y buffer position 31 * @src_w: buffer width 32 * @src_h: buffer height 33 * @disc_x: x discard position 34 * @disc_y: y discard position 35 * @disc_w: discard width 36 * @disc_h: discard height 37 * @ahb_id: AHB identification number 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 static 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 | ATMEL_HLCDC_LAYER_REP; 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); 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 struct atmel_hlcdc_plane_state *state) 417 { 418 struct drm_crtc *crtc = state->base.crtc; 419 struct drm_color_lut *lut; 420 int idx; 421 422 if (!crtc || !crtc->state) 423 return; 424 425 if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut) 426 return; 427 428 lut = (struct drm_color_lut *)crtc->state->gamma_lut->data; 429 430 for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++, lut++) { 431 u32 val = ((lut->red << 8) & 0xff0000) | 432 (lut->green & 0xff00) | 433 (lut->blue >> 8); 434 435 atmel_hlcdc_layer_write_clut(&plane->layer, idx, val); 436 } 437 } 438 439 static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane, 440 struct atmel_hlcdc_plane_state *state) 441 { 442 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc; 443 struct drm_framebuffer *fb = state->base.fb; 444 u32 sr; 445 int i; 446 447 sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR); 448 449 for (i = 0; i < state->nplanes; i++) { 450 struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(fb, i); 451 452 state->dscrs[i]->addr = gem->paddr + state->offsets[i]; 453 454 atmel_hlcdc_layer_write_reg(&plane->layer, 455 ATMEL_HLCDC_LAYER_PLANE_HEAD(i), 456 state->dscrs[i]->self); 457 458 if (!(sr & ATMEL_HLCDC_LAYER_EN)) { 459 atmel_hlcdc_layer_write_reg(&plane->layer, 460 ATMEL_HLCDC_LAYER_PLANE_ADDR(i), 461 state->dscrs[i]->addr); 462 atmel_hlcdc_layer_write_reg(&plane->layer, 463 ATMEL_HLCDC_LAYER_PLANE_CTRL(i), 464 state->dscrs[i]->ctrl); 465 atmel_hlcdc_layer_write_reg(&plane->layer, 466 ATMEL_HLCDC_LAYER_PLANE_NEXT(i), 467 state->dscrs[i]->self); 468 } 469 470 if (desc->layout.xstride[i]) 471 atmel_hlcdc_layer_write_cfg(&plane->layer, 472 desc->layout.xstride[i], 473 state->xstride[i]); 474 475 if (desc->layout.pstride[i]) 476 atmel_hlcdc_layer_write_cfg(&plane->layer, 477 desc->layout.pstride[i], 478 state->pstride[i]); 479 } 480 } 481 482 int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state) 483 { 484 unsigned int ahb_load[2] = { }; 485 struct drm_plane *plane; 486 487 drm_atomic_crtc_state_for_each_plane(plane, c_state) { 488 struct atmel_hlcdc_plane_state *plane_state; 489 struct drm_plane_state *plane_s; 490 unsigned int pixels, load = 0; 491 int i; 492 493 plane_s = drm_atomic_get_plane_state(c_state->state, plane); 494 if (IS_ERR(plane_s)) 495 return PTR_ERR(plane_s); 496 497 plane_state = 498 drm_plane_state_to_atmel_hlcdc_plane_state(plane_s); 499 500 pixels = (plane_state->src_w * plane_state->src_h) - 501 (plane_state->disc_w * plane_state->disc_h); 502 503 for (i = 0; i < plane_state->nplanes; i++) 504 load += pixels * plane_state->bpp[i]; 505 506 if (ahb_load[0] <= ahb_load[1]) 507 plane_state->ahb_id = 0; 508 else 509 plane_state->ahb_id = 1; 510 511 ahb_load[plane_state->ahb_id] += load; 512 } 513 514 return 0; 515 } 516 517 int 518 atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state) 519 { 520 int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0; 521 const struct atmel_hlcdc_layer_cfg_layout *layout; 522 struct atmel_hlcdc_plane_state *primary_state; 523 struct drm_plane_state *primary_s; 524 struct atmel_hlcdc_plane *primary; 525 struct drm_plane *ovl; 526 527 primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary); 528 layout = &primary->layer.desc->layout; 529 if (!layout->disc_pos || !layout->disc_size) 530 return 0; 531 532 primary_s = drm_atomic_get_plane_state(c_state->state, 533 &primary->base); 534 if (IS_ERR(primary_s)) 535 return PTR_ERR(primary_s); 536 537 primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s); 538 539 drm_atomic_crtc_state_for_each_plane(ovl, c_state) { 540 struct atmel_hlcdc_plane_state *ovl_state; 541 struct drm_plane_state *ovl_s; 542 543 if (ovl == c_state->crtc->primary) 544 continue; 545 546 ovl_s = drm_atomic_get_plane_state(c_state->state, ovl); 547 if (IS_ERR(ovl_s)) 548 return PTR_ERR(ovl_s); 549 550 ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s); 551 552 if (!ovl_s->visible || 553 !ovl_s->fb || 554 ovl_s->fb->format->has_alpha || 555 ovl_s->alpha != DRM_BLEND_ALPHA_OPAQUE) 556 continue; 557 558 /* TODO: implement a smarter hidden area detection */ 559 if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w) 560 continue; 561 562 disc_x = ovl_state->crtc_x; 563 disc_y = ovl_state->crtc_y; 564 disc_h = ovl_state->crtc_h; 565 disc_w = ovl_state->crtc_w; 566 } 567 568 primary_state->disc_x = disc_x; 569 primary_state->disc_y = disc_y; 570 primary_state->disc_w = disc_w; 571 primary_state->disc_h = disc_h; 572 573 return 0; 574 } 575 576 static void 577 atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane, 578 struct atmel_hlcdc_plane_state *state) 579 { 580 const struct atmel_hlcdc_layer_cfg_layout *layout; 581 582 layout = &plane->layer.desc->layout; 583 if (!layout->disc_pos || !layout->disc_size) 584 return; 585 586 atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_pos, 587 ATMEL_HLCDC_LAYER_DISC_POS(state->disc_x, 588 state->disc_y)); 589 590 atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_size, 591 ATMEL_HLCDC_LAYER_DISC_SIZE(state->disc_w, 592 state->disc_h)); 593 } 594 595 static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p, 596 struct drm_plane_state *s) 597 { 598 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); 599 struct atmel_hlcdc_plane_state *state = 600 drm_plane_state_to_atmel_hlcdc_plane_state(s); 601 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc; 602 struct drm_framebuffer *fb = state->base.fb; 603 const struct drm_display_mode *mode; 604 struct drm_crtc_state *crtc_state; 605 int ret; 606 int i; 607 608 if (!state->base.crtc || WARN_ON(!fb)) 609 return 0; 610 611 crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc); 612 mode = &crtc_state->adjusted_mode; 613 614 ret = drm_atomic_helper_check_plane_state(s, crtc_state, 615 (1 << 16) / 2048, 616 INT_MAX, true, true); 617 if (ret || !s->visible) 618 return ret; 619 620 state->src_x = s->src.x1; 621 state->src_y = s->src.y1; 622 state->src_w = drm_rect_width(&s->src); 623 state->src_h = drm_rect_height(&s->src); 624 state->crtc_x = s->dst.x1; 625 state->crtc_y = s->dst.y1; 626 state->crtc_w = drm_rect_width(&s->dst); 627 state->crtc_h = drm_rect_height(&s->dst); 628 629 if ((state->src_x | state->src_y | state->src_w | state->src_h) & 630 SUBPIXEL_MASK) 631 return -EINVAL; 632 633 state->src_x >>= 16; 634 state->src_y >>= 16; 635 state->src_w >>= 16; 636 state->src_h >>= 16; 637 638 state->nplanes = fb->format->num_planes; 639 if (state->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES) 640 return -EINVAL; 641 642 for (i = 0; i < state->nplanes; i++) { 643 unsigned int offset = 0; 644 int xdiv = i ? fb->format->hsub : 1; 645 int ydiv = i ? fb->format->vsub : 1; 646 647 state->bpp[i] = fb->format->cpp[i]; 648 if (!state->bpp[i]) 649 return -EINVAL; 650 651 switch (state->base.rotation & DRM_MODE_ROTATE_MASK) { 652 case DRM_MODE_ROTATE_90: 653 offset = (state->src_y / ydiv) * 654 fb->pitches[i]; 655 offset += ((state->src_x + state->src_w - 1) / 656 xdiv) * state->bpp[i]; 657 state->xstride[i] = -(((state->src_h - 1) / ydiv) * 658 fb->pitches[i]) - 659 (2 * state->bpp[i]); 660 state->pstride[i] = fb->pitches[i] - state->bpp[i]; 661 break; 662 case DRM_MODE_ROTATE_180: 663 offset = ((state->src_y + state->src_h - 1) / 664 ydiv) * fb->pitches[i]; 665 offset += ((state->src_x + state->src_w - 1) / 666 xdiv) * state->bpp[i]; 667 state->xstride[i] = ((((state->src_w - 1) / xdiv) - 1) * 668 state->bpp[i]) - fb->pitches[i]; 669 state->pstride[i] = -2 * state->bpp[i]; 670 break; 671 case DRM_MODE_ROTATE_270: 672 offset = ((state->src_y + state->src_h - 1) / 673 ydiv) * fb->pitches[i]; 674 offset += (state->src_x / xdiv) * state->bpp[i]; 675 state->xstride[i] = ((state->src_h - 1) / ydiv) * 676 fb->pitches[i]; 677 state->pstride[i] = -fb->pitches[i] - state->bpp[i]; 678 break; 679 case DRM_MODE_ROTATE_0: 680 default: 681 offset = (state->src_y / ydiv) * fb->pitches[i]; 682 offset += (state->src_x / xdiv) * state->bpp[i]; 683 state->xstride[i] = fb->pitches[i] - 684 ((state->src_w / xdiv) * 685 state->bpp[i]); 686 state->pstride[i] = 0; 687 break; 688 } 689 690 state->offsets[i] = offset + fb->offsets[i]; 691 } 692 693 /* 694 * Swap width and size in case of 90 or 270 degrees rotation 695 */ 696 if (drm_rotation_90_or_270(state->base.rotation)) { 697 swap(state->src_w, state->src_h); 698 } 699 700 if (!desc->layout.size && 701 (mode->hdisplay != state->crtc_w || 702 mode->vdisplay != state->crtc_h)) 703 return -EINVAL; 704 705 if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) && 706 (!desc->layout.memsize || 707 state->base.fb->format->has_alpha)) 708 return -EINVAL; 709 710 return 0; 711 } 712 713 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p, 714 struct drm_plane_state *old_state) 715 { 716 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); 717 718 /* Disable interrupts */ 719 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR, 720 0xffffffff); 721 722 /* Disable the layer */ 723 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR, 724 ATMEL_HLCDC_LAYER_RST | 725 ATMEL_HLCDC_LAYER_A2Q | 726 ATMEL_HLCDC_LAYER_UPDATE); 727 728 /* Clear all pending interrupts */ 729 atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR); 730 } 731 732 static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p, 733 struct drm_plane_state *old_s) 734 { 735 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); 736 struct atmel_hlcdc_plane_state *state = 737 drm_plane_state_to_atmel_hlcdc_plane_state(p->state); 738 u32 sr; 739 740 if (!p->state->crtc || !p->state->fb) 741 return; 742 743 if (!state->base.visible) { 744 atmel_hlcdc_plane_atomic_disable(p, old_s); 745 return; 746 } 747 748 atmel_hlcdc_plane_update_pos_and_size(plane, state); 749 atmel_hlcdc_plane_update_general_settings(plane, state); 750 atmel_hlcdc_plane_update_format(plane, state); 751 atmel_hlcdc_plane_update_clut(plane, state); 752 atmel_hlcdc_plane_update_buffers(plane, state); 753 atmel_hlcdc_plane_update_disc_area(plane, state); 754 755 /* Enable the overrun interrupts. */ 756 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER, 757 ATMEL_HLCDC_LAYER_OVR_IRQ(0) | 758 ATMEL_HLCDC_LAYER_OVR_IRQ(1) | 759 ATMEL_HLCDC_LAYER_OVR_IRQ(2)); 760 761 /* Apply the new config at the next SOF event. */ 762 sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR); 763 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER, 764 ATMEL_HLCDC_LAYER_UPDATE | 765 (sr & ATMEL_HLCDC_LAYER_EN ? 766 ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN)); 767 } 768 769 static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane) 770 { 771 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc; 772 773 if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER || 774 desc->type == ATMEL_HLCDC_CURSOR_LAYER) { 775 int ret; 776 777 ret = drm_plane_create_alpha_property(&plane->base); 778 if (ret) 779 return ret; 780 } 781 782 if (desc->layout.xstride[0] && desc->layout.pstride[0]) { 783 int ret; 784 785 ret = drm_plane_create_rotation_property(&plane->base, 786 DRM_MODE_ROTATE_0, 787 DRM_MODE_ROTATE_0 | 788 DRM_MODE_ROTATE_90 | 789 DRM_MODE_ROTATE_180 | 790 DRM_MODE_ROTATE_270); 791 if (ret) 792 return ret; 793 } 794 795 if (desc->layout.csc) { 796 /* 797 * TODO: decare a "yuv-to-rgb-conv-factors" property to let 798 * userspace modify these factors (using a BLOB property ?). 799 */ 800 atmel_hlcdc_layer_write_cfg(&plane->layer, 801 desc->layout.csc, 802 0x4c900091); 803 atmel_hlcdc_layer_write_cfg(&plane->layer, 804 desc->layout.csc + 1, 805 0x7a5f5090); 806 atmel_hlcdc_layer_write_cfg(&plane->layer, 807 desc->layout.csc + 2, 808 0x40040890); 809 } 810 811 return 0; 812 } 813 814 void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane) 815 { 816 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc; 817 u32 isr; 818 819 isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR); 820 821 /* 822 * There's not much we can do in case of overrun except informing 823 * the user. However, we are in interrupt context here, hence the 824 * use of dev_dbg(). 825 */ 826 if (isr & 827 (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) | 828 ATMEL_HLCDC_LAYER_OVR_IRQ(2))) 829 dev_dbg(plane->base.dev->dev, "overrun on plane %s\n", 830 desc->name); 831 } 832 833 static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = { 834 .atomic_check = atmel_hlcdc_plane_atomic_check, 835 .atomic_update = atmel_hlcdc_plane_atomic_update, 836 .atomic_disable = atmel_hlcdc_plane_atomic_disable, 837 }; 838 839 static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p, 840 struct atmel_hlcdc_plane_state *state) 841 { 842 struct atmel_hlcdc_dc *dc = p->dev->dev_private; 843 int i; 844 845 for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) { 846 struct atmel_hlcdc_dma_channel_dscr *dscr; 847 dma_addr_t dscr_dma; 848 849 dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma); 850 if (!dscr) 851 goto err; 852 853 dscr->addr = 0; 854 dscr->next = dscr_dma; 855 dscr->self = dscr_dma; 856 dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH; 857 858 state->dscrs[i] = dscr; 859 } 860 861 return 0; 862 863 err: 864 for (i--; i >= 0; i--) { 865 dma_pool_free(dc->dscrpool, state->dscrs[i], 866 state->dscrs[i]->self); 867 } 868 869 return -ENOMEM; 870 } 871 872 static void atmel_hlcdc_plane_reset(struct drm_plane *p) 873 { 874 struct atmel_hlcdc_plane_state *state; 875 876 if (p->state) { 877 state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state); 878 879 if (state->base.fb) 880 drm_framebuffer_put(state->base.fb); 881 882 kfree(state); 883 p->state = NULL; 884 } 885 886 state = kzalloc(sizeof(*state), GFP_KERNEL); 887 if (state) { 888 if (atmel_hlcdc_plane_alloc_dscrs(p, state)) { 889 kfree(state); 890 dev_err(p->dev->dev, 891 "Failed to allocate initial plane state\n"); 892 return; 893 } 894 __drm_atomic_helper_plane_reset(p, &state->base); 895 } 896 } 897 898 static struct drm_plane_state * 899 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p) 900 { 901 struct atmel_hlcdc_plane_state *state = 902 drm_plane_state_to_atmel_hlcdc_plane_state(p->state); 903 struct atmel_hlcdc_plane_state *copy; 904 905 copy = kmemdup(state, sizeof(*state), GFP_KERNEL); 906 if (!copy) 907 return NULL; 908 909 if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) { 910 kfree(copy); 911 return NULL; 912 } 913 914 if (copy->base.fb) 915 drm_framebuffer_get(copy->base.fb); 916 917 return ©->base; 918 } 919 920 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p, 921 struct drm_plane_state *s) 922 { 923 struct atmel_hlcdc_plane_state *state = 924 drm_plane_state_to_atmel_hlcdc_plane_state(s); 925 struct atmel_hlcdc_dc *dc = p->dev->dev_private; 926 int i; 927 928 for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) { 929 dma_pool_free(dc->dscrpool, state->dscrs[i], 930 state->dscrs[i]->self); 931 } 932 933 if (s->fb) 934 drm_framebuffer_put(s->fb); 935 936 kfree(state); 937 } 938 939 static const struct drm_plane_funcs layer_plane_funcs = { 940 .update_plane = drm_atomic_helper_update_plane, 941 .disable_plane = drm_atomic_helper_disable_plane, 942 .destroy = drm_plane_cleanup, 943 .reset = atmel_hlcdc_plane_reset, 944 .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state, 945 .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state, 946 }; 947 948 static int atmel_hlcdc_plane_create(struct drm_device *dev, 949 const struct atmel_hlcdc_layer_desc *desc) 950 { 951 struct atmel_hlcdc_dc *dc = dev->dev_private; 952 struct atmel_hlcdc_plane *plane; 953 enum drm_plane_type type; 954 int ret; 955 956 plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL); 957 if (!plane) 958 return -ENOMEM; 959 960 atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap); 961 962 if (desc->type == ATMEL_HLCDC_BASE_LAYER) 963 type = DRM_PLANE_TYPE_PRIMARY; 964 else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER) 965 type = DRM_PLANE_TYPE_CURSOR; 966 else 967 type = DRM_PLANE_TYPE_OVERLAY; 968 969 ret = drm_universal_plane_init(dev, &plane->base, 0, 970 &layer_plane_funcs, 971 desc->formats->formats, 972 desc->formats->nformats, 973 NULL, type, NULL); 974 if (ret) 975 return ret; 976 977 drm_plane_helper_add(&plane->base, 978 &atmel_hlcdc_layer_plane_helper_funcs); 979 980 /* Set default property values*/ 981 ret = atmel_hlcdc_plane_init_properties(plane); 982 if (ret) 983 return ret; 984 985 dc->layers[desc->id] = &plane->layer; 986 987 return 0; 988 } 989 990 int atmel_hlcdc_create_planes(struct drm_device *dev) 991 { 992 struct atmel_hlcdc_dc *dc = dev->dev_private; 993 const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers; 994 int nlayers = dc->desc->nlayers; 995 int i, ret; 996 997 dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev, 998 sizeof(struct atmel_hlcdc_dma_channel_dscr), 999 sizeof(u64), 0); 1000 if (!dc->dscrpool) 1001 return -ENOMEM; 1002 1003 for (i = 0; i < nlayers; i++) { 1004 if (descs[i].type != ATMEL_HLCDC_BASE_LAYER && 1005 descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER && 1006 descs[i].type != ATMEL_HLCDC_CURSOR_LAYER) 1007 continue; 1008 1009 ret = atmel_hlcdc_plane_create(dev, &descs[i]); 1010 if (ret) 1011 return ret; 1012 } 1013 1014 return 0; 1015 } 1016