Loading...
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};
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};