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