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