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