1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved. 4 */ 5 6 #include <linux/clk.h> 7 #include <linux/host1x.h> 8 #include <linux/module.h> 9 #include <linux/of.h> 10 #include <linux/of_device.h> 11 #include <linux/of_graph.h> 12 #include <linux/platform_device.h> 13 #include <linux/pm_runtime.h> 14 #include <linux/reset.h> 15 16 #include <drm/drmP.h> 17 #include <drm/drm_atomic.h> 18 #include <drm/drm_atomic_helper.h> 19 #include <drm/drm_probe_helper.h> 20 21 #include "drm.h" 22 #include "dc.h" 23 #include "plane.h" 24 25 static const u32 tegra_shared_plane_formats[] = { 26 DRM_FORMAT_ARGB1555, 27 DRM_FORMAT_RGB565, 28 DRM_FORMAT_RGBA5551, 29 DRM_FORMAT_ARGB8888, 30 DRM_FORMAT_ABGR8888, 31 /* new on Tegra114 */ 32 DRM_FORMAT_ABGR4444, 33 DRM_FORMAT_ABGR1555, 34 DRM_FORMAT_BGRA5551, 35 DRM_FORMAT_XRGB1555, 36 DRM_FORMAT_RGBX5551, 37 DRM_FORMAT_XBGR1555, 38 DRM_FORMAT_BGRX5551, 39 DRM_FORMAT_BGR565, 40 DRM_FORMAT_XRGB8888, 41 DRM_FORMAT_XBGR8888, 42 /* planar formats */ 43 DRM_FORMAT_UYVY, 44 DRM_FORMAT_YUYV, 45 DRM_FORMAT_YUV420, 46 DRM_FORMAT_YUV422, 47 }; 48 49 static const u64 tegra_shared_plane_modifiers[] = { 50 DRM_FORMAT_MOD_LINEAR, 51 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0), 52 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1), 53 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2), 54 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3), 55 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4), 56 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5), 57 DRM_FORMAT_MOD_INVALID 58 }; 59 60 static inline unsigned int tegra_plane_offset(struct tegra_plane *plane, 61 unsigned int offset) 62 { 63 if (offset >= 0x500 && offset <= 0x581) { 64 offset = 0x000 + (offset - 0x500); 65 return plane->offset + offset; 66 } 67 68 if (offset >= 0x700 && offset <= 0x73c) { 69 offset = 0x180 + (offset - 0x700); 70 return plane->offset + offset; 71 } 72 73 if (offset >= 0x800 && offset <= 0x83e) { 74 offset = 0x1c0 + (offset - 0x800); 75 return plane->offset + offset; 76 } 77 78 dev_WARN(plane->dc->dev, "invalid offset: %x\n", offset); 79 80 return plane->offset + offset; 81 } 82 83 static inline u32 tegra_plane_readl(struct tegra_plane *plane, 84 unsigned int offset) 85 { 86 return tegra_dc_readl(plane->dc, tegra_plane_offset(plane, offset)); 87 } 88 89 static inline void tegra_plane_writel(struct tegra_plane *plane, u32 value, 90 unsigned int offset) 91 { 92 tegra_dc_writel(plane->dc, value, tegra_plane_offset(plane, offset)); 93 } 94 95 static int tegra_windowgroup_enable(struct tegra_windowgroup *wgrp) 96 { 97 mutex_lock(&wgrp->lock); 98 99 if (wgrp->usecount == 0) { 100 pm_runtime_get_sync(wgrp->parent); 101 reset_control_deassert(wgrp->rst); 102 } 103 104 wgrp->usecount++; 105 mutex_unlock(&wgrp->lock); 106 107 return 0; 108 } 109 110 static void tegra_windowgroup_disable(struct tegra_windowgroup *wgrp) 111 { 112 int err; 113 114 mutex_lock(&wgrp->lock); 115 116 if (wgrp->usecount == 1) { 117 err = reset_control_assert(wgrp->rst); 118 if (err < 0) { 119 pr_err("failed to assert reset for window group %u\n", 120 wgrp->index); 121 } 122 123 pm_runtime_put(wgrp->parent); 124 } 125 126 wgrp->usecount--; 127 mutex_unlock(&wgrp->lock); 128 } 129 130 int tegra_display_hub_prepare(struct tegra_display_hub *hub) 131 { 132 unsigned int i; 133 134 /* 135 * XXX Enabling/disabling windowgroups needs to happen when the owner 136 * display controller is disabled. There's currently no good point at 137 * which this could be executed, so unconditionally enable all window 138 * groups for now. 139 */ 140 for (i = 0; i < hub->soc->num_wgrps; i++) { 141 struct tegra_windowgroup *wgrp = &hub->wgrps[i]; 142 143 tegra_windowgroup_enable(wgrp); 144 } 145 146 return 0; 147 } 148 149 void tegra_display_hub_cleanup(struct tegra_display_hub *hub) 150 { 151 unsigned int i; 152 153 /* 154 * XXX Remove this once window groups can be more fine-grainedly 155 * enabled and disabled. 156 */ 157 for (i = 0; i < hub->soc->num_wgrps; i++) { 158 struct tegra_windowgroup *wgrp = &hub->wgrps[i]; 159 160 tegra_windowgroup_disable(wgrp); 161 } 162 } 163 164 static void tegra_shared_plane_update(struct tegra_plane *plane) 165 { 166 struct tegra_dc *dc = plane->dc; 167 unsigned long timeout; 168 u32 mask, value; 169 170 mask = COMMON_UPDATE | WIN_A_UPDATE << plane->base.index; 171 tegra_dc_writel(dc, mask, DC_CMD_STATE_CONTROL); 172 173 timeout = jiffies + msecs_to_jiffies(1000); 174 175 while (time_before(jiffies, timeout)) { 176 value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL); 177 if ((value & mask) == 0) 178 break; 179 180 usleep_range(100, 400); 181 } 182 } 183 184 static void tegra_shared_plane_activate(struct tegra_plane *plane) 185 { 186 struct tegra_dc *dc = plane->dc; 187 unsigned long timeout; 188 u32 mask, value; 189 190 mask = COMMON_ACTREQ | WIN_A_ACT_REQ << plane->base.index; 191 tegra_dc_writel(dc, mask, DC_CMD_STATE_CONTROL); 192 193 timeout = jiffies + msecs_to_jiffies(1000); 194 195 while (time_before(jiffies, timeout)) { 196 value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL); 197 if ((value & mask) == 0) 198 break; 199 200 usleep_range(100, 400); 201 } 202 } 203 204 static unsigned int 205 tegra_shared_plane_get_owner(struct tegra_plane *plane, struct tegra_dc *dc) 206 { 207 unsigned int offset = 208 tegra_plane_offset(plane, DC_WIN_CORE_WINDOWGROUP_SET_CONTROL); 209 210 return tegra_dc_readl(dc, offset) & OWNER_MASK; 211 } 212 213 static bool tegra_dc_owns_shared_plane(struct tegra_dc *dc, 214 struct tegra_plane *plane) 215 { 216 struct device *dev = dc->dev; 217 218 if (tegra_shared_plane_get_owner(plane, dc) == dc->pipe) { 219 if (plane->dc == dc) 220 return true; 221 222 dev_WARN(dev, "head %u owns window %u but is not attached\n", 223 dc->pipe, plane->index); 224 } 225 226 return false; 227 } 228 229 static int tegra_shared_plane_set_owner(struct tegra_plane *plane, 230 struct tegra_dc *new) 231 { 232 unsigned int offset = 233 tegra_plane_offset(plane, DC_WIN_CORE_WINDOWGROUP_SET_CONTROL); 234 struct tegra_dc *old = plane->dc, *dc = new ? new : old; 235 struct device *dev = new ? new->dev : old->dev; 236 unsigned int owner, index = plane->index; 237 u32 value; 238 239 value = tegra_dc_readl(dc, offset); 240 owner = value & OWNER_MASK; 241 242 if (new && (owner != OWNER_MASK && owner != new->pipe)) { 243 dev_WARN(dev, "window %u owned by head %u\n", index, owner); 244 return -EBUSY; 245 } 246 247 /* 248 * This seems to happen whenever the head has been disabled with one 249 * or more windows being active. This is harmless because we'll just 250 * reassign the window to the new head anyway. 251 */ 252 if (old && owner == OWNER_MASK) 253 dev_dbg(dev, "window %u not owned by head %u but %u\n", index, 254 old->pipe, owner); 255 256 value &= ~OWNER_MASK; 257 258 if (new) 259 value |= OWNER(new->pipe); 260 else 261 value |= OWNER_MASK; 262 263 tegra_dc_writel(dc, value, offset); 264 265 plane->dc = new; 266 267 return 0; 268 } 269 270 static void tegra_dc_assign_shared_plane(struct tegra_dc *dc, 271 struct tegra_plane *plane) 272 { 273 u32 value; 274 int err; 275 276 if (!tegra_dc_owns_shared_plane(dc, plane)) { 277 err = tegra_shared_plane_set_owner(plane, dc); 278 if (err < 0) 279 return; 280 } 281 282 value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_LINEBUF_CONFIG); 283 value |= MODE_FOUR_LINES; 284 tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_LINEBUF_CONFIG); 285 286 value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_WGRP_FETCH_METER); 287 value = SLOTS(1); 288 tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_WGRP_FETCH_METER); 289 290 /* disable watermark */ 291 value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLA); 292 value &= ~LATENCY_CTL_MODE_ENABLE; 293 tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLA); 294 295 value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLB); 296 value |= WATERMARK_MASK; 297 tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLB); 298 299 /* pipe meter */ 300 value = tegra_plane_readl(plane, DC_WIN_CORE_PRECOMP_WGRP_PIPE_METER); 301 value = PIPE_METER_INT(0) | PIPE_METER_FRAC(0); 302 tegra_plane_writel(plane, value, DC_WIN_CORE_PRECOMP_WGRP_PIPE_METER); 303 304 /* mempool entries */ 305 value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_WGRP_POOL_CONFIG); 306 value = MEMPOOL_ENTRIES(0x331); 307 tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_WGRP_POOL_CONFIG); 308 309 value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_THREAD_GROUP); 310 value &= ~THREAD_NUM_MASK; 311 value |= THREAD_NUM(plane->base.index); 312 value |= THREAD_GROUP_ENABLE; 313 tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_THREAD_GROUP); 314 315 tegra_shared_plane_update(plane); 316 tegra_shared_plane_activate(plane); 317 } 318 319 static void tegra_dc_remove_shared_plane(struct tegra_dc *dc, 320 struct tegra_plane *plane) 321 { 322 tegra_shared_plane_set_owner(plane, NULL); 323 } 324 325 static int tegra_shared_plane_atomic_check(struct drm_plane *plane, 326 struct drm_plane_state *state) 327 { 328 struct tegra_plane_state *plane_state = to_tegra_plane_state(state); 329 struct tegra_shared_plane *tegra = to_tegra_shared_plane(plane); 330 struct tegra_bo_tiling *tiling = &plane_state->tiling; 331 struct tegra_dc *dc = to_tegra_dc(state->crtc); 332 int err; 333 334 /* no need for further checks if the plane is being disabled */ 335 if (!state->crtc || !state->fb) 336 return 0; 337 338 err = tegra_plane_format(state->fb->format->format, 339 &plane_state->format, 340 &plane_state->swap); 341 if (err < 0) 342 return err; 343 344 err = tegra_fb_get_tiling(state->fb, tiling); 345 if (err < 0) 346 return err; 347 348 if (tiling->mode == TEGRA_BO_TILING_MODE_BLOCK && 349 !dc->soc->supports_block_linear) { 350 DRM_ERROR("hardware doesn't support block linear mode\n"); 351 return -EINVAL; 352 } 353 354 /* 355 * Tegra doesn't support different strides for U and V planes so we 356 * error out if the user tries to display a framebuffer with such a 357 * configuration. 358 */ 359 if (state->fb->format->num_planes > 2) { 360 if (state->fb->pitches[2] != state->fb->pitches[1]) { 361 DRM_ERROR("unsupported UV-plane configuration\n"); 362 return -EINVAL; 363 } 364 } 365 366 /* XXX scaling is not yet supported, add a check here */ 367 368 err = tegra_plane_state_add(&tegra->base, state); 369 if (err < 0) 370 return err; 371 372 return 0; 373 } 374 375 static void tegra_shared_plane_atomic_disable(struct drm_plane *plane, 376 struct drm_plane_state *old_state) 377 { 378 struct tegra_plane *p = to_tegra_plane(plane); 379 struct tegra_dc *dc; 380 u32 value; 381 382 /* rien ne va plus */ 383 if (!old_state || !old_state->crtc) 384 return; 385 386 dc = to_tegra_dc(old_state->crtc); 387 388 /* 389 * XXX Legacy helpers seem to sometimes call ->atomic_disable() even 390 * on planes that are already disabled. Make sure we fallback to the 391 * head for this particular state instead of crashing. 392 */ 393 if (WARN_ON(p->dc == NULL)) 394 p->dc = dc; 395 396 pm_runtime_get_sync(dc->dev); 397 398 value = tegra_plane_readl(p, DC_WIN_WIN_OPTIONS); 399 value &= ~WIN_ENABLE; 400 tegra_plane_writel(p, value, DC_WIN_WIN_OPTIONS); 401 402 tegra_dc_remove_shared_plane(dc, p); 403 404 pm_runtime_put(dc->dev); 405 } 406 407 static void tegra_shared_plane_atomic_update(struct drm_plane *plane, 408 struct drm_plane_state *old_state) 409 { 410 struct tegra_plane_state *state = to_tegra_plane_state(plane->state); 411 struct tegra_dc *dc = to_tegra_dc(plane->state->crtc); 412 unsigned int zpos = plane->state->normalized_zpos; 413 struct drm_framebuffer *fb = plane->state->fb; 414 struct tegra_plane *p = to_tegra_plane(plane); 415 struct tegra_bo *bo; 416 dma_addr_t base; 417 u32 value; 418 419 /* rien ne va plus */ 420 if (!plane->state->crtc || !plane->state->fb) 421 return; 422 423 if (!plane->state->visible) { 424 tegra_shared_plane_atomic_disable(plane, old_state); 425 return; 426 } 427 428 pm_runtime_get_sync(dc->dev); 429 430 tegra_dc_assign_shared_plane(dc, p); 431 432 tegra_plane_writel(p, VCOUNTER, DC_WIN_CORE_ACT_CONTROL); 433 434 /* blending */ 435 value = BLEND_FACTOR_DST_ALPHA_ZERO | BLEND_FACTOR_SRC_ALPHA_K2 | 436 BLEND_FACTOR_DST_COLOR_NEG_K1_TIMES_SRC | 437 BLEND_FACTOR_SRC_COLOR_K1_TIMES_SRC; 438 tegra_plane_writel(p, value, DC_WIN_BLEND_MATCH_SELECT); 439 440 value = BLEND_FACTOR_DST_ALPHA_ZERO | BLEND_FACTOR_SRC_ALPHA_K2 | 441 BLEND_FACTOR_DST_COLOR_NEG_K1_TIMES_SRC | 442 BLEND_FACTOR_SRC_COLOR_K1_TIMES_SRC; 443 tegra_plane_writel(p, value, DC_WIN_BLEND_NOMATCH_SELECT); 444 445 value = K2(255) | K1(255) | WINDOW_LAYER_DEPTH(255 - zpos); 446 tegra_plane_writel(p, value, DC_WIN_BLEND_LAYER_CONTROL); 447 448 /* bypass scaling */ 449 value = HORIZONTAL_TAPS_5 | VERTICAL_TAPS_5; 450 tegra_plane_writel(p, value, DC_WIN_WINDOWGROUP_SET_CONTROL_INPUT_SCALER); 451 452 value = INPUT_SCALER_VBYPASS | INPUT_SCALER_HBYPASS; 453 tegra_plane_writel(p, value, DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_USAGE); 454 455 /* disable compression */ 456 tegra_plane_writel(p, 0, DC_WINBUF_CDE_CONTROL); 457 458 bo = tegra_fb_get_plane(fb, 0); 459 base = bo->paddr; 460 461 tegra_plane_writel(p, state->format, DC_WIN_COLOR_DEPTH); 462 tegra_plane_writel(p, 0, DC_WIN_PRECOMP_WGRP_PARAMS); 463 464 value = V_POSITION(plane->state->crtc_y) | 465 H_POSITION(plane->state->crtc_x); 466 tegra_plane_writel(p, value, DC_WIN_POSITION); 467 468 value = V_SIZE(plane->state->crtc_h) | H_SIZE(plane->state->crtc_w); 469 tegra_plane_writel(p, value, DC_WIN_SIZE); 470 471 value = WIN_ENABLE | COLOR_EXPAND; 472 tegra_plane_writel(p, value, DC_WIN_WIN_OPTIONS); 473 474 value = V_SIZE(plane->state->crtc_h) | H_SIZE(plane->state->crtc_w); 475 tegra_plane_writel(p, value, DC_WIN_CROPPED_SIZE); 476 477 tegra_plane_writel(p, upper_32_bits(base), DC_WINBUF_START_ADDR_HI); 478 tegra_plane_writel(p, lower_32_bits(base), DC_WINBUF_START_ADDR); 479 480 value = PITCH(fb->pitches[0]); 481 tegra_plane_writel(p, value, DC_WIN_PLANAR_STORAGE); 482 483 value = CLAMP_BEFORE_BLEND | DEGAMMA_SRGB | INPUT_RANGE_FULL; 484 tegra_plane_writel(p, value, DC_WIN_SET_PARAMS); 485 486 value = OFFSET_X(plane->state->src_y >> 16) | 487 OFFSET_Y(plane->state->src_x >> 16); 488 tegra_plane_writel(p, value, DC_WINBUF_CROPPED_POINT); 489 490 if (dc->soc->supports_block_linear) { 491 unsigned long height = state->tiling.value; 492 493 /* XXX */ 494 switch (state->tiling.mode) { 495 case TEGRA_BO_TILING_MODE_PITCH: 496 value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(0) | 497 DC_WINBUF_SURFACE_KIND_PITCH; 498 break; 499 500 /* XXX not supported on Tegra186 and later */ 501 case TEGRA_BO_TILING_MODE_TILED: 502 value = DC_WINBUF_SURFACE_KIND_TILED; 503 break; 504 505 case TEGRA_BO_TILING_MODE_BLOCK: 506 value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(height) | 507 DC_WINBUF_SURFACE_KIND_BLOCK; 508 break; 509 } 510 511 tegra_plane_writel(p, value, DC_WINBUF_SURFACE_KIND); 512 } 513 514 /* disable gamut CSC */ 515 value = tegra_plane_readl(p, DC_WIN_WINDOW_SET_CONTROL); 516 value &= ~CONTROL_CSC_ENABLE; 517 tegra_plane_writel(p, value, DC_WIN_WINDOW_SET_CONTROL); 518 519 pm_runtime_put(dc->dev); 520 } 521 522 static const struct drm_plane_helper_funcs tegra_shared_plane_helper_funcs = { 523 .atomic_check = tegra_shared_plane_atomic_check, 524 .atomic_update = tegra_shared_plane_atomic_update, 525 .atomic_disable = tegra_shared_plane_atomic_disable, 526 }; 527 528 struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, 529 struct tegra_dc *dc, 530 unsigned int wgrp, 531 unsigned int index) 532 { 533 enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY; 534 struct tegra_drm *tegra = drm->dev_private; 535 struct tegra_display_hub *hub = tegra->hub; 536 /* planes can be assigned to arbitrary CRTCs */ 537 unsigned int possible_crtcs = 0x7; 538 struct tegra_shared_plane *plane; 539 unsigned int num_formats; 540 const u64 *modifiers; 541 struct drm_plane *p; 542 const u32 *formats; 543 int err; 544 545 plane = kzalloc(sizeof(*plane), GFP_KERNEL); 546 if (!plane) 547 return ERR_PTR(-ENOMEM); 548 549 plane->base.offset = 0x0a00 + 0x0300 * index; 550 plane->base.index = index; 551 552 plane->wgrp = &hub->wgrps[wgrp]; 553 plane->wgrp->parent = dc->dev; 554 555 p = &plane->base.base; 556 557 num_formats = ARRAY_SIZE(tegra_shared_plane_formats); 558 formats = tegra_shared_plane_formats; 559 modifiers = tegra_shared_plane_modifiers; 560 561 err = drm_universal_plane_init(drm, p, possible_crtcs, 562 &tegra_plane_funcs, formats, 563 num_formats, modifiers, type, NULL); 564 if (err < 0) { 565 kfree(plane); 566 return ERR_PTR(err); 567 } 568 569 drm_plane_helper_add(p, &tegra_shared_plane_helper_funcs); 570 drm_plane_create_zpos_property(p, 0, 0, 255); 571 572 return p; 573 } 574 575 static struct drm_private_state * 576 tegra_display_hub_duplicate_state(struct drm_private_obj *obj) 577 { 578 struct tegra_display_hub_state *state; 579 580 state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL); 581 if (!state) 582 return NULL; 583 584 __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); 585 586 return &state->base; 587 } 588 589 static void tegra_display_hub_destroy_state(struct drm_private_obj *obj, 590 struct drm_private_state *state) 591 { 592 struct tegra_display_hub_state *hub_state = 593 to_tegra_display_hub_state(state); 594 595 kfree(hub_state); 596 } 597 598 static const struct drm_private_state_funcs tegra_display_hub_state_funcs = { 599 .atomic_duplicate_state = tegra_display_hub_duplicate_state, 600 .atomic_destroy_state = tegra_display_hub_destroy_state, 601 }; 602 603 static struct tegra_display_hub_state * 604 tegra_display_hub_get_state(struct tegra_display_hub *hub, 605 struct drm_atomic_state *state) 606 { 607 struct drm_device *drm = dev_get_drvdata(hub->client.parent); 608 struct drm_private_state *priv; 609 610 WARN_ON(!drm_modeset_is_locked(&drm->mode_config.connection_mutex)); 611 612 priv = drm_atomic_get_private_obj_state(state, &hub->base); 613 if (IS_ERR(priv)) 614 return ERR_CAST(priv); 615 616 return to_tegra_display_hub_state(priv); 617 } 618 619 int tegra_display_hub_atomic_check(struct drm_device *drm, 620 struct drm_atomic_state *state) 621 { 622 struct tegra_drm *tegra = drm->dev_private; 623 struct tegra_display_hub_state *hub_state; 624 struct drm_crtc_state *old, *new; 625 struct drm_crtc *crtc; 626 unsigned int i; 627 628 if (!tegra->hub) 629 return 0; 630 631 hub_state = tegra_display_hub_get_state(tegra->hub, state); 632 if (IS_ERR(hub_state)) 633 return PTR_ERR(hub_state); 634 635 /* 636 * The display hub display clock needs to be fed by the display clock 637 * with the highest frequency to ensure proper functioning of all the 638 * displays. 639 * 640 * Note that this isn't used before Tegra186, but it doesn't hurt and 641 * conditionalizing it would make the code less clean. 642 */ 643 for_each_oldnew_crtc_in_state(state, crtc, old, new, i) { 644 struct tegra_dc_state *dc = to_dc_state(new); 645 646 if (new->active) { 647 if (!hub_state->clk || dc->pclk > hub_state->rate) { 648 hub_state->dc = to_tegra_dc(dc->base.crtc); 649 hub_state->clk = hub_state->dc->clk; 650 hub_state->rate = dc->pclk; 651 } 652 } 653 } 654 655 return 0; 656 } 657 658 static void tegra_display_hub_update(struct tegra_dc *dc) 659 { 660 u32 value; 661 662 pm_runtime_get_sync(dc->dev); 663 664 value = tegra_dc_readl(dc, DC_CMD_IHUB_COMMON_MISC_CTL); 665 value &= ~LATENCY_EVENT; 666 tegra_dc_writel(dc, value, DC_CMD_IHUB_COMMON_MISC_CTL); 667 668 value = tegra_dc_readl(dc, DC_DISP_IHUB_COMMON_DISPLAY_FETCH_METER); 669 value = CURS_SLOTS(1) | WGRP_SLOTS(1); 670 tegra_dc_writel(dc, value, DC_DISP_IHUB_COMMON_DISPLAY_FETCH_METER); 671 672 tegra_dc_writel(dc, COMMON_UPDATE, DC_CMD_STATE_CONTROL); 673 tegra_dc_readl(dc, DC_CMD_STATE_CONTROL); 674 tegra_dc_writel(dc, COMMON_ACTREQ, DC_CMD_STATE_CONTROL); 675 tegra_dc_readl(dc, DC_CMD_STATE_CONTROL); 676 677 pm_runtime_put(dc->dev); 678 } 679 680 void tegra_display_hub_atomic_commit(struct drm_device *drm, 681 struct drm_atomic_state *state) 682 { 683 struct tegra_drm *tegra = drm->dev_private; 684 struct tegra_display_hub *hub = tegra->hub; 685 struct tegra_display_hub_state *hub_state; 686 struct device *dev = hub->client.dev; 687 int err; 688 689 hub_state = to_tegra_display_hub_state(hub->base.state); 690 691 if (hub_state->clk) { 692 err = clk_set_rate(hub_state->clk, hub_state->rate); 693 if (err < 0) 694 dev_err(dev, "failed to set rate of %pC to %lu Hz\n", 695 hub_state->clk, hub_state->rate); 696 697 err = clk_set_parent(hub->clk_disp, hub_state->clk); 698 if (err < 0) 699 dev_err(dev, "failed to set parent of %pC to %pC: %d\n", 700 hub->clk_disp, hub_state->clk, err); 701 } 702 703 if (hub_state->dc) 704 tegra_display_hub_update(hub_state->dc); 705 } 706 707 static int tegra_display_hub_init(struct host1x_client *client) 708 { 709 struct tegra_display_hub *hub = to_tegra_display_hub(client); 710 struct drm_device *drm = dev_get_drvdata(client->parent); 711 struct tegra_drm *tegra = drm->dev_private; 712 struct tegra_display_hub_state *state; 713 714 state = kzalloc(sizeof(*state), GFP_KERNEL); 715 if (!state) 716 return -ENOMEM; 717 718 drm_atomic_private_obj_init(drm, &hub->base, &state->base, 719 &tegra_display_hub_state_funcs); 720 721 tegra->hub = hub; 722 723 return 0; 724 } 725 726 static int tegra_display_hub_exit(struct host1x_client *client) 727 { 728 struct drm_device *drm = dev_get_drvdata(client->parent); 729 struct tegra_drm *tegra = drm->dev_private; 730 731 drm_atomic_private_obj_fini(&tegra->hub->base); 732 tegra->hub = NULL; 733 734 return 0; 735 } 736 737 static const struct host1x_client_ops tegra_display_hub_ops = { 738 .init = tegra_display_hub_init, 739 .exit = tegra_display_hub_exit, 740 }; 741 742 static int tegra_display_hub_probe(struct platform_device *pdev) 743 { 744 struct device_node *child = NULL; 745 struct tegra_display_hub *hub; 746 struct clk *clk; 747 unsigned int i; 748 int err; 749 750 hub = devm_kzalloc(&pdev->dev, sizeof(*hub), GFP_KERNEL); 751 if (!hub) 752 return -ENOMEM; 753 754 hub->soc = of_device_get_match_data(&pdev->dev); 755 756 hub->clk_disp = devm_clk_get(&pdev->dev, "disp"); 757 if (IS_ERR(hub->clk_disp)) { 758 err = PTR_ERR(hub->clk_disp); 759 return err; 760 } 761 762 if (hub->soc->supports_dsc) { 763 hub->clk_dsc = devm_clk_get(&pdev->dev, "dsc"); 764 if (IS_ERR(hub->clk_dsc)) { 765 err = PTR_ERR(hub->clk_dsc); 766 return err; 767 } 768 } 769 770 hub->clk_hub = devm_clk_get(&pdev->dev, "hub"); 771 if (IS_ERR(hub->clk_hub)) { 772 err = PTR_ERR(hub->clk_hub); 773 return err; 774 } 775 776 hub->rst = devm_reset_control_get(&pdev->dev, "misc"); 777 if (IS_ERR(hub->rst)) { 778 err = PTR_ERR(hub->rst); 779 return err; 780 } 781 782 hub->wgrps = devm_kcalloc(&pdev->dev, hub->soc->num_wgrps, 783 sizeof(*hub->wgrps), GFP_KERNEL); 784 if (!hub->wgrps) 785 return -ENOMEM; 786 787 for (i = 0; i < hub->soc->num_wgrps; i++) { 788 struct tegra_windowgroup *wgrp = &hub->wgrps[i]; 789 char id[8]; 790 791 snprintf(id, sizeof(id), "wgrp%u", i); 792 mutex_init(&wgrp->lock); 793 wgrp->usecount = 0; 794 wgrp->index = i; 795 796 wgrp->rst = devm_reset_control_get(&pdev->dev, id); 797 if (IS_ERR(wgrp->rst)) 798 return PTR_ERR(wgrp->rst); 799 800 err = reset_control_assert(wgrp->rst); 801 if (err < 0) 802 return err; 803 } 804 805 hub->num_heads = of_get_child_count(pdev->dev.of_node); 806 807 hub->clk_heads = devm_kcalloc(&pdev->dev, hub->num_heads, sizeof(clk), 808 GFP_KERNEL); 809 if (!hub->clk_heads) 810 return -ENOMEM; 811 812 for (i = 0; i < hub->num_heads; i++) { 813 child = of_get_next_child(pdev->dev.of_node, child); 814 if (!child) { 815 dev_err(&pdev->dev, "failed to find node for head %u\n", 816 i); 817 return -ENODEV; 818 } 819 820 clk = devm_get_clk_from_child(&pdev->dev, child, "dc"); 821 if (IS_ERR(clk)) { 822 dev_err(&pdev->dev, "failed to get clock for head %u\n", 823 i); 824 of_node_put(child); 825 return PTR_ERR(clk); 826 } 827 828 hub->clk_heads[i] = clk; 829 } 830 831 of_node_put(child); 832 833 /* XXX: enable clock across reset? */ 834 err = reset_control_assert(hub->rst); 835 if (err < 0) 836 return err; 837 838 platform_set_drvdata(pdev, hub); 839 pm_runtime_enable(&pdev->dev); 840 841 INIT_LIST_HEAD(&hub->client.list); 842 hub->client.ops = &tegra_display_hub_ops; 843 hub->client.dev = &pdev->dev; 844 845 err = host1x_client_register(&hub->client); 846 if (err < 0) 847 dev_err(&pdev->dev, "failed to register host1x client: %d\n", 848 err); 849 850 return err; 851 } 852 853 static int tegra_display_hub_remove(struct platform_device *pdev) 854 { 855 struct tegra_display_hub *hub = platform_get_drvdata(pdev); 856 int err; 857 858 err = host1x_client_unregister(&hub->client); 859 if (err < 0) { 860 dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 861 err); 862 } 863 864 pm_runtime_disable(&pdev->dev); 865 866 return err; 867 } 868 869 static int __maybe_unused tegra_display_hub_suspend(struct device *dev) 870 { 871 struct tegra_display_hub *hub = dev_get_drvdata(dev); 872 unsigned int i = hub->num_heads; 873 int err; 874 875 err = reset_control_assert(hub->rst); 876 if (err < 0) 877 return err; 878 879 while (i--) 880 clk_disable_unprepare(hub->clk_heads[i]); 881 882 clk_disable_unprepare(hub->clk_hub); 883 clk_disable_unprepare(hub->clk_dsc); 884 clk_disable_unprepare(hub->clk_disp); 885 886 return 0; 887 } 888 889 static int __maybe_unused tegra_display_hub_resume(struct device *dev) 890 { 891 struct tegra_display_hub *hub = dev_get_drvdata(dev); 892 unsigned int i; 893 int err; 894 895 err = clk_prepare_enable(hub->clk_disp); 896 if (err < 0) 897 return err; 898 899 err = clk_prepare_enable(hub->clk_dsc); 900 if (err < 0) 901 goto disable_disp; 902 903 err = clk_prepare_enable(hub->clk_hub); 904 if (err < 0) 905 goto disable_dsc; 906 907 for (i = 0; i < hub->num_heads; i++) { 908 err = clk_prepare_enable(hub->clk_heads[i]); 909 if (err < 0) 910 goto disable_heads; 911 } 912 913 err = reset_control_deassert(hub->rst); 914 if (err < 0) 915 goto disable_heads; 916 917 return 0; 918 919 disable_heads: 920 while (i--) 921 clk_disable_unprepare(hub->clk_heads[i]); 922 923 clk_disable_unprepare(hub->clk_hub); 924 disable_dsc: 925 clk_disable_unprepare(hub->clk_dsc); 926 disable_disp: 927 clk_disable_unprepare(hub->clk_disp); 928 return err; 929 } 930 931 static const struct dev_pm_ops tegra_display_hub_pm_ops = { 932 SET_RUNTIME_PM_OPS(tegra_display_hub_suspend, 933 tegra_display_hub_resume, NULL) 934 }; 935 936 static const struct tegra_display_hub_soc tegra186_display_hub = { 937 .num_wgrps = 6, 938 .supports_dsc = true, 939 }; 940 941 static const struct tegra_display_hub_soc tegra194_display_hub = { 942 .num_wgrps = 6, 943 .supports_dsc = false, 944 }; 945 946 static const struct of_device_id tegra_display_hub_of_match[] = { 947 { 948 .compatible = "nvidia,tegra194-display", 949 .data = &tegra194_display_hub 950 }, { 951 .compatible = "nvidia,tegra186-display", 952 .data = &tegra186_display_hub 953 }, { 954 /* sentinel */ 955 } 956 }; 957 MODULE_DEVICE_TABLE(of, tegra_display_hub_of_match); 958 959 struct platform_driver tegra_display_hub_driver = { 960 .driver = { 961 .name = "tegra-display-hub", 962 .of_match_table = tegra_display_hub_of_match, 963 .pm = &tegra_display_hub_pm_ops, 964 }, 965 .probe = tegra_display_hub_probe, 966 .remove = tegra_display_hub_remove, 967 }; 968