Linux Audio

Check our new training course

Loading...
v6.8
   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};
v4.17
 
  1/*
  2 * Copyright (C) 2017 NVIDIA CORPORATION.  All rights reserved.
  3 *
  4 * This program is free software; you can redistribute it and/or modify
  5 * it under the terms of the GNU General Public License version 2 as
  6 * published by the Free Software Foundation.
  7 */
  8
  9#include <linux/clk.h>
 
 
 10#include <linux/host1x.h>
 11#include <linux/module.h>
 12#include <linux/of.h>
 13#include <linux/of_device.h>
 14#include <linux/of_graph.h>
 
 15#include <linux/platform_device.h>
 16#include <linux/pm_runtime.h>
 17#include <linux/reset.h>
 18
 19#include <drm/drmP.h>
 20#include <drm/drm_atomic.h>
 21#include <drm/drm_atomic_helper.h>
 22#include <drm/drm_crtc_helper.h>
 
 
 
 23
 24#include "drm.h"
 25#include "dc.h"
 26#include "plane.h"
 27
 
 
 28static const u32 tegra_shared_plane_formats[] = {
 29	DRM_FORMAT_ARGB1555,
 30	DRM_FORMAT_RGB565,
 31	DRM_FORMAT_RGBA5551,
 32	DRM_FORMAT_ARGB8888,
 33	DRM_FORMAT_ABGR8888,
 34	/* new on Tegra114 */
 35	DRM_FORMAT_ABGR4444,
 36	DRM_FORMAT_ABGR1555,
 37	DRM_FORMAT_BGRA5551,
 38	DRM_FORMAT_XRGB1555,
 39	DRM_FORMAT_RGBX5551,
 40	DRM_FORMAT_XBGR1555,
 41	DRM_FORMAT_BGRX5551,
 42	DRM_FORMAT_BGR565,
 43	DRM_FORMAT_XRGB8888,
 44	DRM_FORMAT_XBGR8888,
 45	/* planar formats */
 46	DRM_FORMAT_UYVY,
 47	DRM_FORMAT_YUYV,
 48	DRM_FORMAT_YUV420,
 49	DRM_FORMAT_YUV422,
 50};
 51
 52static const u64 tegra_shared_plane_modifiers[] = {
 53	DRM_FORMAT_MOD_LINEAR,
 54	DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0),
 55	DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1),
 56	DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2),
 57	DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3),
 58	DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4),
 59	DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5),
 
 
 
 
 
 
 
 
 
 
 
 
 60	DRM_FORMAT_MOD_INVALID
 61};
 62
 63static inline unsigned int tegra_plane_offset(struct tegra_plane *plane,
 64					      unsigned int offset)
 65{
 66	if (offset >= 0x500 && offset <= 0x581) {
 67		offset = 0x000 + (offset - 0x500);
 68		return plane->offset + offset;
 69	}
 70
 71	if (offset >= 0x700 && offset <= 0x73c) {
 72		offset = 0x180 + (offset - 0x700);
 73		return plane->offset + offset;
 74	}
 75
 76	if (offset >= 0x800 && offset <= 0x83e) {
 77		offset = 0x1c0 + (offset - 0x800);
 78		return plane->offset + offset;
 79	}
 80
 81	dev_WARN(plane->dc->dev, "invalid offset: %x\n", offset);
 82
 83	return plane->offset + offset;
 84}
 85
 86static inline u32 tegra_plane_readl(struct tegra_plane *plane,
 87				    unsigned int offset)
 88{
 89	return tegra_dc_readl(plane->dc, tegra_plane_offset(plane, offset));
 90}
 91
 92static inline void tegra_plane_writel(struct tegra_plane *plane, u32 value,
 93				      unsigned int offset)
 94{
 95	tegra_dc_writel(plane->dc, value, tegra_plane_offset(plane, offset));
 96}
 97
 98static int tegra_windowgroup_enable(struct tegra_windowgroup *wgrp)
 99{
 
 
100	mutex_lock(&wgrp->lock);
101
102	if (wgrp->usecount == 0) {
103		pm_runtime_get_sync(wgrp->parent);
 
 
 
 
 
104		reset_control_deassert(wgrp->rst);
105	}
106
107	wgrp->usecount++;
 
 
108	mutex_unlock(&wgrp->lock);
109
110	return 0;
111}
112
113static void tegra_windowgroup_disable(struct tegra_windowgroup *wgrp)
114{
115	int err;
116
117	mutex_lock(&wgrp->lock);
118
119	if (wgrp->usecount == 1) {
120		err = reset_control_assert(wgrp->rst);
121		if (err < 0) {
122			pr_err("failed to assert reset for window group %u\n",
123			       wgrp->index);
124		}
125
126		pm_runtime_put(wgrp->parent);
127	}
128
129	wgrp->usecount--;
130	mutex_unlock(&wgrp->lock);
131}
132
133int tegra_display_hub_prepare(struct tegra_display_hub *hub)
134{
135	unsigned int i;
136
137	/*
138	 * XXX Enabling/disabling windowgroups needs to happen when the owner
139	 * display controller is disabled. There's currently no good point at
140	 * which this could be executed, so unconditionally enable all window
141	 * groups for now.
142	 */
143	for (i = 0; i < hub->soc->num_wgrps; i++) {
144		struct tegra_windowgroup *wgrp = &hub->wgrps[i];
145
146		tegra_windowgroup_enable(wgrp);
 
 
147	}
148
149	return 0;
150}
151
152void tegra_display_hub_cleanup(struct tegra_display_hub *hub)
153{
154	unsigned int i;
155
156	/*
157	 * XXX Remove this once window groups can be more fine-grainedly
158	 * enabled and disabled.
159	 */
160	for (i = 0; i < hub->soc->num_wgrps; i++) {
161		struct tegra_windowgroup *wgrp = &hub->wgrps[i];
162
163		tegra_windowgroup_disable(wgrp);
 
 
164	}
165}
166
167static void tegra_shared_plane_update(struct tegra_plane *plane)
168{
169	struct tegra_dc *dc = plane->dc;
170	unsigned long timeout;
171	u32 mask, value;
172
173	mask = COMMON_UPDATE | WIN_A_UPDATE << plane->base.index;
174	tegra_dc_writel(dc, mask, DC_CMD_STATE_CONTROL);
175
176	timeout = jiffies + msecs_to_jiffies(1000);
177
178	while (time_before(jiffies, timeout)) {
179		value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
180		if ((value & mask) == 0)
181			break;
182
183		usleep_range(100, 400);
184	}
185}
186
187static void tegra_shared_plane_activate(struct tegra_plane *plane)
188{
189	struct tegra_dc *dc = plane->dc;
190	unsigned long timeout;
191	u32 mask, value;
192
193	mask = COMMON_ACTREQ | WIN_A_ACT_REQ << plane->base.index;
194	tegra_dc_writel(dc, mask, DC_CMD_STATE_CONTROL);
195
196	timeout = jiffies + msecs_to_jiffies(1000);
197
198	while (time_before(jiffies, timeout)) {
199		value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
200		if ((value & mask) == 0)
201			break;
202
203		usleep_range(100, 400);
204	}
205}
206
207static unsigned int
208tegra_shared_plane_get_owner(struct tegra_plane *plane, struct tegra_dc *dc)
209{
210	unsigned int offset =
211		tegra_plane_offset(plane, DC_WIN_CORE_WINDOWGROUP_SET_CONTROL);
212
213	return tegra_dc_readl(dc, offset) & OWNER_MASK;
214}
215
216static bool tegra_dc_owns_shared_plane(struct tegra_dc *dc,
217				       struct tegra_plane *plane)
218{
219	struct device *dev = dc->dev;
220
221	if (tegra_shared_plane_get_owner(plane, dc) == dc->pipe) {
222		if (plane->dc == dc)
223			return true;
224
225		dev_WARN(dev, "head %u owns window %u but is not attached\n",
226			 dc->pipe, plane->index);
227	}
228
229	return false;
230}
231
232static int tegra_shared_plane_set_owner(struct tegra_plane *plane,
233					struct tegra_dc *new)
234{
235	unsigned int offset =
236		tegra_plane_offset(plane, DC_WIN_CORE_WINDOWGROUP_SET_CONTROL);
237	struct tegra_dc *old = plane->dc, *dc = new ? new : old;
238	struct device *dev = new ? new->dev : old->dev;
239	unsigned int owner, index = plane->index;
240	u32 value;
241
242	value = tegra_dc_readl(dc, offset);
243	owner = value & OWNER_MASK;
244
245	if (new && (owner != OWNER_MASK && owner != new->pipe)) {
246		dev_WARN(dev, "window %u owned by head %u\n", index, owner);
247		return -EBUSY;
248	}
249
250	/*
251	 * This seems to happen whenever the head has been disabled with one
252	 * or more windows being active. This is harmless because we'll just
253	 * reassign the window to the new head anyway.
254	 */
255	if (old && owner == OWNER_MASK)
256		dev_dbg(dev, "window %u not owned by head %u but %u\n", index,
257			old->pipe, owner);
258
259	value &= ~OWNER_MASK;
260
261	if (new)
262		value |= OWNER(new->pipe);
263	else
264		value |= OWNER_MASK;
265
266	tegra_dc_writel(dc, value, offset);
267
268	plane->dc = new;
269
270	return 0;
271}
272
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273static void tegra_dc_assign_shared_plane(struct tegra_dc *dc,
274					 struct tegra_plane *plane)
275{
276	u32 value;
277	int err;
278
279	if (!tegra_dc_owns_shared_plane(dc, plane)) {
280		err = tegra_shared_plane_set_owner(plane, dc);
281		if (err < 0)
282			return;
283	}
284
285	value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_LINEBUF_CONFIG);
286	value |= MODE_FOUR_LINES;
287	tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_LINEBUF_CONFIG);
288
289	value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_WGRP_FETCH_METER);
290	value = SLOTS(1);
291	tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_WGRP_FETCH_METER);
292
293	/* disable watermark */
294	value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLA);
295	value &= ~LATENCY_CTL_MODE_ENABLE;
296	tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLA);
297
298	value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLB);
299	value |= WATERMARK_MASK;
300	tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_WGRP_LATENCY_CTLB);
301
302	/* pipe meter */
303	value = tegra_plane_readl(plane, DC_WIN_CORE_PRECOMP_WGRP_PIPE_METER);
304	value = PIPE_METER_INT(0) | PIPE_METER_FRAC(0);
305	tegra_plane_writel(plane, value, DC_WIN_CORE_PRECOMP_WGRP_PIPE_METER);
306
307	/* mempool entries */
308	value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_WGRP_POOL_CONFIG);
309	value = MEMPOOL_ENTRIES(0x331);
310	tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_WGRP_POOL_CONFIG);
311
312	value = tegra_plane_readl(plane, DC_WIN_CORE_IHUB_THREAD_GROUP);
313	value &= ~THREAD_NUM_MASK;
314	value |= THREAD_NUM(plane->base.index);
315	value |= THREAD_GROUP_ENABLE;
316	tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_THREAD_GROUP);
317
 
 
318	tegra_shared_plane_update(plane);
319	tegra_shared_plane_activate(plane);
320}
321
322static void tegra_dc_remove_shared_plane(struct tegra_dc *dc,
323					 struct tegra_plane *plane)
324{
325	tegra_shared_plane_set_owner(plane, NULL);
326}
327
328static int tegra_shared_plane_atomic_check(struct drm_plane *plane,
329					   struct drm_plane_state *state)
330{
331	struct tegra_plane_state *plane_state = to_tegra_plane_state(state);
 
 
332	struct tegra_shared_plane *tegra = to_tegra_shared_plane(plane);
333	struct tegra_bo_tiling *tiling = &plane_state->tiling;
334	struct tegra_dc *dc = to_tegra_dc(state->crtc);
335	int err;
336
337	/* no need for further checks if the plane is being disabled */
338	if (!state->crtc || !state->fb)
339		return 0;
340
341	err = tegra_plane_format(state->fb->format->format,
342				 &plane_state->format,
343				 &plane_state->swap);
344	if (err < 0)
345		return err;
346
347	err = tegra_fb_get_tiling(state->fb, tiling);
348	if (err < 0)
349		return err;
350
351	if (tiling->mode == TEGRA_BO_TILING_MODE_BLOCK &&
352	    !dc->soc->supports_block_linear) {
353		DRM_ERROR("hardware doesn't support block linear mode\n");
354		return -EINVAL;
355	}
356
 
 
 
 
 
 
357	/*
358	 * Tegra doesn't support different strides for U and V planes so we
359	 * error out if the user tries to display a framebuffer with such a
360	 * configuration.
361	 */
362	if (state->fb->format->num_planes > 2) {
363		if (state->fb->pitches[2] != state->fb->pitches[1]) {
364			DRM_ERROR("unsupported UV-plane configuration\n");
365			return -EINVAL;
366		}
367	}
368
369	/* XXX scaling is not yet supported, add a check here */
370
371	err = tegra_plane_state_add(&tegra->base, state);
372	if (err < 0)
373		return err;
374
375	return 0;
376}
377
378static void tegra_shared_plane_atomic_disable(struct drm_plane *plane,
379					      struct drm_plane_state *old_state)
380{
381	struct tegra_dc *dc = to_tegra_dc(old_state->crtc);
 
382	struct tegra_plane *p = to_tegra_plane(plane);
 
383	u32 value;
 
384
385	/* rien ne va plus */
386	if (!old_state || !old_state->crtc)
387		return;
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
408static 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
523static 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
529struct 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
576static struct drm_private_state *
577tegra_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
590static 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
599static 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
604static struct tegra_display_hub_state *
605tegra_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
620int 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
659static 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
681void 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 = tegra_display_hub_get_state(hub, 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
708static 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(&hub->base, &state->base,
720				    &tegra_display_hub_state_funcs);
721
722	tegra->hub = hub;
723
724	return 0;
725}
726
727static 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
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
738static const struct host1x_client_ops tegra_display_hub_ops = {
739	.init = tegra_display_hub_init,
740	.exit = tegra_display_hub_exit,
 
 
741};
742
743static int tegra_display_hub_probe(struct platform_device *pdev)
744{
 
 
745	struct tegra_display_hub *hub;
 
746	unsigned int i;
747	int err;
748
 
 
 
 
 
 
749	hub = devm_kzalloc(&pdev->dev, sizeof(*hub), GFP_KERNEL);
750	if (!hub)
751		return -ENOMEM;
752
753	hub->soc = of_device_get_match_data(&pdev->dev);
754
755	hub->clk_disp = devm_clk_get(&pdev->dev, "disp");
756	if (IS_ERR(hub->clk_disp)) {
757		err = PTR_ERR(hub->clk_disp);
758		return err;
759	}
760
761	hub->clk_dsc = devm_clk_get(&pdev->dev, "dsc");
762	if (IS_ERR(hub->clk_dsc)) {
763		err = PTR_ERR(hub->clk_dsc);
764		return err;
 
 
765	}
766
767	hub->clk_hub = devm_clk_get(&pdev->dev, "hub");
768	if (IS_ERR(hub->clk_hub)) {
769		err = PTR_ERR(hub->clk_hub);
770		return err;
771	}
772
773	hub->rst = devm_reset_control_get(&pdev->dev, "misc");
774	if (IS_ERR(hub->rst)) {
775		err = PTR_ERR(hub->rst);
776		return err;
777	}
778
779	hub->wgrps = devm_kcalloc(&pdev->dev, hub->soc->num_wgrps,
780				  sizeof(*hub->wgrps), GFP_KERNEL);
781	if (!hub->wgrps)
782		return -ENOMEM;
783
784	for (i = 0; i < hub->soc->num_wgrps; i++) {
785		struct tegra_windowgroup *wgrp = &hub->wgrps[i];
786		char id[8];
787
788		snprintf(id, sizeof(id), "wgrp%u", i);
789		mutex_init(&wgrp->lock);
790		wgrp->usecount = 0;
791		wgrp->index = i;
792
793		wgrp->rst = devm_reset_control_get(&pdev->dev, id);
794		if (IS_ERR(wgrp->rst))
795			return PTR_ERR(wgrp->rst);
796
797		err = reset_control_assert(wgrp->rst);
798		if (err < 0)
799			return err;
800	}
801
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
802	/* XXX: enable clock across reset? */
803	err = reset_control_assert(hub->rst);
804	if (err < 0)
805		return err;
806
807	platform_set_drvdata(pdev, hub);
808	pm_runtime_enable(&pdev->dev);
809
810	INIT_LIST_HEAD(&hub->client.list);
811	hub->client.ops = &tegra_display_hub_ops;
812	hub->client.dev = &pdev->dev;
813
814	err = host1x_client_register(&hub->client);
815	if (err < 0)
816		dev_err(&pdev->dev, "failed to register host1x client: %d\n",
817			err);
818
 
 
 
 
819	return err;
820}
821
822static int tegra_display_hub_remove(struct platform_device *pdev)
823{
824	struct tegra_display_hub *hub = platform_get_drvdata(pdev);
825	int err;
826
827	err = host1x_client_unregister(&hub->client);
828	if (err < 0) {
829		dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
830			err);
831	}
832
 
 
833	pm_runtime_disable(&pdev->dev);
834
835	return err;
836}
837
838static int __maybe_unused tegra_display_hub_suspend(struct device *dev)
839{
840	struct tegra_display_hub *hub = dev_get_drvdata(dev);
841	int err;
842
843	err = reset_control_assert(hub->rst);
844	if (err < 0)
845		return err;
846
847	clk_disable_unprepare(hub->clk_hub);
848	clk_disable_unprepare(hub->clk_dsc);
849	clk_disable_unprepare(hub->clk_disp);
850
851	return 0;
852}
853
854static int __maybe_unused tegra_display_hub_resume(struct device *dev)
855{
856	struct tegra_display_hub *hub = dev_get_drvdata(dev);
857	int err;
858
859	err = clk_prepare_enable(hub->clk_disp);
860	if (err < 0)
861		return err;
862
863	err = clk_prepare_enable(hub->clk_dsc);
864	if (err < 0)
865		goto disable_disp;
866
867	err = clk_prepare_enable(hub->clk_hub);
868	if (err < 0)
869		goto disable_dsc;
870
871	err = reset_control_deassert(hub->rst);
872	if (err < 0)
873		goto disable_hub;
874
875	return 0;
876
877disable_hub:
878	clk_disable_unprepare(hub->clk_hub);
879disable_dsc:
880	clk_disable_unprepare(hub->clk_dsc);
881disable_disp:
882	clk_disable_unprepare(hub->clk_disp);
883	return err;
884}
885
886static const struct dev_pm_ops tegra_display_hub_pm_ops = {
887	SET_RUNTIME_PM_OPS(tegra_display_hub_suspend,
888			   tegra_display_hub_resume, NULL)
889};
890
891static const struct tegra_display_hub_soc tegra186_display_hub = {
892	.num_wgrps = 6,
 
893};
894
895static const struct of_device_id tegra_display_hub_of_match[] = {
896	{
 
 
 
897		.compatible = "nvidia,tegra186-display",
898		.data = &tegra186_display_hub
899	}, {
900		/* sentinel */
901	}
902};
903MODULE_DEVICE_TABLE(of, tegra_display_hub_of_match);
904
905struct platform_driver tegra_display_hub_driver = {
906	.driver = {
907		.name = "tegra-display-hub",
908		.of_match_table = tegra_display_hub_of_match,
909		.pm = &tegra_display_hub_pm_ops,
910	},
911	.probe = tegra_display_hub_probe,
912	.remove = tegra_display_hub_remove,
913};