1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2023 Loongson Technology Corporation Limited 4 */ 5 6 #include <linux/delay.h> 7 8 #include <drm/drm_atomic.h> 9 #include <drm/drm_atomic_helper.h> 10 #include <drm/drm_blend.h> 11 #include <drm/drm_framebuffer.h> 12 #include <drm/drm_gem_atomic_helper.h> 13 #include <drm/drm_print.h> 14 15 #include "lsdc_drv.h" 16 #include "lsdc_regs.h" 17 #include "lsdc_ttm.h" 18 19 static const u32 lsdc_primary_formats[] = { 20 DRM_FORMAT_XRGB8888, 21 }; 22 23 static const u32 lsdc_cursor_formats[] = { 24 DRM_FORMAT_ARGB8888, 25 }; 26 27 static const u64 lsdc_fb_format_modifiers[] = { 28 DRM_FORMAT_MOD_LINEAR, 29 DRM_FORMAT_MOD_INVALID 30 }; 31 32 static unsigned int lsdc_get_fb_offset(struct drm_framebuffer *fb, 33 struct drm_plane_state *state) 34 { 35 unsigned int offset = fb->offsets[0]; 36 37 offset += fb->format->cpp[0] * (state->src_x >> 16); 38 offset += fb->pitches[0] * (state->src_y >> 16); 39 40 return offset; 41 } 42 43 static u64 lsdc_fb_base_addr(struct drm_framebuffer *fb) 44 { 45 struct lsdc_device *ldev = to_lsdc(fb->dev); 46 struct lsdc_bo *lbo = gem_to_lsdc_bo(fb->obj[0]); 47 48 return lsdc_bo_gpu_offset(lbo) + ldev->vram_base; 49 } 50 51 static int lsdc_primary_atomic_check(struct drm_plane *plane, 52 struct drm_atomic_commit *state) 53 { 54 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); 55 struct drm_crtc *crtc = new_plane_state->crtc; 56 struct drm_crtc_state *new_crtc_state; 57 58 if (!crtc) 59 return 0; 60 61 new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 62 63 return drm_atomic_helper_check_plane_state(new_plane_state, 64 new_crtc_state, 65 DRM_PLANE_NO_SCALING, 66 DRM_PLANE_NO_SCALING, 67 false, true); 68 } 69 70 static void lsdc_primary_atomic_update(struct drm_plane *plane, 71 struct drm_atomic_commit *state) 72 { 73 struct lsdc_primary *primary = to_lsdc_primary(plane); 74 const struct lsdc_primary_plane_ops *ops = primary->ops; 75 struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); 76 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); 77 struct drm_framebuffer *new_fb = new_plane_state->fb; 78 struct drm_framebuffer *old_fb = old_plane_state->fb; 79 u64 fb_addr = lsdc_fb_base_addr(new_fb); 80 81 fb_addr += lsdc_get_fb_offset(new_fb, new_plane_state); 82 83 ops->update_fb_addr(primary, fb_addr); 84 ops->update_fb_stride(primary, new_fb->pitches[0]); 85 86 if (!old_fb || old_fb->format != new_fb->format) 87 ops->update_fb_format(primary, new_fb->format); 88 } 89 90 static void lsdc_primary_atomic_disable(struct drm_plane *plane, 91 struct drm_atomic_commit *state) 92 { 93 /* 94 * Do nothing, just prevent call into atomic_update(). 95 * Writing the format as LSDC_PF_NONE can disable the primary, 96 * But it seems not necessary... 97 */ 98 drm_dbg(plane->dev, "%s disabled\n", plane->name); 99 } 100 101 static int lsdc_plane_prepare_fb(struct drm_plane *plane, 102 struct drm_plane_state *new_state) 103 { 104 struct drm_framebuffer *fb = new_state->fb; 105 struct lsdc_bo *lbo; 106 u64 gpu_vaddr; 107 int ret; 108 109 if (!fb) 110 return 0; 111 112 lbo = gem_to_lsdc_bo(fb->obj[0]); 113 114 ret = lsdc_bo_reserve(lbo); 115 if (unlikely(ret)) { 116 drm_err(plane->dev, "bo %p reserve failed\n", lbo); 117 return ret; 118 } 119 120 ret = lsdc_bo_pin(lbo, LSDC_GEM_DOMAIN_VRAM, &gpu_vaddr); 121 122 lsdc_bo_unreserve(lbo); 123 124 if (unlikely(ret)) { 125 drm_err(plane->dev, "bo %p pin failed\n", lbo); 126 return ret; 127 } 128 129 lsdc_bo_ref(lbo); 130 131 if (plane->type != DRM_PLANE_TYPE_CURSOR) 132 drm_dbg(plane->dev, 133 "%s[%p] pin at 0x%llx, bo size: %zu\n", 134 plane->name, lbo, gpu_vaddr, lsdc_bo_size(lbo)); 135 136 return drm_gem_plane_helper_prepare_fb(plane, new_state); 137 } 138 139 static void lsdc_plane_cleanup_fb(struct drm_plane *plane, 140 struct drm_plane_state *old_state) 141 { 142 struct drm_framebuffer *fb = old_state->fb; 143 struct lsdc_bo *lbo; 144 int ret; 145 146 if (!fb) 147 return; 148 149 lbo = gem_to_lsdc_bo(fb->obj[0]); 150 151 ret = lsdc_bo_reserve(lbo); 152 if (unlikely(ret)) { 153 drm_err(plane->dev, "%p reserve failed\n", lbo); 154 return; 155 } 156 157 lsdc_bo_unpin(lbo); 158 159 lsdc_bo_unreserve(lbo); 160 161 lsdc_bo_unref(lbo); 162 163 if (plane->type != DRM_PLANE_TYPE_CURSOR) 164 drm_dbg(plane->dev, "%s unpin\n", plane->name); 165 } 166 167 static const struct drm_plane_helper_funcs lsdc_primary_helper_funcs = { 168 .prepare_fb = lsdc_plane_prepare_fb, 169 .cleanup_fb = lsdc_plane_cleanup_fb, 170 .atomic_check = lsdc_primary_atomic_check, 171 .atomic_update = lsdc_primary_atomic_update, 172 .atomic_disable = lsdc_primary_atomic_disable, 173 }; 174 175 static int lsdc_cursor_plane_atomic_async_check(struct drm_plane *plane, 176 struct drm_atomic_commit *state, 177 bool flip) 178 { 179 struct drm_plane_state *new_state; 180 struct drm_crtc_state *crtc_state; 181 182 new_state = drm_atomic_get_new_plane_state(state, plane); 183 184 if (!plane->state || !plane->state->fb) { 185 drm_dbg(plane->dev, "%s: state is NULL\n", plane->name); 186 return -EINVAL; 187 } 188 189 if (new_state->crtc_w != new_state->crtc_h) { 190 drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n", 191 new_state->crtc_w, new_state->crtc_h); 192 return -EINVAL; 193 } 194 195 if (new_state->crtc_w != 64 && new_state->crtc_w != 32) { 196 drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n", 197 new_state->crtc_w, new_state->crtc_h); 198 return -EINVAL; 199 } 200 201 crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc); 202 if (!crtc_state->active) 203 return -EINVAL; 204 205 if (plane->state->crtc != new_state->crtc || 206 plane->state->src_w != new_state->src_w || 207 plane->state->src_h != new_state->src_h || 208 plane->state->crtc_w != new_state->crtc_w || 209 plane->state->crtc_h != new_state->crtc_h) 210 return -EINVAL; 211 212 if (new_state->visible != plane->state->visible) 213 return -EINVAL; 214 215 return drm_atomic_helper_check_plane_state(plane->state, 216 crtc_state, 217 DRM_PLANE_NO_SCALING, 218 DRM_PLANE_NO_SCALING, 219 true, true); 220 } 221 222 static void lsdc_cursor_plane_atomic_async_update(struct drm_plane *plane, 223 struct drm_atomic_commit *state) 224 { 225 struct lsdc_cursor *cursor = to_lsdc_cursor(plane); 226 const struct lsdc_cursor_plane_ops *ops = cursor->ops; 227 struct drm_framebuffer *old_fb = plane->state->fb; 228 struct drm_framebuffer *new_fb; 229 struct drm_plane_state *new_state; 230 231 new_state = drm_atomic_get_new_plane_state(state, plane); 232 233 new_fb = plane->state->fb; 234 235 plane->state->crtc_x = new_state->crtc_x; 236 plane->state->crtc_y = new_state->crtc_y; 237 plane->state->crtc_h = new_state->crtc_h; 238 plane->state->crtc_w = new_state->crtc_w; 239 plane->state->src_x = new_state->src_x; 240 plane->state->src_y = new_state->src_y; 241 plane->state->src_h = new_state->src_h; 242 plane->state->src_w = new_state->src_w; 243 swap(plane->state->fb, new_state->fb); 244 245 if (new_state->visible) { 246 enum lsdc_cursor_size cursor_size; 247 248 switch (new_state->crtc_w) { 249 case 64: 250 cursor_size = CURSOR_SIZE_64X64; 251 break; 252 case 32: 253 cursor_size = CURSOR_SIZE_32X32; 254 break; 255 default: 256 cursor_size = CURSOR_SIZE_32X32; 257 break; 258 } 259 260 ops->update_position(cursor, new_state->crtc_x, new_state->crtc_y); 261 262 ops->update_cfg(cursor, cursor_size, CURSOR_FORMAT_ARGB8888); 263 264 if (!old_fb || old_fb != new_fb) 265 ops->update_bo_addr(cursor, lsdc_fb_base_addr(new_fb)); 266 } 267 } 268 269 /* ls7a1000 cursor plane helpers */ 270 271 static int ls7a1000_cursor_plane_atomic_check(struct drm_plane *plane, 272 struct drm_atomic_commit *state) 273 { 274 struct drm_plane_state *new_plane_state; 275 struct drm_crtc_state *new_crtc_state; 276 struct drm_crtc *crtc; 277 278 new_plane_state = drm_atomic_get_new_plane_state(state, plane); 279 280 crtc = new_plane_state->crtc; 281 if (!crtc) { 282 drm_dbg(plane->dev, "%s is not bind to a crtc\n", plane->name); 283 return 0; 284 } 285 286 if (new_plane_state->crtc_w != 32 || new_plane_state->crtc_h != 32) { 287 drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n", 288 new_plane_state->crtc_w, new_plane_state->crtc_h); 289 return -EINVAL; 290 } 291 292 new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 293 294 return drm_atomic_helper_check_plane_state(new_plane_state, 295 new_crtc_state, 296 DRM_PLANE_NO_SCALING, 297 DRM_PLANE_NO_SCALING, 298 true, true); 299 } 300 301 static void ls7a1000_cursor_plane_atomic_update(struct drm_plane *plane, 302 struct drm_atomic_commit *state) 303 { 304 struct lsdc_cursor *cursor = to_lsdc_cursor(plane); 305 struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); 306 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); 307 struct drm_framebuffer *new_fb = new_plane_state->fb; 308 struct drm_framebuffer *old_fb = old_plane_state->fb; 309 const struct lsdc_cursor_plane_ops *ops = cursor->ops; 310 u64 addr = lsdc_fb_base_addr(new_fb); 311 312 if (!new_plane_state->visible) 313 return; 314 315 ops->update_position(cursor, new_plane_state->crtc_x, new_plane_state->crtc_y); 316 317 if (!old_fb || old_fb != new_fb) 318 ops->update_bo_addr(cursor, addr); 319 320 ops->update_cfg(cursor, CURSOR_SIZE_32X32, CURSOR_FORMAT_ARGB8888); 321 } 322 323 static void ls7a1000_cursor_plane_atomic_disable(struct drm_plane *plane, 324 struct drm_atomic_commit *state) 325 { 326 struct lsdc_cursor *cursor = to_lsdc_cursor(plane); 327 const struct lsdc_cursor_plane_ops *ops = cursor->ops; 328 329 ops->update_cfg(cursor, CURSOR_SIZE_32X32, CURSOR_FORMAT_DISABLE); 330 } 331 332 static const struct drm_plane_helper_funcs ls7a1000_cursor_plane_helper_funcs = { 333 .prepare_fb = lsdc_plane_prepare_fb, 334 .cleanup_fb = lsdc_plane_cleanup_fb, 335 .atomic_check = ls7a1000_cursor_plane_atomic_check, 336 .atomic_update = ls7a1000_cursor_plane_atomic_update, 337 .atomic_disable = ls7a1000_cursor_plane_atomic_disable, 338 .atomic_async_check = lsdc_cursor_plane_atomic_async_check, 339 .atomic_async_update = lsdc_cursor_plane_atomic_async_update, 340 }; 341 342 /* ls7a2000 cursor plane helpers */ 343 344 static int ls7a2000_cursor_plane_atomic_check(struct drm_plane *plane, 345 struct drm_atomic_commit *state) 346 { 347 struct drm_plane_state *new_plane_state; 348 struct drm_crtc_state *new_crtc_state; 349 struct drm_crtc *crtc; 350 351 new_plane_state = drm_atomic_get_new_plane_state(state, plane); 352 353 crtc = new_plane_state->crtc; 354 if (!crtc) { 355 drm_dbg(plane->dev, "%s is not bind to a crtc\n", plane->name); 356 return 0; 357 } 358 359 if (new_plane_state->crtc_w != new_plane_state->crtc_h) { 360 drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n", 361 new_plane_state->crtc_w, new_plane_state->crtc_h); 362 return -EINVAL; 363 } 364 365 if (new_plane_state->crtc_w != 64 && new_plane_state->crtc_w != 32) { 366 drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n", 367 new_plane_state->crtc_w, new_plane_state->crtc_h); 368 return -EINVAL; 369 } 370 371 new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 372 373 return drm_atomic_helper_check_plane_state(new_plane_state, 374 new_crtc_state, 375 DRM_PLANE_NO_SCALING, 376 DRM_PLANE_NO_SCALING, 377 true, true); 378 } 379 380 /* Update the format, size and location of the cursor */ 381 382 static void ls7a2000_cursor_plane_atomic_update(struct drm_plane *plane, 383 struct drm_atomic_commit *state) 384 { 385 struct lsdc_cursor *cursor = to_lsdc_cursor(plane); 386 struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); 387 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); 388 struct drm_framebuffer *new_fb = new_plane_state->fb; 389 struct drm_framebuffer *old_fb = old_plane_state->fb; 390 const struct lsdc_cursor_plane_ops *ops = cursor->ops; 391 enum lsdc_cursor_size cursor_size; 392 393 if (!new_plane_state->visible) 394 return; 395 396 ops->update_position(cursor, new_plane_state->crtc_x, new_plane_state->crtc_y); 397 398 if (!old_fb || new_fb != old_fb) { 399 u64 addr = lsdc_fb_base_addr(new_fb); 400 401 ops->update_bo_addr(cursor, addr); 402 } 403 404 switch (new_plane_state->crtc_w) { 405 case 64: 406 cursor_size = CURSOR_SIZE_64X64; 407 break; 408 case 32: 409 cursor_size = CURSOR_SIZE_32X32; 410 break; 411 default: 412 cursor_size = CURSOR_SIZE_64X64; 413 break; 414 } 415 416 ops->update_cfg(cursor, cursor_size, CURSOR_FORMAT_ARGB8888); 417 } 418 419 static void ls7a2000_cursor_plane_atomic_disable(struct drm_plane *plane, 420 struct drm_atomic_commit *state) 421 { 422 struct lsdc_cursor *cursor = to_lsdc_cursor(plane); 423 const struct lsdc_cursor_plane_ops *hw_ops = cursor->ops; 424 425 hw_ops->update_cfg(cursor, CURSOR_SIZE_64X64, CURSOR_FORMAT_DISABLE); 426 } 427 428 static const struct drm_plane_helper_funcs ls7a2000_cursor_plane_helper_funcs = { 429 .prepare_fb = lsdc_plane_prepare_fb, 430 .cleanup_fb = lsdc_plane_cleanup_fb, 431 .atomic_check = ls7a2000_cursor_plane_atomic_check, 432 .atomic_update = ls7a2000_cursor_plane_atomic_update, 433 .atomic_disable = ls7a2000_cursor_plane_atomic_disable, 434 .atomic_async_check = lsdc_cursor_plane_atomic_async_check, 435 .atomic_async_update = lsdc_cursor_plane_atomic_async_update, 436 }; 437 438 static void lsdc_plane_atomic_print_state(struct drm_printer *p, 439 const struct drm_plane_state *state) 440 { 441 struct drm_framebuffer *fb = state->fb; 442 u64 addr; 443 444 if (!fb) 445 return; 446 447 addr = lsdc_fb_base_addr(fb); 448 449 drm_printf(p, "\tdma addr=%llx\n", addr); 450 } 451 452 static const struct drm_plane_funcs lsdc_plane_funcs = { 453 .update_plane = drm_atomic_helper_update_plane, 454 .disable_plane = drm_atomic_helper_disable_plane, 455 .destroy = drm_plane_cleanup, 456 .reset = drm_atomic_helper_plane_reset, 457 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 458 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 459 .atomic_print_state = lsdc_plane_atomic_print_state, 460 }; 461 462 /* Primary plane 0 hardware related ops */ 463 464 static void lsdc_primary0_update_fb_addr(struct lsdc_primary *primary, u64 addr) 465 { 466 struct lsdc_device *ldev = primary->ldev; 467 u32 status; 468 u32 lo, hi; 469 470 /* 40-bit width physical address bus */ 471 lo = addr & 0xFFFFFFFF; 472 hi = (addr >> 32) & 0xFF; 473 474 status = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG); 475 if (status & FB_REG_IN_USING) { 476 lsdc_wreg32(ldev, LSDC_CRTC0_FB1_ADDR_LO_REG, lo); 477 lsdc_wreg32(ldev, LSDC_CRTC0_FB1_ADDR_HI_REG, hi); 478 } else { 479 lsdc_wreg32(ldev, LSDC_CRTC0_FB0_ADDR_LO_REG, lo); 480 lsdc_wreg32(ldev, LSDC_CRTC0_FB0_ADDR_HI_REG, hi); 481 } 482 } 483 484 static void lsdc_primary0_update_fb_stride(struct lsdc_primary *primary, u32 stride) 485 { 486 struct lsdc_device *ldev = primary->ldev; 487 488 lsdc_wreg32(ldev, LSDC_CRTC0_STRIDE_REG, stride); 489 } 490 491 static void lsdc_primary0_update_fb_format(struct lsdc_primary *primary, 492 const struct drm_format_info *format) 493 { 494 struct lsdc_device *ldev = primary->ldev; 495 u32 status; 496 497 status = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG); 498 499 /* 500 * TODO: add RGB565 support, only support XRBG8888 at present 501 */ 502 status &= ~CFG_PIX_FMT_MASK; 503 status |= LSDC_PF_XRGB8888; 504 505 lsdc_wreg32(ldev, LSDC_CRTC0_CFG_REG, status); 506 } 507 508 /* Primary plane 1 hardware related ops */ 509 510 static void lsdc_primary1_update_fb_addr(struct lsdc_primary *primary, u64 addr) 511 { 512 struct lsdc_device *ldev = primary->ldev; 513 u32 status; 514 u32 lo, hi; 515 516 /* 40-bit width physical address bus */ 517 lo = addr & 0xFFFFFFFF; 518 hi = (addr >> 32) & 0xFF; 519 520 status = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG); 521 if (status & FB_REG_IN_USING) { 522 lsdc_wreg32(ldev, LSDC_CRTC1_FB1_ADDR_LO_REG, lo); 523 lsdc_wreg32(ldev, LSDC_CRTC1_FB1_ADDR_HI_REG, hi); 524 } else { 525 lsdc_wreg32(ldev, LSDC_CRTC1_FB0_ADDR_LO_REG, lo); 526 lsdc_wreg32(ldev, LSDC_CRTC1_FB0_ADDR_HI_REG, hi); 527 } 528 } 529 530 static void lsdc_primary1_update_fb_stride(struct lsdc_primary *primary, u32 stride) 531 { 532 struct lsdc_device *ldev = primary->ldev; 533 534 lsdc_wreg32(ldev, LSDC_CRTC1_STRIDE_REG, stride); 535 } 536 537 static void lsdc_primary1_update_fb_format(struct lsdc_primary *primary, 538 const struct drm_format_info *format) 539 { 540 struct lsdc_device *ldev = primary->ldev; 541 u32 status; 542 543 status = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG); 544 545 /* 546 * TODO: add RGB565 support, only support XRBG8888 at present 547 */ 548 status &= ~CFG_PIX_FMT_MASK; 549 status |= LSDC_PF_XRGB8888; 550 551 lsdc_wreg32(ldev, LSDC_CRTC1_CFG_REG, status); 552 } 553 554 static const struct lsdc_primary_plane_ops lsdc_primary_plane_hw_ops[2] = { 555 { 556 .update_fb_addr = lsdc_primary0_update_fb_addr, 557 .update_fb_stride = lsdc_primary0_update_fb_stride, 558 .update_fb_format = lsdc_primary0_update_fb_format, 559 }, 560 { 561 .update_fb_addr = lsdc_primary1_update_fb_addr, 562 .update_fb_stride = lsdc_primary1_update_fb_stride, 563 .update_fb_format = lsdc_primary1_update_fb_format, 564 }, 565 }; 566 567 /* 568 * Update location, format, enable and disable state of the cursor, 569 * For those who have two hardware cursor, let cursor 0 is attach to CRTC-0, 570 * cursor 1 is attach to CRTC-1. Compositing the primary plane and cursor 571 * plane is automatically done by hardware, the cursor is alway on the top of 572 * the primary plane. In other word, z-order is fixed in hardware and cannot 573 * be changed. For those old DC who has only one hardware cursor, we made it 574 * shared by the two screen, this works on extend screen mode. 575 */ 576 577 /* cursor plane 0 (for pipe 0) related hardware ops */ 578 579 static void lsdc_cursor0_update_bo_addr(struct lsdc_cursor *cursor, u64 addr) 580 { 581 struct lsdc_device *ldev = cursor->ldev; 582 583 /* 40-bit width physical address bus */ 584 lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_HI_REG, (addr >> 32) & 0xFF); 585 lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_LO_REG, addr); 586 } 587 588 static void lsdc_cursor0_update_position(struct lsdc_cursor *cursor, int x, int y) 589 { 590 struct lsdc_device *ldev = cursor->ldev; 591 592 if (x < 0) 593 x = 0; 594 595 if (y < 0) 596 y = 0; 597 598 lsdc_wreg32(ldev, LSDC_CURSOR0_POSITION_REG, (y << 16) | x); 599 } 600 601 static void lsdc_cursor0_update_cfg(struct lsdc_cursor *cursor, 602 enum lsdc_cursor_size cursor_size, 603 enum lsdc_cursor_format fmt) 604 { 605 struct lsdc_device *ldev = cursor->ldev; 606 u32 cfg; 607 608 cfg = CURSOR_ON_CRTC0 << CURSOR_LOCATION_SHIFT | 609 cursor_size << CURSOR_SIZE_SHIFT | 610 fmt << CURSOR_FORMAT_SHIFT; 611 612 lsdc_wreg32(ldev, LSDC_CURSOR0_CFG_REG, cfg); 613 } 614 615 /* cursor plane 1 (for pipe 1) related hardware ops */ 616 617 static void lsdc_cursor1_update_bo_addr(struct lsdc_cursor *cursor, u64 addr) 618 { 619 struct lsdc_device *ldev = cursor->ldev; 620 621 /* 40-bit width physical address bus */ 622 lsdc_wreg32(ldev, LSDC_CURSOR1_ADDR_HI_REG, (addr >> 32) & 0xFF); 623 lsdc_wreg32(ldev, LSDC_CURSOR1_ADDR_LO_REG, addr); 624 } 625 626 static void lsdc_cursor1_update_position(struct lsdc_cursor *cursor, int x, int y) 627 { 628 struct lsdc_device *ldev = cursor->ldev; 629 630 if (x < 0) 631 x = 0; 632 633 if (y < 0) 634 y = 0; 635 636 lsdc_wreg32(ldev, LSDC_CURSOR1_POSITION_REG, (y << 16) | x); 637 } 638 639 static void lsdc_cursor1_update_cfg(struct lsdc_cursor *cursor, 640 enum lsdc_cursor_size cursor_size, 641 enum lsdc_cursor_format fmt) 642 { 643 struct lsdc_device *ldev = cursor->ldev; 644 u32 cfg; 645 646 cfg = CURSOR_ON_CRTC1 << CURSOR_LOCATION_SHIFT | 647 cursor_size << CURSOR_SIZE_SHIFT | 648 fmt << CURSOR_FORMAT_SHIFT; 649 650 lsdc_wreg32(ldev, LSDC_CURSOR1_CFG_REG, cfg); 651 } 652 653 /* The hardware cursors become normal since ls7a2000/ls2k2000 */ 654 655 static const struct lsdc_cursor_plane_ops ls7a2000_cursor_hw_ops[2] = { 656 { 657 .update_bo_addr = lsdc_cursor0_update_bo_addr, 658 .update_cfg = lsdc_cursor0_update_cfg, 659 .update_position = lsdc_cursor0_update_position, 660 }, 661 { 662 .update_bo_addr = lsdc_cursor1_update_bo_addr, 663 .update_cfg = lsdc_cursor1_update_cfg, 664 .update_position = lsdc_cursor1_update_position, 665 }, 666 }; 667 668 /* Quirks for cursor 1, only for old loongson display controller */ 669 670 static void lsdc_cursor1_update_bo_addr_quirk(struct lsdc_cursor *cursor, u64 addr) 671 { 672 struct lsdc_device *ldev = cursor->ldev; 673 674 /* 40-bit width physical address bus */ 675 lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_HI_REG, (addr >> 32) & 0xFF); 676 lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_LO_REG, addr); 677 } 678 679 static void lsdc_cursor1_update_position_quirk(struct lsdc_cursor *cursor, int x, int y) 680 { 681 struct lsdc_device *ldev = cursor->ldev; 682 683 if (x < 0) 684 x = 0; 685 686 if (y < 0) 687 y = 0; 688 689 lsdc_wreg32(ldev, LSDC_CURSOR0_POSITION_REG, (y << 16) | x); 690 } 691 692 static void lsdc_cursor1_update_cfg_quirk(struct lsdc_cursor *cursor, 693 enum lsdc_cursor_size cursor_size, 694 enum lsdc_cursor_format fmt) 695 { 696 struct lsdc_device *ldev = cursor->ldev; 697 u32 cfg; 698 699 cfg = CURSOR_ON_CRTC1 << CURSOR_LOCATION_SHIFT | 700 cursor_size << CURSOR_SIZE_SHIFT | 701 fmt << CURSOR_FORMAT_SHIFT; 702 703 lsdc_wreg32(ldev, LSDC_CURSOR0_CFG_REG, cfg); 704 } 705 706 /* 707 * The unforgiving LS7A1000/LS2K1000 has only one hardware cursors plane 708 */ 709 static const struct lsdc_cursor_plane_ops ls7a1000_cursor_hw_ops[2] = { 710 { 711 .update_bo_addr = lsdc_cursor0_update_bo_addr, 712 .update_cfg = lsdc_cursor0_update_cfg, 713 .update_position = lsdc_cursor0_update_position, 714 }, 715 { 716 .update_bo_addr = lsdc_cursor1_update_bo_addr_quirk, 717 .update_cfg = lsdc_cursor1_update_cfg_quirk, 718 .update_position = lsdc_cursor1_update_position_quirk, 719 }, 720 }; 721 722 int lsdc_primary_plane_init(struct drm_device *ddev, 723 struct drm_plane *plane, 724 unsigned int index) 725 { 726 struct lsdc_primary *primary = to_lsdc_primary(plane); 727 int ret; 728 729 ret = drm_universal_plane_init(ddev, plane, 1 << index, 730 &lsdc_plane_funcs, 731 lsdc_primary_formats, 732 ARRAY_SIZE(lsdc_primary_formats), 733 lsdc_fb_format_modifiers, 734 DRM_PLANE_TYPE_PRIMARY, 735 "ls-primary-plane-%u", index); 736 if (ret) 737 return ret; 738 739 drm_plane_helper_add(plane, &lsdc_primary_helper_funcs); 740 741 primary->ldev = to_lsdc(ddev); 742 primary->ops = &lsdc_primary_plane_hw_ops[index]; 743 744 return 0; 745 } 746 747 int ls7a1000_cursor_plane_init(struct drm_device *ddev, 748 struct drm_plane *plane, 749 unsigned int index) 750 { 751 struct lsdc_cursor *cursor = to_lsdc_cursor(plane); 752 int ret; 753 754 ret = drm_universal_plane_init(ddev, plane, 1 << index, 755 &lsdc_plane_funcs, 756 lsdc_cursor_formats, 757 ARRAY_SIZE(lsdc_cursor_formats), 758 lsdc_fb_format_modifiers, 759 DRM_PLANE_TYPE_CURSOR, 760 "ls-cursor-plane-%u", index); 761 if (ret) 762 return ret; 763 764 cursor->ldev = to_lsdc(ddev); 765 cursor->ops = &ls7a1000_cursor_hw_ops[index]; 766 767 drm_plane_helper_add(plane, &ls7a1000_cursor_plane_helper_funcs); 768 769 return drm_plane_create_blend_mode_property(plane, BIT(DRM_MODE_BLEND_COVERAGE)); 770 } 771 772 int ls7a2000_cursor_plane_init(struct drm_device *ddev, 773 struct drm_plane *plane, 774 unsigned int index) 775 { 776 struct lsdc_cursor *cursor = to_lsdc_cursor(plane); 777 int ret; 778 779 ret = drm_universal_plane_init(ddev, plane, 1 << index, 780 &lsdc_plane_funcs, 781 lsdc_cursor_formats, 782 ARRAY_SIZE(lsdc_cursor_formats), 783 lsdc_fb_format_modifiers, 784 DRM_PLANE_TYPE_CURSOR, 785 "ls-cursor-plane-%u", index); 786 if (ret) 787 return ret; 788 789 cursor->ldev = to_lsdc(ddev); 790 cursor->ops = &ls7a2000_cursor_hw_ops[index]; 791 792 drm_plane_helper_add(plane, &ls7a2000_cursor_plane_helper_funcs); 793 794 return drm_plane_create_blend_mode_property(plane, BIT(DRM_MODE_BLEND_COVERAGE)); 795 } 796