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 crtc_state = drm_atomic_get_existing_crtc_state(state, new_state->crtc); 200 if (!crtc_state->active) 201 return -EINVAL; 202 203 if (plane->state->crtc != new_state->crtc || 204 plane->state->src_w != new_state->src_w || 205 plane->state->src_h != new_state->src_h || 206 plane->state->crtc_w != new_state->crtc_w || 207 plane->state->crtc_h != new_state->crtc_h) 208 return -EINVAL; 209 210 if (new_state->visible != plane->state->visible) 211 return -EINVAL; 212 213 return drm_atomic_helper_check_plane_state(plane->state, 214 crtc_state, 215 DRM_PLANE_NO_SCALING, 216 DRM_PLANE_NO_SCALING, 217 true, true); 218 } 219 220 static void lsdc_cursor_plane_atomic_async_update(struct drm_plane *plane, 221 struct drm_atomic_state *state) 222 { 223 struct lsdc_cursor *cursor = to_lsdc_cursor(plane); 224 const struct lsdc_cursor_plane_ops *ops = cursor->ops; 225 struct drm_framebuffer *old_fb = plane->state->fb; 226 struct drm_framebuffer *new_fb; 227 struct drm_plane_state *new_state; 228 229 new_state = drm_atomic_get_new_plane_state(state, plane); 230 231 new_fb = plane->state->fb; 232 233 plane->state->crtc_x = new_state->crtc_x; 234 plane->state->crtc_y = new_state->crtc_y; 235 plane->state->crtc_h = new_state->crtc_h; 236 plane->state->crtc_w = new_state->crtc_w; 237 plane->state->src_x = new_state->src_x; 238 plane->state->src_y = new_state->src_y; 239 plane->state->src_h = new_state->src_h; 240 plane->state->src_w = new_state->src_w; 241 swap(plane->state->fb, new_state->fb); 242 243 if (new_state->visible) { 244 enum lsdc_cursor_size cursor_size; 245 246 switch (new_state->crtc_w) { 247 case 64: 248 cursor_size = CURSOR_SIZE_64X64; 249 break; 250 case 32: 251 cursor_size = CURSOR_SIZE_32X32; 252 break; 253 default: 254 cursor_size = CURSOR_SIZE_32X32; 255 break; 256 } 257 258 ops->update_position(cursor, new_state->crtc_x, new_state->crtc_y); 259 260 ops->update_cfg(cursor, cursor_size, CURSOR_FORMAT_ARGB8888); 261 262 if (!old_fb || old_fb != new_fb) 263 ops->update_bo_addr(cursor, lsdc_fb_base_addr(new_fb)); 264 } 265 } 266 267 /* ls7a1000 cursor plane helpers */ 268 269 static int ls7a1000_cursor_plane_atomic_check(struct drm_plane *plane, 270 struct drm_atomic_state *state) 271 { 272 struct drm_plane_state *new_plane_state; 273 struct drm_crtc_state *new_crtc_state; 274 struct drm_crtc *crtc; 275 276 new_plane_state = drm_atomic_get_new_plane_state(state, plane); 277 278 crtc = new_plane_state->crtc; 279 if (!crtc) { 280 drm_dbg(plane->dev, "%s is not bind to a crtc\n", plane->name); 281 return 0; 282 } 283 284 if (new_plane_state->crtc_w != 32 || new_plane_state->crtc_h != 32) { 285 drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n", 286 new_plane_state->crtc_w, new_plane_state->crtc_h); 287 return -EINVAL; 288 } 289 290 new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 291 292 return drm_atomic_helper_check_plane_state(new_plane_state, 293 new_crtc_state, 294 DRM_PLANE_NO_SCALING, 295 DRM_PLANE_NO_SCALING, 296 true, true); 297 } 298 299 static void ls7a1000_cursor_plane_atomic_update(struct drm_plane *plane, 300 struct drm_atomic_state *state) 301 { 302 struct lsdc_cursor *cursor = to_lsdc_cursor(plane); 303 struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); 304 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); 305 struct drm_framebuffer *new_fb = new_plane_state->fb; 306 struct drm_framebuffer *old_fb = old_plane_state->fb; 307 const struct lsdc_cursor_plane_ops *ops = cursor->ops; 308 u64 addr = lsdc_fb_base_addr(new_fb); 309 310 if (!new_plane_state->visible) 311 return; 312 313 ops->update_position(cursor, new_plane_state->crtc_x, new_plane_state->crtc_y); 314 315 if (!old_fb || old_fb != new_fb) 316 ops->update_bo_addr(cursor, addr); 317 318 ops->update_cfg(cursor, CURSOR_SIZE_32X32, CURSOR_FORMAT_ARGB8888); 319 } 320 321 static void ls7a1000_cursor_plane_atomic_disable(struct drm_plane *plane, 322 struct drm_atomic_state *state) 323 { 324 struct lsdc_cursor *cursor = to_lsdc_cursor(plane); 325 const struct lsdc_cursor_plane_ops *ops = cursor->ops; 326 327 ops->update_cfg(cursor, CURSOR_SIZE_32X32, CURSOR_FORMAT_DISABLE); 328 } 329 330 static const struct drm_plane_helper_funcs ls7a1000_cursor_plane_helper_funcs = { 331 .prepare_fb = lsdc_plane_prepare_fb, 332 .cleanup_fb = lsdc_plane_cleanup_fb, 333 .atomic_check = ls7a1000_cursor_plane_atomic_check, 334 .atomic_update = ls7a1000_cursor_plane_atomic_update, 335 .atomic_disable = ls7a1000_cursor_plane_atomic_disable, 336 .atomic_async_check = lsdc_cursor_plane_atomic_async_check, 337 .atomic_async_update = lsdc_cursor_plane_atomic_async_update, 338 }; 339 340 /* ls7a2000 cursor plane helpers */ 341 342 static int ls7a2000_cursor_plane_atomic_check(struct drm_plane *plane, 343 struct drm_atomic_state *state) 344 { 345 struct drm_plane_state *new_plane_state; 346 struct drm_crtc_state *new_crtc_state; 347 struct drm_crtc *crtc; 348 349 new_plane_state = drm_atomic_get_new_plane_state(state, plane); 350 351 crtc = new_plane_state->crtc; 352 if (!crtc) { 353 drm_dbg(plane->dev, "%s is not bind to a crtc\n", plane->name); 354 return 0; 355 } 356 357 if (new_plane_state->crtc_w != new_plane_state->crtc_h) { 358 drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n", 359 new_plane_state->crtc_w, new_plane_state->crtc_h); 360 return -EINVAL; 361 } 362 363 if (new_plane_state->crtc_w != 64 && new_plane_state->crtc_w != 32) { 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 new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 370 371 return drm_atomic_helper_check_plane_state(new_plane_state, 372 new_crtc_state, 373 DRM_PLANE_NO_SCALING, 374 DRM_PLANE_NO_SCALING, 375 true, true); 376 } 377 378 /* Update the format, size and location of the cursor */ 379 380 static void ls7a2000_cursor_plane_atomic_update(struct drm_plane *plane, 381 struct drm_atomic_state *state) 382 { 383 struct lsdc_cursor *cursor = to_lsdc_cursor(plane); 384 struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); 385 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); 386 struct drm_framebuffer *new_fb = new_plane_state->fb; 387 struct drm_framebuffer *old_fb = old_plane_state->fb; 388 const struct lsdc_cursor_plane_ops *ops = cursor->ops; 389 enum lsdc_cursor_size cursor_size; 390 391 if (!new_plane_state->visible) 392 return; 393 394 ops->update_position(cursor, new_plane_state->crtc_x, new_plane_state->crtc_y); 395 396 if (!old_fb || new_fb != old_fb) { 397 u64 addr = lsdc_fb_base_addr(new_fb); 398 399 ops->update_bo_addr(cursor, addr); 400 } 401 402 switch (new_plane_state->crtc_w) { 403 case 64: 404 cursor_size = CURSOR_SIZE_64X64; 405 break; 406 case 32: 407 cursor_size = CURSOR_SIZE_32X32; 408 break; 409 default: 410 cursor_size = CURSOR_SIZE_64X64; 411 break; 412 } 413 414 ops->update_cfg(cursor, cursor_size, CURSOR_FORMAT_ARGB8888); 415 } 416 417 static void ls7a2000_cursor_plane_atomic_disable(struct drm_plane *plane, 418 struct drm_atomic_state *state) 419 { 420 struct lsdc_cursor *cursor = to_lsdc_cursor(plane); 421 const struct lsdc_cursor_plane_ops *hw_ops = cursor->ops; 422 423 hw_ops->update_cfg(cursor, CURSOR_SIZE_64X64, CURSOR_FORMAT_DISABLE); 424 } 425 426 static const struct drm_plane_helper_funcs ls7a2000_cursor_plane_helper_funcs = { 427 .prepare_fb = lsdc_plane_prepare_fb, 428 .cleanup_fb = lsdc_plane_cleanup_fb, 429 .atomic_check = ls7a2000_cursor_plane_atomic_check, 430 .atomic_update = ls7a2000_cursor_plane_atomic_update, 431 .atomic_disable = ls7a2000_cursor_plane_atomic_disable, 432 .atomic_async_check = lsdc_cursor_plane_atomic_async_check, 433 .atomic_async_update = lsdc_cursor_plane_atomic_async_update, 434 }; 435 436 static void lsdc_plane_atomic_print_state(struct drm_printer *p, 437 const struct drm_plane_state *state) 438 { 439 struct drm_framebuffer *fb = state->fb; 440 u64 addr; 441 442 if (!fb) 443 return; 444 445 addr = lsdc_fb_base_addr(fb); 446 447 drm_printf(p, "\tdma addr=%llx\n", addr); 448 } 449 450 static const struct drm_plane_funcs lsdc_plane_funcs = { 451 .update_plane = drm_atomic_helper_update_plane, 452 .disable_plane = drm_atomic_helper_disable_plane, 453 .destroy = drm_plane_cleanup, 454 .reset = drm_atomic_helper_plane_reset, 455 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 456 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 457 .atomic_print_state = lsdc_plane_atomic_print_state, 458 }; 459 460 /* Primary plane 0 hardware related ops */ 461 462 static void lsdc_primary0_update_fb_addr(struct lsdc_primary *primary, u64 addr) 463 { 464 struct lsdc_device *ldev = primary->ldev; 465 u32 status; 466 u32 lo, hi; 467 468 /* 40-bit width physical address bus */ 469 lo = addr & 0xFFFFFFFF; 470 hi = (addr >> 32) & 0xFF; 471 472 status = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG); 473 if (status & FB_REG_IN_USING) { 474 lsdc_wreg32(ldev, LSDC_CRTC0_FB1_ADDR_LO_REG, lo); 475 lsdc_wreg32(ldev, LSDC_CRTC0_FB1_ADDR_HI_REG, hi); 476 } else { 477 lsdc_wreg32(ldev, LSDC_CRTC0_FB0_ADDR_LO_REG, lo); 478 lsdc_wreg32(ldev, LSDC_CRTC0_FB0_ADDR_HI_REG, hi); 479 } 480 } 481 482 static void lsdc_primary0_update_fb_stride(struct lsdc_primary *primary, u32 stride) 483 { 484 struct lsdc_device *ldev = primary->ldev; 485 486 lsdc_wreg32(ldev, LSDC_CRTC0_STRIDE_REG, stride); 487 } 488 489 static void lsdc_primary0_update_fb_format(struct lsdc_primary *primary, 490 const struct drm_format_info *format) 491 { 492 struct lsdc_device *ldev = primary->ldev; 493 u32 status; 494 495 status = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG); 496 497 /* 498 * TODO: add RGB565 support, only support XRBG8888 at present 499 */ 500 status &= ~CFG_PIX_FMT_MASK; 501 status |= LSDC_PF_XRGB8888; 502 503 lsdc_wreg32(ldev, LSDC_CRTC0_CFG_REG, status); 504 } 505 506 /* Primary plane 1 hardware related ops */ 507 508 static void lsdc_primary1_update_fb_addr(struct lsdc_primary *primary, u64 addr) 509 { 510 struct lsdc_device *ldev = primary->ldev; 511 u32 status; 512 u32 lo, hi; 513 514 /* 40-bit width physical address bus */ 515 lo = addr & 0xFFFFFFFF; 516 hi = (addr >> 32) & 0xFF; 517 518 status = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG); 519 if (status & FB_REG_IN_USING) { 520 lsdc_wreg32(ldev, LSDC_CRTC1_FB1_ADDR_LO_REG, lo); 521 lsdc_wreg32(ldev, LSDC_CRTC1_FB1_ADDR_HI_REG, hi); 522 } else { 523 lsdc_wreg32(ldev, LSDC_CRTC1_FB0_ADDR_LO_REG, lo); 524 lsdc_wreg32(ldev, LSDC_CRTC1_FB0_ADDR_HI_REG, hi); 525 } 526 } 527 528 static void lsdc_primary1_update_fb_stride(struct lsdc_primary *primary, u32 stride) 529 { 530 struct lsdc_device *ldev = primary->ldev; 531 532 lsdc_wreg32(ldev, LSDC_CRTC1_STRIDE_REG, stride); 533 } 534 535 static void lsdc_primary1_update_fb_format(struct lsdc_primary *primary, 536 const struct drm_format_info *format) 537 { 538 struct lsdc_device *ldev = primary->ldev; 539 u32 status; 540 541 status = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG); 542 543 /* 544 * TODO: add RGB565 support, only support XRBG8888 at present 545 */ 546 status &= ~CFG_PIX_FMT_MASK; 547 status |= LSDC_PF_XRGB8888; 548 549 lsdc_wreg32(ldev, LSDC_CRTC1_CFG_REG, status); 550 } 551 552 static const struct lsdc_primary_plane_ops lsdc_primary_plane_hw_ops[2] = { 553 { 554 .update_fb_addr = lsdc_primary0_update_fb_addr, 555 .update_fb_stride = lsdc_primary0_update_fb_stride, 556 .update_fb_format = lsdc_primary0_update_fb_format, 557 }, 558 { 559 .update_fb_addr = lsdc_primary1_update_fb_addr, 560 .update_fb_stride = lsdc_primary1_update_fb_stride, 561 .update_fb_format = lsdc_primary1_update_fb_format, 562 }, 563 }; 564 565 /* 566 * Update location, format, enable and disable state of the cursor, 567 * For those who have two hardware cursor, let cursor 0 is attach to CRTC-0, 568 * cursor 1 is attach to CRTC-1. Compositing the primary plane and cursor 569 * plane is automatically done by hardware, the cursor is alway on the top of 570 * the primary plane. In other word, z-order is fixed in hardware and cannot 571 * be changed. For those old DC who has only one hardware cursor, we made it 572 * shared by the two screen, this works on extend screen mode. 573 */ 574 575 /* cursor plane 0 (for pipe 0) related hardware ops */ 576 577 static void lsdc_cursor0_update_bo_addr(struct lsdc_cursor *cursor, u64 addr) 578 { 579 struct lsdc_device *ldev = cursor->ldev; 580 581 /* 40-bit width physical address bus */ 582 lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_HI_REG, (addr >> 32) & 0xFF); 583 lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_LO_REG, addr); 584 } 585 586 static void lsdc_cursor0_update_position(struct lsdc_cursor *cursor, int x, int y) 587 { 588 struct lsdc_device *ldev = cursor->ldev; 589 590 if (x < 0) 591 x = 0; 592 593 if (y < 0) 594 y = 0; 595 596 lsdc_wreg32(ldev, LSDC_CURSOR0_POSITION_REG, (y << 16) | x); 597 } 598 599 static void lsdc_cursor0_update_cfg(struct lsdc_cursor *cursor, 600 enum lsdc_cursor_size cursor_size, 601 enum lsdc_cursor_format fmt) 602 { 603 struct lsdc_device *ldev = cursor->ldev; 604 u32 cfg; 605 606 cfg = CURSOR_ON_CRTC0 << CURSOR_LOCATION_SHIFT | 607 cursor_size << CURSOR_SIZE_SHIFT | 608 fmt << CURSOR_FORMAT_SHIFT; 609 610 lsdc_wreg32(ldev, LSDC_CURSOR0_CFG_REG, cfg); 611 } 612 613 /* cursor plane 1 (for pipe 1) related hardware ops */ 614 615 static void lsdc_cursor1_update_bo_addr(struct lsdc_cursor *cursor, u64 addr) 616 { 617 struct lsdc_device *ldev = cursor->ldev; 618 619 /* 40-bit width physical address bus */ 620 lsdc_wreg32(ldev, LSDC_CURSOR1_ADDR_HI_REG, (addr >> 32) & 0xFF); 621 lsdc_wreg32(ldev, LSDC_CURSOR1_ADDR_LO_REG, addr); 622 } 623 624 static void lsdc_cursor1_update_position(struct lsdc_cursor *cursor, int x, int y) 625 { 626 struct lsdc_device *ldev = cursor->ldev; 627 628 if (x < 0) 629 x = 0; 630 631 if (y < 0) 632 y = 0; 633 634 lsdc_wreg32(ldev, LSDC_CURSOR1_POSITION_REG, (y << 16) | x); 635 } 636 637 static void lsdc_cursor1_update_cfg(struct lsdc_cursor *cursor, 638 enum lsdc_cursor_size cursor_size, 639 enum lsdc_cursor_format fmt) 640 { 641 struct lsdc_device *ldev = cursor->ldev; 642 u32 cfg; 643 644 cfg = CURSOR_ON_CRTC1 << CURSOR_LOCATION_SHIFT | 645 cursor_size << CURSOR_SIZE_SHIFT | 646 fmt << CURSOR_FORMAT_SHIFT; 647 648 lsdc_wreg32(ldev, LSDC_CURSOR1_CFG_REG, cfg); 649 } 650 651 /* The hardware cursors become normal since ls7a2000/ls2k2000 */ 652 653 static const struct lsdc_cursor_plane_ops ls7a2000_cursor_hw_ops[2] = { 654 { 655 .update_bo_addr = lsdc_cursor0_update_bo_addr, 656 .update_cfg = lsdc_cursor0_update_cfg, 657 .update_position = lsdc_cursor0_update_position, 658 }, 659 { 660 .update_bo_addr = lsdc_cursor1_update_bo_addr, 661 .update_cfg = lsdc_cursor1_update_cfg, 662 .update_position = lsdc_cursor1_update_position, 663 }, 664 }; 665 666 /* Quirks for cursor 1, only for old loongson display controller */ 667 668 static void lsdc_cursor1_update_bo_addr_quirk(struct lsdc_cursor *cursor, u64 addr) 669 { 670 struct lsdc_device *ldev = cursor->ldev; 671 672 /* 40-bit width physical address bus */ 673 lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_HI_REG, (addr >> 32) & 0xFF); 674 lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_LO_REG, addr); 675 } 676 677 static void lsdc_cursor1_update_position_quirk(struct lsdc_cursor *cursor, int x, int y) 678 { 679 struct lsdc_device *ldev = cursor->ldev; 680 681 if (x < 0) 682 x = 0; 683 684 if (y < 0) 685 y = 0; 686 687 lsdc_wreg32(ldev, LSDC_CURSOR0_POSITION_REG, (y << 16) | x); 688 } 689 690 static void lsdc_cursor1_update_cfg_quirk(struct lsdc_cursor *cursor, 691 enum lsdc_cursor_size cursor_size, 692 enum lsdc_cursor_format fmt) 693 { 694 struct lsdc_device *ldev = cursor->ldev; 695 u32 cfg; 696 697 cfg = CURSOR_ON_CRTC1 << CURSOR_LOCATION_SHIFT | 698 cursor_size << CURSOR_SIZE_SHIFT | 699 fmt << CURSOR_FORMAT_SHIFT; 700 701 lsdc_wreg32(ldev, LSDC_CURSOR0_CFG_REG, cfg); 702 } 703 704 /* 705 * The unforgiving LS7A1000/LS2K1000 has only one hardware cursors plane 706 */ 707 static const struct lsdc_cursor_plane_ops ls7a1000_cursor_hw_ops[2] = { 708 { 709 .update_bo_addr = lsdc_cursor0_update_bo_addr, 710 .update_cfg = lsdc_cursor0_update_cfg, 711 .update_position = lsdc_cursor0_update_position, 712 }, 713 { 714 .update_bo_addr = lsdc_cursor1_update_bo_addr_quirk, 715 .update_cfg = lsdc_cursor1_update_cfg_quirk, 716 .update_position = lsdc_cursor1_update_position_quirk, 717 }, 718 }; 719 720 int lsdc_primary_plane_init(struct drm_device *ddev, 721 struct drm_plane *plane, 722 unsigned int index) 723 { 724 struct lsdc_primary *primary = to_lsdc_primary(plane); 725 int ret; 726 727 ret = drm_universal_plane_init(ddev, plane, 1 << index, 728 &lsdc_plane_funcs, 729 lsdc_primary_formats, 730 ARRAY_SIZE(lsdc_primary_formats), 731 lsdc_fb_format_modifiers, 732 DRM_PLANE_TYPE_PRIMARY, 733 "ls-primary-plane-%u", index); 734 if (ret) 735 return ret; 736 737 drm_plane_helper_add(plane, &lsdc_primary_helper_funcs); 738 739 primary->ldev = to_lsdc(ddev); 740 primary->ops = &lsdc_primary_plane_hw_ops[index]; 741 742 return 0; 743 } 744 745 int ls7a1000_cursor_plane_init(struct drm_device *ddev, 746 struct drm_plane *plane, 747 unsigned int index) 748 { 749 struct lsdc_cursor *cursor = to_lsdc_cursor(plane); 750 int ret; 751 752 ret = drm_universal_plane_init(ddev, plane, 1 << index, 753 &lsdc_plane_funcs, 754 lsdc_cursor_formats, 755 ARRAY_SIZE(lsdc_cursor_formats), 756 lsdc_fb_format_modifiers, 757 DRM_PLANE_TYPE_CURSOR, 758 "ls-cursor-plane-%u", index); 759 if (ret) 760 return ret; 761 762 cursor->ldev = to_lsdc(ddev); 763 cursor->ops = &ls7a1000_cursor_hw_ops[index]; 764 765 drm_plane_helper_add(plane, &ls7a1000_cursor_plane_helper_funcs); 766 767 return 0; 768 } 769 770 int ls7a2000_cursor_plane_init(struct drm_device *ddev, 771 struct drm_plane *plane, 772 unsigned int index) 773 { 774 struct lsdc_cursor *cursor = to_lsdc_cursor(plane); 775 int ret; 776 777 ret = drm_universal_plane_init(ddev, plane, 1 << index, 778 &lsdc_plane_funcs, 779 lsdc_cursor_formats, 780 ARRAY_SIZE(lsdc_cursor_formats), 781 lsdc_fb_format_modifiers, 782 DRM_PLANE_TYPE_CURSOR, 783 "ls-cursor-plane-%u", index); 784 if (ret) 785 return ret; 786 787 cursor->ldev = to_lsdc(ddev); 788 cursor->ops = &ls7a2000_cursor_hw_ops[index]; 789 790 drm_plane_helper_add(plane, &ls7a2000_cursor_plane_helper_funcs); 791 792 return 0; 793 } 794