Linux Audio

Check our new training course

Buildroot integration, development and maintenance

Need a Buildroot system for your embedded project?
Loading...
Note: File does not exist in v3.1.
   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/dma-mapping.h>
   9#include <linux/host1x.h>
  10#include <linux/module.h>
  11#include <linux/of.h>
  12#include <linux/of_graph.h>
  13#include <linux/of_platform.h>
  14#include <linux/platform_device.h>
  15#include <linux/pm_runtime.h>
  16#include <linux/reset.h>
  17
  18#include <drm/drm_atomic.h>
  19#include <drm/drm_atomic_helper.h>
  20#include <drm/drm_blend.h>
  21#include <drm/drm_fourcc.h>
  22#include <drm/drm_framebuffer.h>
  23#include <drm/drm_probe_helper.h>
  24
  25#include "drm.h"
  26#include "dc.h"
  27#include "plane.h"
  28
  29#define NFB 24
  30
  31static const u32 tegra_shared_plane_formats[] = {
  32	DRM_FORMAT_ARGB1555,
  33	DRM_FORMAT_RGB565,
  34	DRM_FORMAT_RGBA5551,
  35	DRM_FORMAT_ARGB8888,
  36	DRM_FORMAT_ABGR8888,
  37	/* new on Tegra114 */
  38	DRM_FORMAT_ABGR4444,
  39	DRM_FORMAT_ABGR1555,
  40	DRM_FORMAT_BGRA5551,
  41	DRM_FORMAT_XRGB1555,
  42	DRM_FORMAT_RGBX5551,
  43	DRM_FORMAT_XBGR1555,
  44	DRM_FORMAT_BGRX5551,
  45	DRM_FORMAT_BGR565,
  46	DRM_FORMAT_XRGB8888,
  47	DRM_FORMAT_XBGR8888,
  48	/* planar formats */
  49	DRM_FORMAT_UYVY,
  50	DRM_FORMAT_YUYV,
  51	DRM_FORMAT_YUV420,
  52	DRM_FORMAT_YUV422,
  53};
  54
  55static const u64 tegra_shared_plane_modifiers[] = {
  56	DRM_FORMAT_MOD_LINEAR,
  57	DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0),
  58	DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1),
  59	DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2),
  60	DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3),
  61	DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4),
  62	DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5),
  63	/*
  64	 * The GPU sector layout is only supported on Tegra194, but these will
  65	 * be filtered out later on by ->format_mod_supported() on SoCs where
  66	 * it isn't supported.
  67	 */
  68	DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT,
  69	DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT,
  70	DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT,
  71	DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT,
  72	DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT,
  73	DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5) | DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT,
  74	/* sentinel */
  75	DRM_FORMAT_MOD_INVALID
  76};
  77
  78static inline unsigned int tegra_plane_offset(struct tegra_plane *plane,
  79					      unsigned int offset)
  80{
  81	if (offset >= 0x500 && offset <= 0x581) {
  82		offset = 0x000 + (offset - 0x500);
  83		return plane->offset + offset;
  84	}
  85
  86	if (offset >= 0x700 && offset <= 0x73c) {
  87		offset = 0x180 + (offset - 0x700);
  88		return plane->offset + offset;
  89	}
  90
  91	if (offset >= 0x800 && offset <= 0x83e) {
  92		offset = 0x1c0 + (offset - 0x800);
  93		return plane->offset + offset;
  94	}
  95
  96	dev_WARN(plane->dc->dev, "invalid offset: %x\n", offset);
  97
  98	return plane->offset + offset;
  99}
 100
 101static inline u32 tegra_plane_readl(struct tegra_plane *plane,
 102				    unsigned int offset)
 103{
 104	return tegra_dc_readl(plane->dc, tegra_plane_offset(plane, offset));
 105}
 106
 107static inline void tegra_plane_writel(struct tegra_plane *plane, u32 value,
 108				      unsigned int offset)
 109{
 110	tegra_dc_writel(plane->dc, value, tegra_plane_offset(plane, offset));
 111}
 112
 113static int tegra_windowgroup_enable(struct tegra_windowgroup *wgrp)
 114{
 115	int err = 0;
 116
 117	mutex_lock(&wgrp->lock);
 118
 119	if (wgrp->usecount == 0) {
 120		err = host1x_client_resume(wgrp->parent);
 121		if (err < 0) {
 122			dev_err(wgrp->parent->dev, "failed to resume: %d\n", err);
 123			goto unlock;
 124		}
 125
 126		reset_control_deassert(wgrp->rst);
 127	}
 128
 129	wgrp->usecount++;
 130
 131unlock:
 132	mutex_unlock(&wgrp->lock);
 133	return err;
 134}
 135
 136static void tegra_windowgroup_disable(struct tegra_windowgroup *wgrp)
 137{
 138	int err;
 139
 140	mutex_lock(&wgrp->lock);
 141
 142	if (wgrp->usecount == 1) {
 143		err = reset_control_assert(wgrp->rst);
 144		if (err < 0) {
 145			pr_err("failed to assert reset for window group %u\n",
 146			       wgrp->index);
 147		}
 148
 149		host1x_client_suspend(wgrp->parent);
 150	}
 151
 152	wgrp->usecount--;
 153	mutex_unlock(&wgrp->lock);
 154}
 155
 156int tegra_display_hub_prepare(struct tegra_display_hub *hub)
 157{
 158	unsigned int i;
 159
 160	/*
 161	 * XXX Enabling/disabling windowgroups needs to happen when the owner
 162	 * display controller is disabled. There's currently no good point at
 163	 * which this could be executed, so unconditionally enable all window
 164	 * groups for now.
 165	 */
 166	for (i = 0; i < hub->soc->num_wgrps; i++) {
 167		struct tegra_windowgroup *wgrp = &hub->wgrps[i];
 168
 169		/* Skip orphaned window group whose parent DC is disabled */
 170		if (wgrp->parent)
 171			tegra_windowgroup_enable(wgrp);
 172	}
 173
 174	return 0;
 175}
 176
 177void tegra_display_hub_cleanup(struct tegra_display_hub *hub)
 178{
 179	unsigned int i;
 180
 181	/*
 182	 * XXX Remove this once window groups can be more fine-grainedly
 183	 * enabled and disabled.
 184	 */
 185	for (i = 0; i < hub->soc->num_wgrps; i++) {
 186		struct tegra_windowgroup *wgrp = &hub->wgrps[i];
 187
 188		/* Skip orphaned window group whose parent DC is disabled */
 189		if (wgrp->parent)
 190			tegra_windowgroup_disable(wgrp);
 191	}
 192}
 193
 194static void tegra_shared_plane_update(struct tegra_plane *plane)
 195{
 196	struct tegra_dc *dc = plane->dc;
 197	unsigned long timeout;
 198	u32 mask, value;
 199
 200	mask = COMMON_UPDATE | WIN_A_UPDATE << plane->base.index;
 201	tegra_dc_writel(dc, mask, DC_CMD_STATE_CONTROL);
 202
 203	timeout = jiffies + msecs_to_jiffies(1000);
 204
 205	while (time_before(jiffies, timeout)) {
 206		value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
 207		if ((value & mask) == 0)
 208			break;
 209
 210		usleep_range(100, 400);
 211	}
 212}
 213
 214static void tegra_shared_plane_activate(struct tegra_plane *plane)
 215{
 216	struct tegra_dc *dc = plane->dc;
 217	unsigned long timeout;
 218	u32 mask, value;
 219
 220	mask = COMMON_ACTREQ | WIN_A_ACT_REQ << plane->base.index;
 221	tegra_dc_writel(dc, mask, DC_CMD_STATE_CONTROL);
 222
 223	timeout = jiffies + msecs_to_jiffies(1000);
 224
 225	while (time_before(jiffies, timeout)) {
 226		value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
 227		if ((value & mask) == 0)
 228			break;
 229
 230		usleep_range(100, 400);
 231	}
 232}
 233
 234static unsigned int
 235tegra_shared_plane_get_owner(struct tegra_plane *plane, struct tegra_dc *dc)
 236{
 237	unsigned int offset =
 238		tegra_plane_offset(plane, DC_WIN_CORE_WINDOWGROUP_SET_CONTROL);
 239
 240	return tegra_dc_readl(dc, offset) & OWNER_MASK;
 241}
 242
 243static bool tegra_dc_owns_shared_plane(struct tegra_dc *dc,
 244				       struct tegra_plane *plane)
 245{
 246	struct device *dev = dc->dev;
 247
 248	if (tegra_shared_plane_get_owner(plane, dc) == dc->pipe) {
 249		if (plane->dc == dc)
 250			return true;
 251
 252		dev_WARN(dev, "head %u owns window %u but is not attached\n",
 253			 dc->pipe, plane->index);
 254	}
 255
 256	return false;
 257}
 258
 259static int tegra_shared_plane_set_owner(struct tegra_plane *plane,
 260					struct tegra_dc *new)
 261{
 262	unsigned int offset =
 263		tegra_plane_offset(plane, DC_WIN_CORE_WINDOWGROUP_SET_CONTROL);
 264	struct tegra_dc *old = plane->dc, *dc = new ? new : old;
 265	struct device *dev = new ? new->dev : old->dev;
 266	unsigned int owner, index = plane->index;
 267	u32 value;
 268
 269	value = tegra_dc_readl(dc, offset);
 270	owner = value & OWNER_MASK;
 271
 272	if (new && (owner != OWNER_MASK && owner != new->pipe)) {
 273		dev_WARN(dev, "window %u owned by head %u\n", index, owner);
 274		return -EBUSY;
 275	}
 276
 277	/*
 278	 * This seems to happen whenever the head has been disabled with one
 279	 * or more windows being active. This is harmless because we'll just
 280	 * reassign the window to the new head anyway.
 281	 */
 282	if (old && owner == OWNER_MASK)
 283		dev_dbg(dev, "window %u not owned by head %u but %u\n", index,
 284			old->pipe, owner);
 285
 286	value &= ~OWNER_MASK;
 287
 288	if (new)
 289		value |= OWNER(new->pipe);
 290	else
 291		value |= OWNER_MASK;
 292
 293	tegra_dc_writel(dc, value, offset);
 294
 295	plane->dc = new;
 296
 297	return 0;
 298}
 299
 300static void tegra_shared_plane_setup_scaler(struct tegra_plane *plane)
 301{
 302	static const unsigned int coeffs[192] = {
 303		0x00000000, 0x3c70e400, 0x3bb037e4, 0x0c51cc9c,
 304		0x00100001, 0x3bf0dbfa, 0x3d00f406, 0x3fe003ff,
 305		0x00300002, 0x3b80cbf5, 0x3da1040d, 0x3fb003fe,
 306		0x00400002, 0x3b20bff1, 0x3e511015, 0x3f9003fc,
 307		0x00500002, 0x3ad0b3ed, 0x3f21201d, 0x3f5003fb,
 308		0x00500003, 0x3aa0a3e9, 0x3ff13026, 0x3f2007f9,
 309		0x00500403, 0x3a7097e6, 0x00e1402f, 0x3ee007f7,
 310		0x00500403, 0x3a608be4, 0x01d14c38, 0x3ea00bf6,
 311		0x00500403, 0x3a507fe2, 0x02e15c42, 0x3e500ff4,
 312		0x00500402, 0x3a6073e1, 0x03f16c4d, 0x3e000ff2,
 313		0x00400402, 0x3a706be0, 0x05117858, 0x3db013f0,
 314		0x00300402, 0x3a905fe0, 0x06318863, 0x3d6017ee,
 315		0x00300402, 0x3ab057e0, 0x0771986e, 0x3d001beb,
 316		0x00200001, 0x3af04fe1, 0x08a1a47a, 0x3cb023e9,
 317		0x00100001, 0x3b2047e2, 0x09e1b485, 0x3c6027e7,
 318		0x00100000, 0x3b703fe2, 0x0b11c091, 0x3c002fe6,
 319		0x3f203800, 0x0391103f, 0x3ff0a014, 0x0811606c,
 320		0x3f2037ff, 0x0351083c, 0x03e11842, 0x3f203c00,
 321		0x3f302fff, 0x03010439, 0x04311c45, 0x3f104401,
 322		0x3f302fff, 0x02c0fc35, 0x04812448, 0x3f104802,
 323		0x3f4027ff, 0x0270f832, 0x04c1284b, 0x3f205003,
 324		0x3f4023ff, 0x0230f030, 0x0511304e, 0x3f205403,
 325		0x3f601fff, 0x01f0e82d, 0x05613451, 0x3f205c04,
 326		0x3f701bfe, 0x01b0e02a, 0x05a13c54, 0x3f306006,
 327		0x3f7017fe, 0x0170d827, 0x05f14057, 0x3f406807,
 328		0x3f8017ff, 0x0140d424, 0x0641445a, 0x3f406c08,
 329		0x3fa013ff, 0x0100cc22, 0x0681485d, 0x3f507409,
 330		0x3fa00fff, 0x00d0c41f, 0x06d14c60, 0x3f607c0b,
 331		0x3fc00fff, 0x0090bc1c, 0x07115063, 0x3f80840c,
 332		0x3fd00bff, 0x0070b41a, 0x07515465, 0x3f908c0e,
 333		0x3fe007ff, 0x0040b018, 0x07915868, 0x3fb0900f,
 334		0x3ff00400, 0x0010a816, 0x07d15c6a, 0x3fd09811,
 335		0x00a04c0e, 0x0460f442, 0x0240a827, 0x05c15859,
 336		0x0090440d, 0x0440f040, 0x0480fc43, 0x00b05010,
 337		0x0080400c, 0x0410ec3e, 0x04910044, 0x00d05411,
 338		0x0070380b, 0x03f0e83d, 0x04b10846, 0x00e05812,
 339		0x0060340a, 0x03d0e43b, 0x04d10c48, 0x00f06013,
 340		0x00503009, 0x03b0e039, 0x04e11449, 0x01106415,
 341		0x00402c08, 0x0390d838, 0x05011c4b, 0x01206c16,
 342		0x00302807, 0x0370d436, 0x0511204c, 0x01407018,
 343		0x00302406, 0x0340d034, 0x0531244e, 0x01507419,
 344		0x00202005, 0x0320cc32, 0x05412c50, 0x01707c1b,
 345		0x00101c04, 0x0300c431, 0x05613451, 0x0180801d,
 346		0x00101803, 0x02e0c02f, 0x05713853, 0x01a0881e,
 347		0x00101002, 0x02b0bc2d, 0x05814054, 0x01c08c20,
 348		0x00000c02, 0x02a0b82c, 0x05914455, 0x01e09421,
 349		0x00000801, 0x0280b02a, 0x05a14c57, 0x02009c23,
 350		0x00000400, 0x0260ac28, 0x05b15458, 0x0220a025,
 351	};
 352	unsigned int ratio, row, column;
 353
 354	for (ratio = 0; ratio <= 2; ratio++) {
 355		for (row = 0; row <= 15; row++) {
 356			for (column = 0; column <= 3; column++) {
 357				unsigned int index = (ratio << 6) + (row << 2) + column;
 358				u32 value;
 359
 360				value = COEFF_INDEX(index) | COEFF_DATA(coeffs[index]);
 361				tegra_plane_writel(plane, value,
 362						   DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_COEFF);
 363			}
 364		}
 365	}
 366}
 367
 368static void tegra_dc_assign_shared_plane(struct tegra_dc *dc,
 369					 struct tegra_plane *plane)
 370{
 371	u32 value;
 372	int err;
 373
 374	if (!tegra_dc_owns_shared_plane(dc, plane)) {
 375		err = tegra_shared_plane_set_owner(plane, dc);
 376		if (err < 0)
 377			return;
 378	}
 379
 380	value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_LINEBUF_CONFIG);
 381	value |= MODE_FOUR_LINES;
 382	tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_LINEBUF_CONFIG);
 383
 384	value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_WGRP_FETCH_METER);
 385	value = SLOTS(1);
 386	tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_WGRP_FETCH_METER);
 387
 388	/* disable watermark */
 389	value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLA);
 390	value &= ~LATENCY_CTL_MODE_ENABLE;
 391	tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLA);
 392
 393	value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLB);
 394	value |= WATERMARK_MASK;
 395	tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLB);
 396
 397	/* pipe meter */
 398	value = tegra_plane_readl(plane, DC_WIN_CORE_PRECOMP_WGRP_PIPE_METER);
 399	value = PIPE_METER_INT(0) | PIPE_METER_FRAC(0);
 400	tegra_plane_writel(plane, value, DC_WIN_CORE_PRECOMP_WGRP_PIPE_METER);
 401
 402	/* mempool entries */
 403	value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_WGRP_POOL_CONFIG);
 404	value = MEMPOOL_ENTRIES(0x331);
 405	tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_WGRP_POOL_CONFIG);
 406
 407	value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_THREAD_GROUP);
 408	value &= ~THREAD_NUM_MASK;
 409	value |= THREAD_NUM(plane->base.index);
 410	value |= THREAD_GROUP_ENABLE;
 411	tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_THREAD_GROUP);
 412
 413	tegra_shared_plane_setup_scaler(plane);
 414
 415	tegra_shared_plane_update(plane);
 416	tegra_shared_plane_activate(plane);
 417}
 418
 419static void tegra_dc_remove_shared_plane(struct tegra_dc *dc,
 420					 struct tegra_plane *plane)
 421{
 422	tegra_shared_plane_set_owner(plane, NULL);
 423}
 424
 425static int tegra_shared_plane_atomic_check(struct drm_plane *plane,
 426					   struct drm_atomic_state *state)
 427{
 428	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
 429										 plane);
 430	struct tegra_plane_state *plane_state = to_tegra_plane_state(new_plane_state);
 431	struct tegra_shared_plane *tegra = to_tegra_shared_plane(plane);
 432	struct tegra_bo_tiling *tiling = &plane_state->tiling;
 433	struct tegra_dc *dc = to_tegra_dc(new_plane_state->crtc);
 434	int err;
 435
 436	/* no need for further checks if the plane is being disabled */
 437	if (!new_plane_state->crtc || !new_plane_state->fb)
 438		return 0;
 439
 440	err = tegra_plane_format(new_plane_state->fb->format->format,
 441				 &plane_state->format,
 442				 &plane_state->swap);
 443	if (err < 0)
 444		return err;
 445
 446	err = tegra_fb_get_tiling(new_plane_state->fb, tiling);
 447	if (err < 0)
 448		return err;
 449
 450	if (tiling->mode == TEGRA_BO_TILING_MODE_BLOCK &&
 451	    !dc->soc->supports_block_linear) {
 452		DRM_ERROR("hardware doesn't support block linear mode\n");
 453		return -EINVAL;
 454	}
 455
 456	if (tiling->sector_layout == TEGRA_BO_SECTOR_LAYOUT_GPU &&
 457	    !dc->soc->supports_sector_layout) {
 458		DRM_ERROR("hardware doesn't support GPU sector layout\n");
 459		return -EINVAL;
 460	}
 461
 462	/*
 463	 * Tegra doesn't support different strides for U and V planes so we
 464	 * error out if the user tries to display a framebuffer with such a
 465	 * configuration.
 466	 */
 467	if (new_plane_state->fb->format->num_planes > 2) {
 468		if (new_plane_state->fb->pitches[2] != new_plane_state->fb->pitches[1]) {
 469			DRM_ERROR("unsupported UV-plane configuration\n");
 470			return -EINVAL;
 471		}
 472	}
 473
 474	/* XXX scaling is not yet supported, add a check here */
 475
 476	err = tegra_plane_state_add(&tegra->base, new_plane_state);
 477	if (err < 0)
 478		return err;
 479
 480	return 0;
 481}
 482
 483static void tegra_shared_plane_atomic_disable(struct drm_plane *plane,
 484					      struct drm_atomic_state *state)
 485{
 486	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
 487									   plane);
 488	struct tegra_plane *p = to_tegra_plane(plane);
 489	struct tegra_dc *dc;
 490	u32 value;
 491	int err;
 492
 493	/* rien ne va plus */
 494	if (!old_state || !old_state->crtc)
 495		return;
 496
 497	dc = to_tegra_dc(old_state->crtc);
 498
 499	err = host1x_client_resume(&dc->client);
 500	if (err < 0) {
 501		dev_err(dc->dev, "failed to resume: %d\n", err);
 502		return;
 503	}
 504
 505	/*
 506	 * XXX Legacy helpers seem to sometimes call ->atomic_disable() even
 507	 * on planes that are already disabled. Make sure we fallback to the
 508	 * head for this particular state instead of crashing.
 509	 */
 510	if (WARN_ON(p->dc == NULL))
 511		p->dc = dc;
 512
 513	value = tegra_plane_readl(p, DC_WIN_WIN_OPTIONS);
 514	value &= ~WIN_ENABLE;
 515	tegra_plane_writel(p, value, DC_WIN_WIN_OPTIONS);
 516
 517	tegra_dc_remove_shared_plane(dc, p);
 518
 519	host1x_client_suspend(&dc->client);
 520}
 521
 522static inline u32 compute_phase_incr(fixed20_12 in, unsigned int out)
 523{
 524	u64 tmp, tmp1, tmp2;
 525
 526	tmp = (u64)dfixed_trunc(in);
 527	tmp2 = (u64)out;
 528	tmp1 = (tmp << NFB) + (tmp2 >> 1);
 529	do_div(tmp1, tmp2);
 530
 531	return lower_32_bits(tmp1);
 532}
 533
 534static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
 535					     struct drm_atomic_state *state)
 536{
 537	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
 538									   plane);
 539	struct tegra_plane_state *tegra_plane_state = to_tegra_plane_state(new_state);
 540	struct tegra_dc *dc = to_tegra_dc(new_state->crtc);
 541	unsigned int zpos = new_state->normalized_zpos;
 542	struct drm_framebuffer *fb = new_state->fb;
 543	struct tegra_plane *p = to_tegra_plane(plane);
 544	u32 value, min_width, bypass = 0;
 545	dma_addr_t base, addr_flag = 0;
 546	unsigned int bpc, planes;
 547	bool yuv;
 548	int err;
 549
 550	/* rien ne va plus */
 551	if (!new_state->crtc || !new_state->fb)
 552		return;
 553
 554	if (!new_state->visible) {
 555		tegra_shared_plane_atomic_disable(plane, state);
 556		return;
 557	}
 558
 559	err = host1x_client_resume(&dc->client);
 560	if (err < 0) {
 561		dev_err(dc->dev, "failed to resume: %d\n", err);
 562		return;
 563	}
 564
 565	yuv = tegra_plane_format_is_yuv(tegra_plane_state->format, &planes, &bpc);
 566
 567	tegra_dc_assign_shared_plane(dc, p);
 568
 569	tegra_plane_writel(p, VCOUNTER, DC_WIN_CORE_ACT_CONTROL);
 570
 571	/* blending */
 572	value = BLEND_FACTOR_DST_ALPHA_ZERO | BLEND_FACTOR_SRC_ALPHA_K2 |
 573		BLEND_FACTOR_DST_COLOR_NEG_K1_TIMES_SRC |
 574		BLEND_FACTOR_SRC_COLOR_K1_TIMES_SRC;
 575	tegra_plane_writel(p, value, DC_WIN_BLEND_MATCH_SELECT);
 576
 577	value = BLEND_FACTOR_DST_ALPHA_ZERO | BLEND_FACTOR_SRC_ALPHA_K2 |
 578		BLEND_FACTOR_DST_COLOR_NEG_K1_TIMES_SRC |
 579		BLEND_FACTOR_SRC_COLOR_K1_TIMES_SRC;
 580	tegra_plane_writel(p, value, DC_WIN_BLEND_NOMATCH_SELECT);
 581
 582	value = K2(255) | K1(255) | WINDOW_LAYER_DEPTH(255 - zpos);
 583	tegra_plane_writel(p, value, DC_WIN_BLEND_LAYER_CONTROL);
 584
 585	/* scaling */
 586	min_width = min(new_state->src_w >> 16, new_state->crtc_w);
 587
 588	value = tegra_plane_readl(p, DC_WINC_PRECOMP_WGRP_PIPE_CAPC);
 589
 590	if (min_width < MAX_PIXELS_5TAP444(value)) {
 591		value = HORIZONTAL_TAPS_5 | VERTICAL_TAPS_5;
 592	} else {
 593		value = tegra_plane_readl(p, DC_WINC_PRECOMP_WGRP_PIPE_CAPE);
 594
 595		if (min_width < MAX_PIXELS_2TAP444(value))
 596			value = HORIZONTAL_TAPS_2 | VERTICAL_TAPS_2;
 597		else
 598			dev_err(dc->dev, "invalid minimum width: %u\n", min_width);
 599	}
 600
 601	value = HORIZONTAL_TAPS_5 | VERTICAL_TAPS_5;
 602	tegra_plane_writel(p, value, DC_WIN_WINDOWGROUP_SET_CONTROL_INPUT_SCALER);
 603
 604	if (new_state->src_w != new_state->crtc_w << 16) {
 605		fixed20_12 width = dfixed_init(new_state->src_w >> 16);
 606		u32 incr = compute_phase_incr(width, new_state->crtc_w) & ~0x1;
 607		u32 init = (1 << (NFB - 1)) + (incr >> 1);
 608
 609		tegra_plane_writel(p, incr, DC_WIN_SET_INPUT_SCALER_HPHASE_INCR);
 610		tegra_plane_writel(p, init, DC_WIN_SET_INPUT_SCALER_H_START_PHASE);
 611	} else {
 612		bypass |= INPUT_SCALER_HBYPASS;
 613	}
 614
 615	if (new_state->src_h != new_state->crtc_h << 16) {
 616		fixed20_12 height = dfixed_init(new_state->src_h >> 16);
 617		u32 incr = compute_phase_incr(height, new_state->crtc_h) & ~0x1;
 618		u32 init = (1 << (NFB - 1)) + (incr >> 1);
 619
 620		tegra_plane_writel(p, incr, DC_WIN_SET_INPUT_SCALER_VPHASE_INCR);
 621		tegra_plane_writel(p, init, DC_WIN_SET_INPUT_SCALER_V_START_PHASE);
 622	} else {
 623		bypass |= INPUT_SCALER_VBYPASS;
 624	}
 625
 626	tegra_plane_writel(p, bypass, DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_USAGE);
 627
 628	/* disable compression */
 629	tegra_plane_writel(p, 0, DC_WINBUF_CDE_CONTROL);
 630
 631#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
 632	/*
 633	 * Physical address bit 39 in Tegra194 is used as a switch for special
 634	 * logic that swizzles the memory using either the legacy Tegra or the
 635	 * dGPU sector layout.
 636	 */
 637	if (tegra_plane_state->tiling.sector_layout == TEGRA_BO_SECTOR_LAYOUT_GPU)
 638		addr_flag = BIT_ULL(39);
 639#endif
 640
 641	base = tegra_plane_state->iova[0] + fb->offsets[0];
 642	base |= addr_flag;
 643
 644	tegra_plane_writel(p, tegra_plane_state->format, DC_WIN_COLOR_DEPTH);
 645	tegra_plane_writel(p, 0, DC_WIN_PRECOMP_WGRP_PARAMS);
 646
 647	value = V_POSITION(new_state->crtc_y) |
 648		H_POSITION(new_state->crtc_x);
 649	tegra_plane_writel(p, value, DC_WIN_POSITION);
 650
 651	value = V_SIZE(new_state->crtc_h) | H_SIZE(new_state->crtc_w);
 652	tegra_plane_writel(p, value, DC_WIN_SIZE);
 653
 654	value = WIN_ENABLE | COLOR_EXPAND;
 655	tegra_plane_writel(p, value, DC_WIN_WIN_OPTIONS);
 656
 657	value = V_SIZE(new_state->src_h >> 16) | H_SIZE(new_state->src_w >> 16);
 658	tegra_plane_writel(p, value, DC_WIN_CROPPED_SIZE);
 659
 660	tegra_plane_writel(p, upper_32_bits(base), DC_WINBUF_START_ADDR_HI);
 661	tegra_plane_writel(p, lower_32_bits(base), DC_WINBUF_START_ADDR);
 662
 663	value = PITCH(fb->pitches[0]);
 664	tegra_plane_writel(p, value, DC_WIN_PLANAR_STORAGE);
 665
 666	if (yuv && planes > 1) {
 667		base = tegra_plane_state->iova[1] + fb->offsets[1];
 668		base |= addr_flag;
 669
 670		tegra_plane_writel(p, upper_32_bits(base), DC_WINBUF_START_ADDR_HI_U);
 671		tegra_plane_writel(p, lower_32_bits(base), DC_WINBUF_START_ADDR_U);
 672
 673		if (planes > 2) {
 674			base = tegra_plane_state->iova[2] + fb->offsets[2];
 675			base |= addr_flag;
 676
 677			tegra_plane_writel(p, upper_32_bits(base), DC_WINBUF_START_ADDR_HI_V);
 678			tegra_plane_writel(p, lower_32_bits(base), DC_WINBUF_START_ADDR_V);
 679		}
 680
 681		value = PITCH_U(fb->pitches[1]);
 682
 683		if (planes > 2)
 684			value |= PITCH_V(fb->pitches[2]);
 685
 686		tegra_plane_writel(p, value, DC_WIN_PLANAR_STORAGE_UV);
 687	} else {
 688		tegra_plane_writel(p, 0, DC_WINBUF_START_ADDR_U);
 689		tegra_plane_writel(p, 0, DC_WINBUF_START_ADDR_HI_U);
 690		tegra_plane_writel(p, 0, DC_WINBUF_START_ADDR_V);
 691		tegra_plane_writel(p, 0, DC_WINBUF_START_ADDR_HI_V);
 692		tegra_plane_writel(p, 0, DC_WIN_PLANAR_STORAGE_UV);
 693	}
 694
 695	value = CLAMP_BEFORE_BLEND | INPUT_RANGE_FULL;
 696
 697	if (yuv) {
 698		if (bpc < 12)
 699			value |= DEGAMMA_YUV8_10;
 700		else
 701			value |= DEGAMMA_YUV12;
 702
 703		/* XXX parameterize */
 704		value |= COLOR_SPACE_YUV_2020;
 705	} else {
 706		if (!tegra_plane_format_is_indexed(tegra_plane_state->format))
 707			value |= DEGAMMA_SRGB;
 708	}
 709
 710	tegra_plane_writel(p, value, DC_WIN_SET_PARAMS);
 711
 712	value = OFFSET_X(new_state->src_y >> 16) |
 713		OFFSET_Y(new_state->src_x >> 16);
 714	tegra_plane_writel(p, value, DC_WINBUF_CROPPED_POINT);
 715
 716	if (dc->soc->supports_block_linear) {
 717		unsigned long height = tegra_plane_state->tiling.value;
 718
 719		/* XXX */
 720		switch (tegra_plane_state->tiling.mode) {
 721		case TEGRA_BO_TILING_MODE_PITCH:
 722			value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(0) |
 723				DC_WINBUF_SURFACE_KIND_PITCH;
 724			break;
 725
 726		/* XXX not supported on Tegra186 and later */
 727		case TEGRA_BO_TILING_MODE_TILED:
 728			value = DC_WINBUF_SURFACE_KIND_TILED;
 729			break;
 730
 731		case TEGRA_BO_TILING_MODE_BLOCK:
 732			value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(height) |
 733				DC_WINBUF_SURFACE_KIND_BLOCK;
 734			break;
 735		}
 736
 737		tegra_plane_writel(p, value, DC_WINBUF_SURFACE_KIND);
 738	}
 739
 740	/* disable gamut CSC */
 741	value = tegra_plane_readl(p, DC_WIN_WINDOW_SET_CONTROL);
 742	value &= ~CONTROL_CSC_ENABLE;
 743	tegra_plane_writel(p, value, DC_WIN_WINDOW_SET_CONTROL);
 744
 745	host1x_client_suspend(&dc->client);
 746}
 747
 748static const struct drm_plane_helper_funcs tegra_shared_plane_helper_funcs = {
 749	.prepare_fb = tegra_plane_prepare_fb,
 750	.cleanup_fb = tegra_plane_cleanup_fb,
 751	.atomic_check = tegra_shared_plane_atomic_check,
 752	.atomic_update = tegra_shared_plane_atomic_update,
 753	.atomic_disable = tegra_shared_plane_atomic_disable,
 754};
 755
 756struct drm_plane *tegra_shared_plane_create(struct drm_device *drm,
 757					    struct tegra_dc *dc,
 758					    unsigned int wgrp,
 759					    unsigned int index)
 760{
 761	enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY;
 762	struct tegra_drm *tegra = drm->dev_private;
 763	struct tegra_display_hub *hub = tegra->hub;
 764	struct tegra_shared_plane *plane;
 765	unsigned int possible_crtcs;
 766	unsigned int num_formats;
 767	const u64 *modifiers;
 768	struct drm_plane *p;
 769	const u32 *formats;
 770	int err;
 771
 772	plane = kzalloc(sizeof(*plane), GFP_KERNEL);
 773	if (!plane)
 774		return ERR_PTR(-ENOMEM);
 775
 776	plane->base.offset = 0x0a00 + 0x0300 * index;
 777	plane->base.index = index;
 778
 779	plane->wgrp = &hub->wgrps[wgrp];
 780	plane->wgrp->parent = &dc->client;
 781
 782	p = &plane->base.base;
 783
 784	/* planes can be assigned to arbitrary CRTCs */
 785	possible_crtcs = BIT(tegra->num_crtcs) - 1;
 786
 787	num_formats = ARRAY_SIZE(tegra_shared_plane_formats);
 788	formats = tegra_shared_plane_formats;
 789	modifiers = tegra_shared_plane_modifiers;
 790
 791	err = drm_universal_plane_init(drm, p, possible_crtcs,
 792				       &tegra_plane_funcs, formats,
 793				       num_formats, modifiers, type, NULL);
 794	if (err < 0) {
 795		kfree(plane);
 796		return ERR_PTR(err);
 797	}
 798
 799	drm_plane_helper_add(p, &tegra_shared_plane_helper_funcs);
 800	drm_plane_create_zpos_property(p, 0, 0, 255);
 801
 802	return p;
 803}
 804
 805static struct drm_private_state *
 806tegra_display_hub_duplicate_state(struct drm_private_obj *obj)
 807{
 808	struct tegra_display_hub_state *state;
 809
 810	state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
 811	if (!state)
 812		return NULL;
 813
 814	__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
 815
 816	return &state->base;
 817}
 818
 819static void tegra_display_hub_destroy_state(struct drm_private_obj *obj,
 820					    struct drm_private_state *state)
 821{
 822	struct tegra_display_hub_state *hub_state =
 823		to_tegra_display_hub_state(state);
 824
 825	kfree(hub_state);
 826}
 827
 828static const struct drm_private_state_funcs tegra_display_hub_state_funcs = {
 829	.atomic_duplicate_state = tegra_display_hub_duplicate_state,
 830	.atomic_destroy_state = tegra_display_hub_destroy_state,
 831};
 832
 833static struct tegra_display_hub_state *
 834tegra_display_hub_get_state(struct tegra_display_hub *hub,
 835			    struct drm_atomic_state *state)
 836{
 837	struct drm_private_state *priv;
 838
 839	priv = drm_atomic_get_private_obj_state(state, &hub->base);
 840	if (IS_ERR(priv))
 841		return ERR_CAST(priv);
 842
 843	return to_tegra_display_hub_state(priv);
 844}
 845
 846int tegra_display_hub_atomic_check(struct drm_device *drm,
 847				   struct drm_atomic_state *state)
 848{
 849	struct tegra_drm *tegra = drm->dev_private;
 850	struct tegra_display_hub_state *hub_state;
 851	struct drm_crtc_state *old, *new;
 852	struct drm_crtc *crtc;
 853	unsigned int i;
 854
 855	if (!tegra->hub)
 856		return 0;
 857
 858	hub_state = tegra_display_hub_get_state(tegra->hub, state);
 859	if (IS_ERR(hub_state))
 860		return PTR_ERR(hub_state);
 861
 862	/*
 863	 * The display hub display clock needs to be fed by the display clock
 864	 * with the highest frequency to ensure proper functioning of all the
 865	 * displays.
 866	 *
 867	 * Note that this isn't used before Tegra186, but it doesn't hurt and
 868	 * conditionalizing it would make the code less clean.
 869	 */
 870	for_each_oldnew_crtc_in_state(state, crtc, old, new, i) {
 871		struct tegra_dc_state *dc = to_dc_state(new);
 872
 873		if (new->active) {
 874			if (!hub_state->clk || dc->pclk > hub_state->rate) {
 875				hub_state->dc = to_tegra_dc(dc->base.crtc);
 876				hub_state->clk = hub_state->dc->clk;
 877				hub_state->rate = dc->pclk;
 878			}
 879		}
 880	}
 881
 882	return 0;
 883}
 884
 885static void tegra_display_hub_update(struct tegra_dc *dc)
 886{
 887	u32 value;
 888	int err;
 889
 890	err = host1x_client_resume(&dc->client);
 891	if (err < 0) {
 892		dev_err(dc->dev, "failed to resume: %d\n", err);
 893		return;
 894	}
 895
 896	value = tegra_dc_readl(dc, DC_CMD_IHUB_COMMON_MISC_CTL);
 897	value &= ~LATENCY_EVENT;
 898	tegra_dc_writel(dc, value, DC_CMD_IHUB_COMMON_MISC_CTL);
 899
 900	value = tegra_dc_readl(dc, DC_DISP_IHUB_COMMON_DISPLAY_FETCH_METER);
 901	value = CURS_SLOTS(1) | WGRP_SLOTS(1);
 902	tegra_dc_writel(dc, value, DC_DISP_IHUB_COMMON_DISPLAY_FETCH_METER);
 903
 904	tegra_dc_writel(dc, COMMON_UPDATE, DC_CMD_STATE_CONTROL);
 905	tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
 906	tegra_dc_writel(dc, COMMON_ACTREQ, DC_CMD_STATE_CONTROL);
 907	tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
 908
 909	host1x_client_suspend(&dc->client);
 910}
 911
 912void tegra_display_hub_atomic_commit(struct drm_device *drm,
 913				     struct drm_atomic_state *state)
 914{
 915	struct tegra_drm *tegra = drm->dev_private;
 916	struct tegra_display_hub *hub = tegra->hub;
 917	struct tegra_display_hub_state *hub_state;
 918	struct device *dev = hub->client.dev;
 919	int err;
 920
 921	hub_state = to_tegra_display_hub_state(hub->base.state);
 922
 923	if (hub_state->clk) {
 924		err = clk_set_rate(hub_state->clk, hub_state->rate);
 925		if (err < 0)
 926			dev_err(dev, "failed to set rate of %pC to %lu Hz\n",
 927				hub_state->clk, hub_state->rate);
 928
 929		err = clk_set_parent(hub->clk_disp, hub_state->clk);
 930		if (err < 0)
 931			dev_err(dev, "failed to set parent of %pC to %pC: %d\n",
 932				hub->clk_disp, hub_state->clk, err);
 933	}
 934
 935	if (hub_state->dc)
 936		tegra_display_hub_update(hub_state->dc);
 937}
 938
 939static int tegra_display_hub_init(struct host1x_client *client)
 940{
 941	struct tegra_display_hub *hub = to_tegra_display_hub(client);
 942	struct drm_device *drm = dev_get_drvdata(client->host);
 943	struct tegra_drm *tegra = drm->dev_private;
 944	struct tegra_display_hub_state *state;
 945
 946	state = kzalloc(sizeof(*state), GFP_KERNEL);
 947	if (!state)
 948		return -ENOMEM;
 949
 950	drm_atomic_private_obj_init(drm, &hub->base, &state->base,
 951				    &tegra_display_hub_state_funcs);
 952
 953	tegra->hub = hub;
 954
 955	return 0;
 956}
 957
 958static int tegra_display_hub_exit(struct host1x_client *client)
 959{
 960	struct drm_device *drm = dev_get_drvdata(client->host);
 961	struct tegra_drm *tegra = drm->dev_private;
 962
 963	drm_atomic_private_obj_fini(&tegra->hub->base);
 964	tegra->hub = NULL;
 965
 966	return 0;
 967}
 968
 969static int tegra_display_hub_runtime_suspend(struct host1x_client *client)
 970{
 971	struct tegra_display_hub *hub = to_tegra_display_hub(client);
 972	struct device *dev = client->dev;
 973	unsigned int i = hub->num_heads;
 974	int err;
 975
 976	err = reset_control_assert(hub->rst);
 977	if (err < 0)
 978		return err;
 979
 980	while (i--)
 981		clk_disable_unprepare(hub->clk_heads[i]);
 982
 983	clk_disable_unprepare(hub->clk_hub);
 984	clk_disable_unprepare(hub->clk_dsc);
 985	clk_disable_unprepare(hub->clk_disp);
 986
 987	pm_runtime_put_sync(dev);
 988
 989	return 0;
 990}
 991
 992static int tegra_display_hub_runtime_resume(struct host1x_client *client)
 993{
 994	struct tegra_display_hub *hub = to_tegra_display_hub(client);
 995	struct device *dev = client->dev;
 996	unsigned int i;
 997	int err;
 998
 999	err = pm_runtime_resume_and_get(dev);
1000	if (err < 0) {
1001		dev_err(dev, "failed to get runtime PM: %d\n", err);
1002		return err;
1003	}
1004
1005	err = clk_prepare_enable(hub->clk_disp);
1006	if (err < 0)
1007		goto put_rpm;
1008
1009	err = clk_prepare_enable(hub->clk_dsc);
1010	if (err < 0)
1011		goto disable_disp;
1012
1013	err = clk_prepare_enable(hub->clk_hub);
1014	if (err < 0)
1015		goto disable_dsc;
1016
1017	for (i = 0; i < hub->num_heads; i++) {
1018		err = clk_prepare_enable(hub->clk_heads[i]);
1019		if (err < 0)
1020			goto disable_heads;
1021	}
1022
1023	err = reset_control_deassert(hub->rst);
1024	if (err < 0)
1025		goto disable_heads;
1026
1027	return 0;
1028
1029disable_heads:
1030	while (i--)
1031		clk_disable_unprepare(hub->clk_heads[i]);
1032
1033	clk_disable_unprepare(hub->clk_hub);
1034disable_dsc:
1035	clk_disable_unprepare(hub->clk_dsc);
1036disable_disp:
1037	clk_disable_unprepare(hub->clk_disp);
1038put_rpm:
1039	pm_runtime_put_sync(dev);
1040	return err;
1041}
1042
1043static const struct host1x_client_ops tegra_display_hub_ops = {
1044	.init = tegra_display_hub_init,
1045	.exit = tegra_display_hub_exit,
1046	.suspend = tegra_display_hub_runtime_suspend,
1047	.resume = tegra_display_hub_runtime_resume,
1048};
1049
1050static int tegra_display_hub_probe(struct platform_device *pdev)
1051{
1052	u64 dma_mask = dma_get_mask(pdev->dev.parent);
1053	struct device_node *child = NULL;
1054	struct tegra_display_hub *hub;
1055	struct clk *clk;
1056	unsigned int i;
1057	int err;
1058
1059	err = dma_coerce_mask_and_coherent(&pdev->dev, dma_mask);
1060	if (err < 0) {
1061		dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err);
1062		return err;
1063	}
1064
1065	hub = devm_kzalloc(&pdev->dev, sizeof(*hub), GFP_KERNEL);
1066	if (!hub)
1067		return -ENOMEM;
1068
1069	hub->soc = of_device_get_match_data(&pdev->dev);
1070
1071	hub->clk_disp = devm_clk_get(&pdev->dev, "disp");
1072	if (IS_ERR(hub->clk_disp)) {
1073		err = PTR_ERR(hub->clk_disp);
1074		return err;
1075	}
1076
1077	if (hub->soc->supports_dsc) {
1078		hub->clk_dsc = devm_clk_get(&pdev->dev, "dsc");
1079		if (IS_ERR(hub->clk_dsc)) {
1080			err = PTR_ERR(hub->clk_dsc);
1081			return err;
1082		}
1083	}
1084
1085	hub->clk_hub = devm_clk_get(&pdev->dev, "hub");
1086	if (IS_ERR(hub->clk_hub)) {
1087		err = PTR_ERR(hub->clk_hub);
1088		return err;
1089	}
1090
1091	hub->rst = devm_reset_control_get(&pdev->dev, "misc");
1092	if (IS_ERR(hub->rst)) {
1093		err = PTR_ERR(hub->rst);
1094		return err;
1095	}
1096
1097	hub->wgrps = devm_kcalloc(&pdev->dev, hub->soc->num_wgrps,
1098				  sizeof(*hub->wgrps), GFP_KERNEL);
1099	if (!hub->wgrps)
1100		return -ENOMEM;
1101
1102	for (i = 0; i < hub->soc->num_wgrps; i++) {
1103		struct tegra_windowgroup *wgrp = &hub->wgrps[i];
1104		char id[16];
1105
1106		snprintf(id, sizeof(id), "wgrp%u", i);
1107		mutex_init(&wgrp->lock);
1108		wgrp->usecount = 0;
1109		wgrp->index = i;
1110
1111		wgrp->rst = devm_reset_control_get(&pdev->dev, id);
1112		if (IS_ERR(wgrp->rst))
1113			return PTR_ERR(wgrp->rst);
1114
1115		err = reset_control_assert(wgrp->rst);
1116		if (err < 0)
1117			return err;
1118	}
1119
1120	hub->num_heads = of_get_child_count(pdev->dev.of_node);
1121
1122	hub->clk_heads = devm_kcalloc(&pdev->dev, hub->num_heads, sizeof(clk),
1123				      GFP_KERNEL);
1124	if (!hub->clk_heads)
1125		return -ENOMEM;
1126
1127	for (i = 0; i < hub->num_heads; i++) {
1128		child = of_get_next_child(pdev->dev.of_node, child);
1129		if (!child) {
1130			dev_err(&pdev->dev, "failed to find node for head %u\n",
1131				i);
1132			return -ENODEV;
1133		}
1134
1135		clk = devm_get_clk_from_child(&pdev->dev, child, "dc");
1136		if (IS_ERR(clk)) {
1137			dev_err(&pdev->dev, "failed to get clock for head %u\n",
1138				i);
1139			of_node_put(child);
1140			return PTR_ERR(clk);
1141		}
1142
1143		hub->clk_heads[i] = clk;
1144	}
1145
1146	of_node_put(child);
1147
1148	/* XXX: enable clock across reset? */
1149	err = reset_control_assert(hub->rst);
1150	if (err < 0)
1151		return err;
1152
1153	platform_set_drvdata(pdev, hub);
1154	pm_runtime_enable(&pdev->dev);
1155
1156	INIT_LIST_HEAD(&hub->client.list);
1157	hub->client.ops = &tegra_display_hub_ops;
1158	hub->client.dev = &pdev->dev;
1159
1160	err = host1x_client_register(&hub->client);
1161	if (err < 0)
1162		dev_err(&pdev->dev, "failed to register host1x client: %d\n",
1163			err);
1164
1165	err = devm_of_platform_populate(&pdev->dev);
1166	if (err < 0)
1167		goto unregister;
1168
1169	return err;
1170
1171unregister:
1172	host1x_client_unregister(&hub->client);
1173	pm_runtime_disable(&pdev->dev);
1174	return err;
1175}
1176
1177static void tegra_display_hub_remove(struct platform_device *pdev)
1178{
1179	struct tegra_display_hub *hub = platform_get_drvdata(pdev);
1180	unsigned int i;
1181
1182	host1x_client_unregister(&hub->client);
1183
1184	for (i = 0; i < hub->soc->num_wgrps; i++) {
1185		struct tegra_windowgroup *wgrp = &hub->wgrps[i];
1186
1187		mutex_destroy(&wgrp->lock);
1188	}
1189
1190	pm_runtime_disable(&pdev->dev);
1191}
1192
1193static const struct tegra_display_hub_soc tegra186_display_hub = {
1194	.num_wgrps = 6,
1195	.supports_dsc = true,
1196};
1197
1198static const struct tegra_display_hub_soc tegra194_display_hub = {
1199	.num_wgrps = 6,
1200	.supports_dsc = false,
1201};
1202
1203static const struct of_device_id tegra_display_hub_of_match[] = {
1204	{
1205		.compatible = "nvidia,tegra194-display",
1206		.data = &tegra194_display_hub
1207	}, {
1208		.compatible = "nvidia,tegra186-display",
1209		.data = &tegra186_display_hub
1210	}, {
1211		/* sentinel */
1212	}
1213};
1214MODULE_DEVICE_TABLE(of, tegra_display_hub_of_match);
1215
1216struct platform_driver tegra_display_hub_driver = {
1217	.driver = {
1218		.name = "tegra-display-hub",
1219		.of_match_table = tegra_display_hub_of_match,
1220	},
1221	.probe = tegra_display_hub_probe,
1222	.remove_new = tegra_display_hub_remove,
1223};