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