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