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