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