root/drivers/gpu/drm/tegra/hub.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tegra_plane_offset
  2. tegra_plane_readl
  3. tegra_plane_writel
  4. tegra_windowgroup_enable
  5. tegra_windowgroup_disable
  6. tegra_display_hub_prepare
  7. tegra_display_hub_cleanup
  8. tegra_shared_plane_update
  9. tegra_shared_plane_activate
  10. tegra_shared_plane_get_owner
  11. tegra_dc_owns_shared_plane
  12. tegra_shared_plane_set_owner
  13. tegra_dc_assign_shared_plane
  14. tegra_dc_remove_shared_plane
  15. tegra_shared_plane_atomic_check
  16. tegra_shared_plane_atomic_disable
  17. tegra_shared_plane_atomic_update
  18. tegra_shared_plane_create
  19. tegra_display_hub_duplicate_state
  20. tegra_display_hub_destroy_state
  21. tegra_display_hub_get_state
  22. tegra_display_hub_atomic_check
  23. tegra_display_hub_update
  24. tegra_display_hub_atomic_commit
  25. tegra_display_hub_init
  26. tegra_display_hub_exit
  27. tegra_display_hub_probe
  28. tegra_display_hub_remove
  29. tegra_display_hub_suspend
  30. tegra_display_hub_resume

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

/* [<][>][^][v][top][bottom][index][help] */