drm/tegra: Check for NULL pointer instead of IS_ERR()
[deliverable/linux.git] / drivers / gpu / drm / tegra / dc.c
CommitLineData
d8f4a9ed
TR
1/*
2 * Copyright (C) 2012 Avionic Design GmbH
3 * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9
10#include <linux/clk.h>
9eb9b220 11#include <linux/debugfs.h>
df06b759 12#include <linux/iommu.h>
ca48080a 13#include <linux/reset.h>
d8f4a9ed 14
9c012700
TR
15#include <soc/tegra/pmc.h>
16
de2ba664
AM
17#include "dc.h"
18#include "drm.h"
19#include "gem.h"
d8f4a9ed 20
3cb9ae4f
DV
21#include <drm/drm_plane_helper.h>
22
8620fc62
TR
23struct tegra_dc_soc_info {
24 bool supports_interlacing;
e687651b 25 bool supports_cursor;
c134f019 26 bool supports_block_linear;
d1f3e1e0 27 unsigned int pitch_align;
9c012700 28 bool has_powergate;
8620fc62
TR
29};
30
f34bc787
TR
31struct tegra_plane {
32 struct drm_plane base;
33 unsigned int index;
d8f4a9ed
TR
34};
35
f34bc787
TR
36static inline struct tegra_plane *to_tegra_plane(struct drm_plane *plane)
37{
38 return container_of(plane, struct tegra_plane, base);
39}
40
205d48ed
TR
41static void tegra_dc_window_commit(struct tegra_dc *dc, unsigned int index)
42{
43 u32 value = WIN_A_ACT_REQ << index;
44
45 tegra_dc_writel(dc, value << 8, DC_CMD_STATE_CONTROL);
46 tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
47}
48
49static void tegra_dc_cursor_commit(struct tegra_dc *dc)
50{
51 tegra_dc_writel(dc, CURSOR_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
52 tegra_dc_writel(dc, CURSOR_ACT_REQ, DC_CMD_STATE_CONTROL);
53}
54
55static void tegra_dc_commit(struct tegra_dc *dc)
56{
57 tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
58 tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
59}
60
10288eea
TR
61static unsigned int tegra_dc_format(uint32_t format, uint32_t *swap)
62{
63 /* assume no swapping of fetched data */
64 if (swap)
65 *swap = BYTE_SWAP_NOSWAP;
66
67 switch (format) {
68 case DRM_FORMAT_XBGR8888:
69 return WIN_COLOR_DEPTH_R8G8B8A8;
70
71 case DRM_FORMAT_XRGB8888:
72 return WIN_COLOR_DEPTH_B8G8R8A8;
73
74 case DRM_FORMAT_RGB565:
75 return WIN_COLOR_DEPTH_B5G6R5;
76
77 case DRM_FORMAT_UYVY:
78 return WIN_COLOR_DEPTH_YCbCr422;
79
80 case DRM_FORMAT_YUYV:
81 if (swap)
82 *swap = BYTE_SWAP_SWAP2;
83
84 return WIN_COLOR_DEPTH_YCbCr422;
85
86 case DRM_FORMAT_YUV420:
87 return WIN_COLOR_DEPTH_YCbCr420P;
88
89 case DRM_FORMAT_YUV422:
90 return WIN_COLOR_DEPTH_YCbCr422P;
91
92 default:
93 break;
94 }
95
96 WARN(1, "unsupported pixel format %u, using default\n", format);
97 return WIN_COLOR_DEPTH_B8G8R8A8;
98}
99
100static bool tegra_dc_format_is_yuv(unsigned int format, bool *planar)
101{
102 switch (format) {
103 case WIN_COLOR_DEPTH_YCbCr422:
104 case WIN_COLOR_DEPTH_YUV422:
105 if (planar)
106 *planar = false;
107
108 return true;
109
110 case WIN_COLOR_DEPTH_YCbCr420P:
111 case WIN_COLOR_DEPTH_YUV420P:
112 case WIN_COLOR_DEPTH_YCbCr422P:
113 case WIN_COLOR_DEPTH_YUV422P:
114 case WIN_COLOR_DEPTH_YCbCr422R:
115 case WIN_COLOR_DEPTH_YUV422R:
116 case WIN_COLOR_DEPTH_YCbCr422RA:
117 case WIN_COLOR_DEPTH_YUV422RA:
118 if (planar)
119 *planar = true;
120
121 return true;
122 }
123
124 return false;
125}
126
127static inline u32 compute_dda_inc(unsigned int in, unsigned int out, bool v,
128 unsigned int bpp)
129{
130 fixed20_12 outf = dfixed_init(out);
131 fixed20_12 inf = dfixed_init(in);
132 u32 dda_inc;
133 int max;
134
135 if (v)
136 max = 15;
137 else {
138 switch (bpp) {
139 case 2:
140 max = 8;
141 break;
142
143 default:
144 WARN_ON_ONCE(1);
145 /* fallthrough */
146 case 4:
147 max = 4;
148 break;
149 }
150 }
151
152 outf.full = max_t(u32, outf.full - dfixed_const(1), dfixed_const(1));
153 inf.full -= dfixed_const(1);
154
155 dda_inc = dfixed_div(inf, outf);
156 dda_inc = min_t(u32, dda_inc, dfixed_const(max));
157
158 return dda_inc;
159}
160
161static inline u32 compute_initial_dda(unsigned int in)
162{
163 fixed20_12 inf = dfixed_init(in);
164 return dfixed_frac(inf);
165}
166
167static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
168 const struct tegra_dc_window *window)
169{
170 unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp;
93396d0f 171 unsigned long value, flags;
10288eea
TR
172 bool yuv, planar;
173
174 /*
175 * For YUV planar modes, the number of bytes per pixel takes into
176 * account only the luma component and therefore is 1.
177 */
178 yuv = tegra_dc_format_is_yuv(window->format, &planar);
179 if (!yuv)
180 bpp = window->bits_per_pixel / 8;
181 else
182 bpp = planar ? 1 : 2;
183
93396d0f
SP
184 spin_lock_irqsave(&dc->lock, flags);
185
10288eea
TR
186 value = WINDOW_A_SELECT << index;
187 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
188
189 tegra_dc_writel(dc, window->format, DC_WIN_COLOR_DEPTH);
190 tegra_dc_writel(dc, window->swap, DC_WIN_BYTE_SWAP);
191
192 value = V_POSITION(window->dst.y) | H_POSITION(window->dst.x);
193 tegra_dc_writel(dc, value, DC_WIN_POSITION);
194
195 value = V_SIZE(window->dst.h) | H_SIZE(window->dst.w);
196 tegra_dc_writel(dc, value, DC_WIN_SIZE);
197
198 h_offset = window->src.x * bpp;
199 v_offset = window->src.y;
200 h_size = window->src.w * bpp;
201 v_size = window->src.h;
202
203 value = V_PRESCALED_SIZE(v_size) | H_PRESCALED_SIZE(h_size);
204 tegra_dc_writel(dc, value, DC_WIN_PRESCALED_SIZE);
205
206 /*
207 * For DDA computations the number of bytes per pixel for YUV planar
208 * modes needs to take into account all Y, U and V components.
209 */
210 if (yuv && planar)
211 bpp = 2;
212
213 h_dda = compute_dda_inc(window->src.w, window->dst.w, false, bpp);
214 v_dda = compute_dda_inc(window->src.h, window->dst.h, true, bpp);
215
216 value = V_DDA_INC(v_dda) | H_DDA_INC(h_dda);
217 tegra_dc_writel(dc, value, DC_WIN_DDA_INC);
218
219 h_dda = compute_initial_dda(window->src.x);
220 v_dda = compute_initial_dda(window->src.y);
221
222 tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA);
223 tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA);
224
225 tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE);
226 tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE);
227
228 tegra_dc_writel(dc, window->base[0], DC_WINBUF_START_ADDR);
229
230 if (yuv && planar) {
231 tegra_dc_writel(dc, window->base[1], DC_WINBUF_START_ADDR_U);
232 tegra_dc_writel(dc, window->base[2], DC_WINBUF_START_ADDR_V);
233 value = window->stride[1] << 16 | window->stride[0];
234 tegra_dc_writel(dc, value, DC_WIN_LINE_STRIDE);
235 } else {
236 tegra_dc_writel(dc, window->stride[0], DC_WIN_LINE_STRIDE);
237 }
238
239 if (window->bottom_up)
240 v_offset += window->src.h - 1;
241
242 tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET);
243 tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET);
244
c134f019
TR
245 if (dc->soc->supports_block_linear) {
246 unsigned long height = window->tiling.value;
247
248 switch (window->tiling.mode) {
249 case TEGRA_BO_TILING_MODE_PITCH:
250 value = DC_WINBUF_SURFACE_KIND_PITCH;
251 break;
252
253 case TEGRA_BO_TILING_MODE_TILED:
254 value = DC_WINBUF_SURFACE_KIND_TILED;
255 break;
256
257 case TEGRA_BO_TILING_MODE_BLOCK:
258 value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(height) |
259 DC_WINBUF_SURFACE_KIND_BLOCK;
260 break;
261 }
262
263 tegra_dc_writel(dc, value, DC_WINBUF_SURFACE_KIND);
10288eea 264 } else {
c134f019
TR
265 switch (window->tiling.mode) {
266 case TEGRA_BO_TILING_MODE_PITCH:
267 value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV |
268 DC_WIN_BUFFER_ADDR_MODE_LINEAR;
269 break;
10288eea 270
c134f019
TR
271 case TEGRA_BO_TILING_MODE_TILED:
272 value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV |
273 DC_WIN_BUFFER_ADDR_MODE_TILE;
274 break;
275
276 case TEGRA_BO_TILING_MODE_BLOCK:
277 DRM_ERROR("hardware doesn't support block linear mode\n");
93396d0f 278 spin_unlock_irqrestore(&dc->lock, flags);
c134f019
TR
279 return -EINVAL;
280 }
281
282 tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE);
283 }
10288eea
TR
284
285 value = WIN_ENABLE;
286
287 if (yuv) {
288 /* setup default colorspace conversion coefficients */
289 tegra_dc_writel(dc, 0x00f0, DC_WIN_CSC_YOF);
290 tegra_dc_writel(dc, 0x012a, DC_WIN_CSC_KYRGB);
291 tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KUR);
292 tegra_dc_writel(dc, 0x0198, DC_WIN_CSC_KVR);
293 tegra_dc_writel(dc, 0x039b, DC_WIN_CSC_KUG);
294 tegra_dc_writel(dc, 0x032f, DC_WIN_CSC_KVG);
295 tegra_dc_writel(dc, 0x0204, DC_WIN_CSC_KUB);
296 tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KVB);
297
298 value |= CSC_ENABLE;
299 } else if (window->bits_per_pixel < 24) {
300 value |= COLOR_EXPAND;
301 }
302
303 if (window->bottom_up)
304 value |= V_DIRECTION;
305
306 tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
307
308 /*
309 * Disable blending and assume Window A is the bottom-most window,
310 * Window C is the top-most window and Window B is in the middle.
311 */
312 tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_NOKEY);
313 tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_1WIN);
314
315 switch (index) {
316 case 0:
317 tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_X);
318 tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y);
319 tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY);
320 break;
321
322 case 1:
323 tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X);
324 tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y);
325 tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY);
326 break;
327
328 case 2:
329 tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X);
330 tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_Y);
331 tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_3WIN_XY);
332 break;
333 }
334
205d48ed 335 tegra_dc_window_commit(dc, index);
10288eea 336
93396d0f
SP
337 spin_unlock_irqrestore(&dc->lock, flags);
338
10288eea
TR
339 return 0;
340}
341
c7679306
TR
342static int tegra_window_plane_disable(struct drm_plane *plane)
343{
344 struct tegra_dc *dc = to_tegra_dc(plane->crtc);
345 struct tegra_plane *p = to_tegra_plane(plane);
93396d0f 346 unsigned long flags;
c7679306
TR
347 u32 value;
348
349 if (!plane->crtc)
350 return 0;
351
93396d0f
SP
352 spin_lock_irqsave(&dc->lock, flags);
353
c7679306
TR
354 value = WINDOW_A_SELECT << p->index;
355 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
356
357 value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
358 value &= ~WIN_ENABLE;
359 tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
360
361 tegra_dc_window_commit(dc, p->index);
362
93396d0f
SP
363 spin_unlock_irqrestore(&dc->lock, flags);
364
c7679306
TR
365 return 0;
366}
367
368static void tegra_plane_destroy(struct drm_plane *plane)
369{
370 struct tegra_plane *p = to_tegra_plane(plane);
371
372 drm_plane_cleanup(plane);
373 kfree(p);
374}
375
376static const u32 tegra_primary_plane_formats[] = {
377 DRM_FORMAT_XBGR8888,
378 DRM_FORMAT_XRGB8888,
379 DRM_FORMAT_RGB565,
380};
381
382static int tegra_primary_plane_update(struct drm_plane *plane,
383 struct drm_crtc *crtc,
384 struct drm_framebuffer *fb, int crtc_x,
385 int crtc_y, unsigned int crtc_w,
386 unsigned int crtc_h, uint32_t src_x,
387 uint32_t src_y, uint32_t src_w,
388 uint32_t src_h)
389{
390 struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
391 struct tegra_plane *p = to_tegra_plane(plane);
392 struct tegra_dc *dc = to_tegra_dc(crtc);
393 struct tegra_dc_window window;
394 int err;
395
396 memset(&window, 0, sizeof(window));
397 window.src.x = src_x >> 16;
398 window.src.y = src_y >> 16;
399 window.src.w = src_w >> 16;
400 window.src.h = src_h >> 16;
401 window.dst.x = crtc_x;
402 window.dst.y = crtc_y;
403 window.dst.w = crtc_w;
404 window.dst.h = crtc_h;
405 window.format = tegra_dc_format(fb->pixel_format, &window.swap);
406 window.bits_per_pixel = fb->bits_per_pixel;
407 window.bottom_up = tegra_fb_is_bottom_up(fb);
408
409 err = tegra_fb_get_tiling(fb, &window.tiling);
410 if (err < 0)
411 return err;
412
413 window.base[0] = bo->paddr + fb->offsets[0];
414 window.stride[0] = fb->pitches[0];
415
416 err = tegra_dc_setup_window(dc, p->index, &window);
417 if (err < 0)
418 return err;
10288eea
TR
419
420 return 0;
421}
422
c7679306
TR
423static void tegra_primary_plane_destroy(struct drm_plane *plane)
424{
425 tegra_window_plane_disable(plane);
426 tegra_plane_destroy(plane);
427}
428
429static const struct drm_plane_funcs tegra_primary_plane_funcs = {
430 .update_plane = tegra_primary_plane_update,
431 .disable_plane = tegra_window_plane_disable,
432 .destroy = tegra_primary_plane_destroy,
433};
434
435static struct drm_plane *tegra_dc_primary_plane_create(struct drm_device *drm,
436 struct tegra_dc *dc)
437{
518e6227
TR
438 /*
439 * Ideally this would use drm_crtc_mask(), but that would require the
440 * CRTC to already be in the mode_config's list of CRTCs. However, it
441 * will only be added to that list in the drm_crtc_init_with_planes()
442 * (in tegra_dc_init()), which in turn requires registration of these
443 * planes. So we have ourselves a nice little chicken and egg problem
444 * here.
445 *
446 * We work around this by manually creating the mask from the number
447 * of CRTCs that have been registered, and should therefore always be
448 * the same as drm_crtc_index() after registration.
449 */
450 unsigned long possible_crtcs = 1 << drm->mode_config.num_crtc;
c7679306
TR
451 struct tegra_plane *plane;
452 unsigned int num_formats;
453 const u32 *formats;
454 int err;
455
456 plane = kzalloc(sizeof(*plane), GFP_KERNEL);
457 if (!plane)
458 return ERR_PTR(-ENOMEM);
459
460 num_formats = ARRAY_SIZE(tegra_primary_plane_formats);
461 formats = tegra_primary_plane_formats;
462
518e6227 463 err = drm_universal_plane_init(drm, &plane->base, possible_crtcs,
c7679306
TR
464 &tegra_primary_plane_funcs, formats,
465 num_formats, DRM_PLANE_TYPE_PRIMARY);
466 if (err < 0) {
467 kfree(plane);
468 return ERR_PTR(err);
469 }
470
471 return &plane->base;
472}
473
474static const u32 tegra_cursor_plane_formats[] = {
475 DRM_FORMAT_RGBA8888,
476};
477
478static int tegra_cursor_plane_update(struct drm_plane *plane,
479 struct drm_crtc *crtc,
480 struct drm_framebuffer *fb, int crtc_x,
481 int crtc_y, unsigned int crtc_w,
482 unsigned int crtc_h, uint32_t src_x,
483 uint32_t src_y, uint32_t src_w,
484 uint32_t src_h)
485{
486 struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
487 struct tegra_dc *dc = to_tegra_dc(crtc);
488 u32 value = CURSOR_CLIP_DISPLAY;
489
490 /* scaling not supported for cursor */
491 if ((src_w >> 16 != crtc_w) || (src_h >> 16 != crtc_h))
492 return -EINVAL;
493
494 /* only square cursors supported */
495 if (src_w != src_h)
496 return -EINVAL;
497
498 switch (crtc_w) {
499 case 32:
500 value |= CURSOR_SIZE_32x32;
501 break;
502
503 case 64:
504 value |= CURSOR_SIZE_64x64;
505 break;
506
507 case 128:
508 value |= CURSOR_SIZE_128x128;
509 break;
510
511 case 256:
512 value |= CURSOR_SIZE_256x256;
513 break;
514
515 default:
516 return -EINVAL;
517 }
518
519 value |= (bo->paddr >> 10) & 0x3fffff;
520 tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR);
521
522#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
523 value = (bo->paddr >> 32) & 0x3;
524 tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR_HI);
525#endif
526
527 /* enable cursor and set blend mode */
528 value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
529 value |= CURSOR_ENABLE;
530 tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
531
532 value = tegra_dc_readl(dc, DC_DISP_BLEND_CURSOR_CONTROL);
533 value &= ~CURSOR_DST_BLEND_MASK;
534 value &= ~CURSOR_SRC_BLEND_MASK;
535 value |= CURSOR_MODE_NORMAL;
536 value |= CURSOR_DST_BLEND_NEG_K1_TIMES_SRC;
537 value |= CURSOR_SRC_BLEND_K1_TIMES_SRC;
538 value |= CURSOR_ALPHA;
539 tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL);
540
541 /* position the cursor */
542 value = (crtc_y & 0x3fff) << 16 | (crtc_x & 0x3fff);
543 tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION);
544
545 /* apply changes */
546 tegra_dc_cursor_commit(dc);
547 tegra_dc_commit(dc);
548
549 return 0;
550}
551
552static int tegra_cursor_plane_disable(struct drm_plane *plane)
553{
554 struct tegra_dc *dc = to_tegra_dc(plane->crtc);
555 u32 value;
556
557 if (!plane->crtc)
558 return 0;
559
560 value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
561 value &= ~CURSOR_ENABLE;
562 tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
563
564 tegra_dc_cursor_commit(dc);
565 tegra_dc_commit(dc);
566
567 return 0;
568}
569
570static const struct drm_plane_funcs tegra_cursor_plane_funcs = {
571 .update_plane = tegra_cursor_plane_update,
572 .disable_plane = tegra_cursor_plane_disable,
573 .destroy = tegra_plane_destroy,
574};
575
576static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm,
577 struct tegra_dc *dc)
578{
579 struct tegra_plane *plane;
580 unsigned int num_formats;
581 const u32 *formats;
582 int err;
583
584 plane = kzalloc(sizeof(*plane), GFP_KERNEL);
585 if (!plane)
586 return ERR_PTR(-ENOMEM);
587
588 num_formats = ARRAY_SIZE(tegra_cursor_plane_formats);
589 formats = tegra_cursor_plane_formats;
590
591 err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe,
592 &tegra_cursor_plane_funcs, formats,
593 num_formats, DRM_PLANE_TYPE_CURSOR);
594 if (err < 0) {
595 kfree(plane);
596 return ERR_PTR(err);
597 }
598
599 return &plane->base;
600}
601
602static int tegra_overlay_plane_update(struct drm_plane *plane,
603 struct drm_crtc *crtc,
604 struct drm_framebuffer *fb, int crtc_x,
605 int crtc_y, unsigned int crtc_w,
606 unsigned int crtc_h, uint32_t src_x,
607 uint32_t src_y, uint32_t src_w,
608 uint32_t src_h)
f34bc787
TR
609{
610 struct tegra_plane *p = to_tegra_plane(plane);
611 struct tegra_dc *dc = to_tegra_dc(crtc);
612 struct tegra_dc_window window;
613 unsigned int i;
c134f019 614 int err;
f34bc787
TR
615
616 memset(&window, 0, sizeof(window));
617 window.src.x = src_x >> 16;
618 window.src.y = src_y >> 16;
619 window.src.w = src_w >> 16;
620 window.src.h = src_h >> 16;
621 window.dst.x = crtc_x;
622 window.dst.y = crtc_y;
623 window.dst.w = crtc_w;
624 window.dst.h = crtc_h;
f925390e 625 window.format = tegra_dc_format(fb->pixel_format, &window.swap);
f34bc787 626 window.bits_per_pixel = fb->bits_per_pixel;
db7fbdfd 627 window.bottom_up = tegra_fb_is_bottom_up(fb);
c134f019
TR
628
629 err = tegra_fb_get_tiling(fb, &window.tiling);
630 if (err < 0)
631 return err;
f34bc787
TR
632
633 for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) {
de2ba664 634 struct tegra_bo *bo = tegra_fb_get_plane(fb, i);
f34bc787 635
de2ba664 636 window.base[i] = bo->paddr + fb->offsets[i];
f34bc787
TR
637
638 /*
639 * Tegra doesn't support different strides for U and V planes
640 * so we display a warning if the user tries to display a
641 * framebuffer with such a configuration.
642 */
643 if (i >= 2) {
644 if (fb->pitches[i] != window.stride[1])
645 DRM_ERROR("unsupported UV-plane configuration\n");
646 } else {
647 window.stride[i] = fb->pitches[i];
648 }
649 }
650
651 return tegra_dc_setup_window(dc, p->index, &window);
652}
653
c7679306 654static void tegra_overlay_plane_destroy(struct drm_plane *plane)
f34bc787 655{
c7679306
TR
656 tegra_window_plane_disable(plane);
657 tegra_plane_destroy(plane);
f34bc787
TR
658}
659
c7679306
TR
660static const struct drm_plane_funcs tegra_overlay_plane_funcs = {
661 .update_plane = tegra_overlay_plane_update,
662 .disable_plane = tegra_window_plane_disable,
663 .destroy = tegra_overlay_plane_destroy,
f34bc787
TR
664};
665
c7679306 666static const uint32_t tegra_overlay_plane_formats[] = {
dbe4d9a7 667 DRM_FORMAT_XBGR8888,
f34bc787 668 DRM_FORMAT_XRGB8888,
dbe4d9a7 669 DRM_FORMAT_RGB565,
f34bc787 670 DRM_FORMAT_UYVY,
f925390e 671 DRM_FORMAT_YUYV,
f34bc787
TR
672 DRM_FORMAT_YUV420,
673 DRM_FORMAT_YUV422,
674};
675
c7679306
TR
676static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
677 struct tegra_dc *dc,
678 unsigned int index)
f34bc787 679{
c7679306
TR
680 struct tegra_plane *plane;
681 unsigned int num_formats;
682 const u32 *formats;
683 int err;
f34bc787 684
c7679306
TR
685 plane = kzalloc(sizeof(*plane), GFP_KERNEL);
686 if (!plane)
687 return ERR_PTR(-ENOMEM);
f34bc787 688
c7679306 689 plane->index = index;
f34bc787 690
c7679306
TR
691 num_formats = ARRAY_SIZE(tegra_overlay_plane_formats);
692 formats = tegra_overlay_plane_formats;
f34bc787 693
c7679306
TR
694 err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe,
695 &tegra_overlay_plane_funcs, formats,
696 num_formats, DRM_PLANE_TYPE_OVERLAY);
697 if (err < 0) {
698 kfree(plane);
699 return ERR_PTR(err);
700 }
701
702 return &plane->base;
703}
704
705static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc)
706{
707 struct drm_plane *plane;
708 unsigned int i;
709
710 for (i = 0; i < 2; i++) {
711 plane = tegra_dc_overlay_plane_create(drm, dc, 1 + i);
712 if (IS_ERR(plane))
713 return PTR_ERR(plane);
f34bc787
TR
714 }
715
716 return 0;
717}
718
23fb4740
TR
719static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
720 struct drm_framebuffer *fb)
721{
de2ba664 722 struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
db7fbdfd 723 unsigned int h_offset = 0, v_offset = 0;
c134f019 724 struct tegra_bo_tiling tiling;
93396d0f 725 unsigned long value, flags;
f925390e 726 unsigned int format, swap;
c134f019
TR
727 int err;
728
729 err = tegra_fb_get_tiling(fb, &tiling);
730 if (err < 0)
731 return err;
23fb4740 732
93396d0f
SP
733 spin_lock_irqsave(&dc->lock, flags);
734
23fb4740
TR
735 tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);
736
737 value = fb->offsets[0] + y * fb->pitches[0] +
738 x * fb->bits_per_pixel / 8;
739
de2ba664 740 tegra_dc_writel(dc, bo->paddr + value, DC_WINBUF_START_ADDR);
23fb4740 741 tegra_dc_writel(dc, fb->pitches[0], DC_WIN_LINE_STRIDE);
f925390e
TR
742
743 format = tegra_dc_format(fb->pixel_format, &swap);
ed683aea 744 tegra_dc_writel(dc, format, DC_WIN_COLOR_DEPTH);
f925390e 745 tegra_dc_writel(dc, swap, DC_WIN_BYTE_SWAP);
23fb4740 746
c134f019
TR
747 if (dc->soc->supports_block_linear) {
748 unsigned long height = tiling.value;
749
750 switch (tiling.mode) {
751 case TEGRA_BO_TILING_MODE_PITCH:
752 value = DC_WINBUF_SURFACE_KIND_PITCH;
753 break;
754
755 case TEGRA_BO_TILING_MODE_TILED:
756 value = DC_WINBUF_SURFACE_KIND_TILED;
757 break;
758
759 case TEGRA_BO_TILING_MODE_BLOCK:
760 value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(height) |
761 DC_WINBUF_SURFACE_KIND_BLOCK;
762 break;
763 }
764
765 tegra_dc_writel(dc, value, DC_WINBUF_SURFACE_KIND);
773af77f 766 } else {
c134f019
TR
767 switch (tiling.mode) {
768 case TEGRA_BO_TILING_MODE_PITCH:
769 value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV |
770 DC_WIN_BUFFER_ADDR_MODE_LINEAR;
771 break;
773af77f 772
c134f019
TR
773 case TEGRA_BO_TILING_MODE_TILED:
774 value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV |
775 DC_WIN_BUFFER_ADDR_MODE_TILE;
776 break;
777
778 case TEGRA_BO_TILING_MODE_BLOCK:
779 DRM_ERROR("hardware doesn't support block linear mode\n");
93396d0f 780 spin_unlock_irqrestore(&dc->lock, flags);
c134f019
TR
781 return -EINVAL;
782 }
783
784 tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE);
785 }
773af77f 786
db7fbdfd
TR
787 /* make sure bottom-up buffers are properly displayed */
788 if (tegra_fb_is_bottom_up(fb)) {
789 value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
eba66501 790 value |= V_DIRECTION;
db7fbdfd
TR
791 tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
792
793 v_offset += fb->height - 1;
794 } else {
795 value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
eba66501 796 value &= ~V_DIRECTION;
db7fbdfd
TR
797 tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
798 }
799
800 tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET);
801 tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET);
802
23fb4740 803 value = GENERAL_ACT_REQ | WIN_A_ACT_REQ;
205d48ed 804 tegra_dc_writel(dc, value << 8, DC_CMD_STATE_CONTROL);
23fb4740
TR
805 tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
806
93396d0f
SP
807 spin_unlock_irqrestore(&dc->lock, flags);
808
23fb4740
TR
809 return 0;
810}
811
6e5ff998
TR
812void tegra_dc_enable_vblank(struct tegra_dc *dc)
813{
814 unsigned long value, flags;
815
816 spin_lock_irqsave(&dc->lock, flags);
817
818 value = tegra_dc_readl(dc, DC_CMD_INT_MASK);
819 value |= VBLANK_INT;
820 tegra_dc_writel(dc, value, DC_CMD_INT_MASK);
821
822 spin_unlock_irqrestore(&dc->lock, flags);
823}
824
825void tegra_dc_disable_vblank(struct tegra_dc *dc)
826{
827 unsigned long value, flags;
828
829 spin_lock_irqsave(&dc->lock, flags);
830
831 value = tegra_dc_readl(dc, DC_CMD_INT_MASK);
832 value &= ~VBLANK_INT;
833 tegra_dc_writel(dc, value, DC_CMD_INT_MASK);
834
835 spin_unlock_irqrestore(&dc->lock, flags);
836}
837
3c03c46a
TR
838static void tegra_dc_finish_page_flip(struct tegra_dc *dc)
839{
840 struct drm_device *drm = dc->base.dev;
841 struct drm_crtc *crtc = &dc->base;
3c03c46a 842 unsigned long flags, base;
de2ba664 843 struct tegra_bo *bo;
3c03c46a 844
6b59cc1c
TR
845 spin_lock_irqsave(&drm->event_lock, flags);
846
847 if (!dc->event) {
848 spin_unlock_irqrestore(&drm->event_lock, flags);
3c03c46a 849 return;
6b59cc1c 850 }
3c03c46a 851
f4510a27 852 bo = tegra_fb_get_plane(crtc->primary->fb, 0);
3c03c46a 853
93396d0f
SP
854 spin_lock_irqsave(&dc->lock, flags);
855
3c03c46a 856 /* check if new start address has been latched */
93396d0f 857 tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);
3c03c46a
TR
858 tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS);
859 base = tegra_dc_readl(dc, DC_WINBUF_START_ADDR);
860 tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS);
861
93396d0f
SP
862 spin_unlock_irqrestore(&dc->lock, flags);
863
f4510a27 864 if (base == bo->paddr + crtc->primary->fb->offsets[0]) {
ed7dae58
TR
865 drm_crtc_send_vblank_event(crtc, dc->event);
866 drm_crtc_vblank_put(crtc);
3c03c46a 867 dc->event = NULL;
3c03c46a 868 }
6b59cc1c
TR
869
870 spin_unlock_irqrestore(&drm->event_lock, flags);
3c03c46a
TR
871}
872
873void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
874{
875 struct tegra_dc *dc = to_tegra_dc(crtc);
876 struct drm_device *drm = crtc->dev;
877 unsigned long flags;
878
879 spin_lock_irqsave(&drm->event_lock, flags);
880
881 if (dc->event && dc->event->base.file_priv == file) {
882 dc->event->base.destroy(&dc->event->base);
ed7dae58 883 drm_crtc_vblank_put(crtc);
3c03c46a
TR
884 dc->event = NULL;
885 }
886
887 spin_unlock_irqrestore(&drm->event_lock, flags);
888}
889
890static int tegra_dc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
a5b6f74e 891 struct drm_pending_vblank_event *event, uint32_t page_flip_flags)
3c03c46a 892{
ed7dae58 893 unsigned int pipe = drm_crtc_index(crtc);
3c03c46a 894 struct tegra_dc *dc = to_tegra_dc(crtc);
3c03c46a
TR
895
896 if (dc->event)
897 return -EBUSY;
898
899 if (event) {
ed7dae58 900 event->pipe = pipe;
3c03c46a 901 dc->event = event;
ed7dae58 902 drm_crtc_vblank_get(crtc);
3c03c46a
TR
903 }
904
905 tegra_dc_set_base(dc, 0, 0, fb);
f4510a27 906 crtc->primary->fb = fb;
3c03c46a
TR
907
908 return 0;
909}
910
f002abc1
TR
911static void tegra_dc_destroy(struct drm_crtc *crtc)
912{
913 drm_crtc_cleanup(crtc);
f002abc1
TR
914}
915
d8f4a9ed 916static const struct drm_crtc_funcs tegra_crtc_funcs = {
3c03c46a 917 .page_flip = tegra_dc_page_flip,
d8f4a9ed 918 .set_config = drm_crtc_helper_set_config,
f002abc1 919 .destroy = tegra_dc_destroy,
d8f4a9ed
TR
920};
921
f34bc787 922static void tegra_crtc_disable(struct drm_crtc *crtc)
d8f4a9ed 923{
f002abc1 924 struct tegra_dc *dc = to_tegra_dc(crtc);
f34bc787
TR
925 struct drm_device *drm = crtc->dev;
926 struct drm_plane *plane;
927
2b4c3661 928 drm_for_each_legacy_plane(plane, &drm->mode_config.plane_list) {
f34bc787 929 if (plane->crtc == crtc) {
c7679306 930 tegra_window_plane_disable(plane);
f34bc787
TR
931 plane->crtc = NULL;
932
933 if (plane->fb) {
934 drm_framebuffer_unreference(plane->fb);
935 plane->fb = NULL;
936 }
937 }
938 }
f002abc1 939
8ff64c17 940 drm_crtc_vblank_off(crtc);
c7679306 941 tegra_dc_commit(dc);
d8f4a9ed
TR
942}
943
944static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc,
945 const struct drm_display_mode *mode,
946 struct drm_display_mode *adjusted)
947{
948 return true;
949}
950
d8f4a9ed
TR
951static int tegra_dc_set_timings(struct tegra_dc *dc,
952 struct drm_display_mode *mode)
953{
0444c0ff
TR
954 unsigned int h_ref_to_sync = 1;
955 unsigned int v_ref_to_sync = 1;
d8f4a9ed
TR
956 unsigned long value;
957
958 tegra_dc_writel(dc, 0x0, DC_DISP_DISP_TIMING_OPTIONS);
959
960 value = (v_ref_to_sync << 16) | h_ref_to_sync;
961 tegra_dc_writel(dc, value, DC_DISP_REF_TO_SYNC);
962
963 value = ((mode->vsync_end - mode->vsync_start) << 16) |
964 ((mode->hsync_end - mode->hsync_start) << 0);
965 tegra_dc_writel(dc, value, DC_DISP_SYNC_WIDTH);
966
d8f4a9ed
TR
967 value = ((mode->vtotal - mode->vsync_end) << 16) |
968 ((mode->htotal - mode->hsync_end) << 0);
40495089
LS
969 tegra_dc_writel(dc, value, DC_DISP_BACK_PORCH);
970
971 value = ((mode->vsync_start - mode->vdisplay) << 16) |
972 ((mode->hsync_start - mode->hdisplay) << 0);
d8f4a9ed
TR
973 tegra_dc_writel(dc, value, DC_DISP_FRONT_PORCH);
974
975 value = (mode->vdisplay << 16) | mode->hdisplay;
976 tegra_dc_writel(dc, value, DC_DISP_ACTIVE);
977
978 return 0;
979}
980
981static int tegra_crtc_setup_clk(struct drm_crtc *crtc,
dbb3f2f7 982 struct drm_display_mode *mode)
d8f4a9ed 983{
91eded9b 984 unsigned long pclk = mode->clock * 1000;
d8f4a9ed
TR
985 struct tegra_dc *dc = to_tegra_dc(crtc);
986 struct tegra_output *output = NULL;
987 struct drm_encoder *encoder;
dbb3f2f7
TR
988 unsigned int div;
989 u32 value;
d8f4a9ed
TR
990 long err;
991
992 list_for_each_entry(encoder, &crtc->dev->mode_config.encoder_list, head)
993 if (encoder->crtc == crtc) {
994 output = encoder_to_output(encoder);
995 break;
996 }
997
998 if (!output)
999 return -ENODEV;
1000
1001 /*
91eded9b
TR
1002 * This assumes that the parent clock is pll_d_out0 or pll_d2_out
1003 * respectively, each of which divides the base pll_d by 2.
d8f4a9ed 1004 */
91eded9b 1005 err = tegra_output_setup_clock(output, dc->clk, pclk, &div);
d8f4a9ed
TR
1006 if (err < 0) {
1007 dev_err(dc->dev, "failed to setup clock: %ld\n", err);
1008 return err;
1009 }
1010
91eded9b 1011 DRM_DEBUG_KMS("rate: %lu, div: %u\n", clk_get_rate(dc->clk), div);
d8f4a9ed 1012
dbb3f2f7
TR
1013 value = SHIFT_CLK_DIVIDER(div) | PIXEL_CLK_DIVIDER_PCD1;
1014 tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL);
d8f4a9ed
TR
1015
1016 return 0;
1017}
1018
1019static int tegra_crtc_mode_set(struct drm_crtc *crtc,
1020 struct drm_display_mode *mode,
1021 struct drm_display_mode *adjusted,
1022 int x, int y, struct drm_framebuffer *old_fb)
1023{
f4510a27 1024 struct tegra_bo *bo = tegra_fb_get_plane(crtc->primary->fb, 0);
d8f4a9ed 1025 struct tegra_dc *dc = to_tegra_dc(crtc);
f34bc787 1026 struct tegra_dc_window window;
dbb3f2f7 1027 u32 value;
d8f4a9ed
TR
1028 int err;
1029
dbb3f2f7 1030 err = tegra_crtc_setup_clk(crtc, mode);
d8f4a9ed
TR
1031 if (err) {
1032 dev_err(dc->dev, "failed to setup clock for CRTC: %d\n", err);
1033 return err;
1034 }
1035
1036 /* program display mode */
1037 tegra_dc_set_timings(dc, mode);
1038
8620fc62
TR
1039 /* interlacing isn't supported yet, so disable it */
1040 if (dc->soc->supports_interlacing) {
1041 value = tegra_dc_readl(dc, DC_DISP_INTERLACE_CONTROL);
1042 value &= ~INTERLACE_ENABLE;
1043 tegra_dc_writel(dc, value, DC_DISP_INTERLACE_CONTROL);
1044 }
1045
d8f4a9ed 1046 /* setup window parameters */
f34bc787
TR
1047 memset(&window, 0, sizeof(window));
1048 window.src.x = 0;
1049 window.src.y = 0;
1050 window.src.w = mode->hdisplay;
1051 window.src.h = mode->vdisplay;
1052 window.dst.x = 0;
1053 window.dst.y = 0;
1054 window.dst.w = mode->hdisplay;
1055 window.dst.h = mode->vdisplay;
f925390e
TR
1056 window.format = tegra_dc_format(crtc->primary->fb->pixel_format,
1057 &window.swap);
f4510a27
MR
1058 window.bits_per_pixel = crtc->primary->fb->bits_per_pixel;
1059 window.stride[0] = crtc->primary->fb->pitches[0];
de2ba664 1060 window.base[0] = bo->paddr;
f34bc787
TR
1061
1062 err = tegra_dc_setup_window(dc, 0, &window);
1063 if (err < 0)
1064 dev_err(dc->dev, "failed to enable root plane\n");
d8f4a9ed 1065
d8f4a9ed
TR
1066 return 0;
1067}
d8f4a9ed 1068
23fb4740
TR
1069static int tegra_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
1070 struct drm_framebuffer *old_fb)
1071{
1072 struct tegra_dc *dc = to_tegra_dc(crtc);
d8f4a9ed 1073
f4510a27 1074 return tegra_dc_set_base(dc, x, y, crtc->primary->fb);
d8f4a9ed
TR
1075}
1076
1077static void tegra_crtc_prepare(struct drm_crtc *crtc)
1078{
1079 struct tegra_dc *dc = to_tegra_dc(crtc);
1080 unsigned int syncpt;
1081 unsigned long value;
1082
8ff64c17
TR
1083 drm_crtc_vblank_off(crtc);
1084
d8f4a9ed 1085 /* hardware initialization */
ca48080a 1086 reset_control_deassert(dc->rst);
d8f4a9ed
TR
1087 usleep_range(10000, 20000);
1088
1089 if (dc->pipe)
1090 syncpt = SYNCPT_VBLANK1;
1091 else
1092 syncpt = SYNCPT_VBLANK0;
1093
1094 /* initialize display controller */
1095 tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
1096 tegra_dc_writel(dc, 0x100 | syncpt, DC_CMD_CONT_SYNCPT_VSYNC);
1097
1098 value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | WIN_A_OF_INT;
1099 tegra_dc_writel(dc, value, DC_CMD_INT_TYPE);
1100
1101 value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
1102 WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT;
1103 tegra_dc_writel(dc, value, DC_CMD_INT_POLARITY);
1104
d8f4a9ed
TR
1105 /* initialize timer */
1106 value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) |
1107 WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20);
1108 tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY);
1109
1110 value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(1) |
1111 WINDOW_B_THRESHOLD(1) | WINDOW_C_THRESHOLD(1);
1112 tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER);
1113
d8f4a9ed
TR
1114 value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT;
1115 tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE);
6e5ff998
TR
1116
1117 value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT;
1118 tegra_dc_writel(dc, value, DC_CMD_INT_MASK);
d8f4a9ed
TR
1119}
1120
1121static void tegra_crtc_commit(struct drm_crtc *crtc)
1122{
1123 struct tegra_dc *dc = to_tegra_dc(crtc);
d8f4a9ed 1124
8ff64c17 1125 drm_crtc_vblank_on(crtc);
205d48ed 1126 tegra_dc_commit(dc);
d8f4a9ed
TR
1127}
1128
d8f4a9ed 1129static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = {
f34bc787 1130 .disable = tegra_crtc_disable,
d8f4a9ed
TR
1131 .mode_fixup = tegra_crtc_mode_fixup,
1132 .mode_set = tegra_crtc_mode_set,
23fb4740 1133 .mode_set_base = tegra_crtc_mode_set_base,
d8f4a9ed
TR
1134 .prepare = tegra_crtc_prepare,
1135 .commit = tegra_crtc_commit,
d8f4a9ed
TR
1136};
1137
6e5ff998 1138static irqreturn_t tegra_dc_irq(int irq, void *data)
d8f4a9ed
TR
1139{
1140 struct tegra_dc *dc = data;
1141 unsigned long status;
1142
1143 status = tegra_dc_readl(dc, DC_CMD_INT_STATUS);
1144 tegra_dc_writel(dc, status, DC_CMD_INT_STATUS);
1145
1146 if (status & FRAME_END_INT) {
1147 /*
1148 dev_dbg(dc->dev, "%s(): frame end\n", __func__);
1149 */
1150 }
1151
1152 if (status & VBLANK_INT) {
1153 /*
1154 dev_dbg(dc->dev, "%s(): vertical blank\n", __func__);
1155 */
ed7dae58 1156 drm_crtc_handle_vblank(&dc->base);
3c03c46a 1157 tegra_dc_finish_page_flip(dc);
d8f4a9ed
TR
1158 }
1159
1160 if (status & (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT)) {
1161 /*
1162 dev_dbg(dc->dev, "%s(): underflow\n", __func__);
1163 */
1164 }
1165
1166 return IRQ_HANDLED;
1167}
1168
1169static int tegra_dc_show_regs(struct seq_file *s, void *data)
1170{
1171 struct drm_info_node *node = s->private;
1172 struct tegra_dc *dc = node->info_ent->data;
1173
1174#define DUMP_REG(name) \
03a60569 1175 seq_printf(s, "%-40s %#05x %08x\n", #name, name, \
d8f4a9ed
TR
1176 tegra_dc_readl(dc, name))
1177
1178 DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT);
1179 DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
1180 DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT_ERROR);
1181 DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT);
1182 DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT_CNTRL);
1183 DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT_ERROR);
1184 DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT);
1185 DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT_CNTRL);
1186 DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT_ERROR);
1187 DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT);
1188 DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT_CNTRL);
1189 DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT_ERROR);
1190 DUMP_REG(DC_CMD_CONT_SYNCPT_VSYNC);
1191 DUMP_REG(DC_CMD_DISPLAY_COMMAND_OPTION0);
1192 DUMP_REG(DC_CMD_DISPLAY_COMMAND);
1193 DUMP_REG(DC_CMD_SIGNAL_RAISE);
1194 DUMP_REG(DC_CMD_DISPLAY_POWER_CONTROL);
1195 DUMP_REG(DC_CMD_INT_STATUS);
1196 DUMP_REG(DC_CMD_INT_MASK);
1197 DUMP_REG(DC_CMD_INT_ENABLE);
1198 DUMP_REG(DC_CMD_INT_TYPE);
1199 DUMP_REG(DC_CMD_INT_POLARITY);
1200 DUMP_REG(DC_CMD_SIGNAL_RAISE1);
1201 DUMP_REG(DC_CMD_SIGNAL_RAISE2);
1202 DUMP_REG(DC_CMD_SIGNAL_RAISE3);
1203 DUMP_REG(DC_CMD_STATE_ACCESS);
1204 DUMP_REG(DC_CMD_STATE_CONTROL);
1205 DUMP_REG(DC_CMD_DISPLAY_WINDOW_HEADER);
1206 DUMP_REG(DC_CMD_REG_ACT_CONTROL);
1207 DUMP_REG(DC_COM_CRC_CONTROL);
1208 DUMP_REG(DC_COM_CRC_CHECKSUM);
1209 DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(0));
1210 DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(1));
1211 DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(2));
1212 DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(3));
1213 DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(0));
1214 DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(1));
1215 DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(2));
1216 DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(3));
1217 DUMP_REG(DC_COM_PIN_OUTPUT_DATA(0));
1218 DUMP_REG(DC_COM_PIN_OUTPUT_DATA(1));
1219 DUMP_REG(DC_COM_PIN_OUTPUT_DATA(2));
1220 DUMP_REG(DC_COM_PIN_OUTPUT_DATA(3));
1221 DUMP_REG(DC_COM_PIN_INPUT_ENABLE(0));
1222 DUMP_REG(DC_COM_PIN_INPUT_ENABLE(1));
1223 DUMP_REG(DC_COM_PIN_INPUT_ENABLE(2));
1224 DUMP_REG(DC_COM_PIN_INPUT_ENABLE(3));
1225 DUMP_REG(DC_COM_PIN_INPUT_DATA(0));
1226 DUMP_REG(DC_COM_PIN_INPUT_DATA(1));
1227 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(0));
1228 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(1));
1229 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(2));
1230 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(3));
1231 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(4));
1232 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(5));
1233 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(6));
1234 DUMP_REG(DC_COM_PIN_MISC_CONTROL);
1235 DUMP_REG(DC_COM_PIN_PM0_CONTROL);
1236 DUMP_REG(DC_COM_PIN_PM0_DUTY_CYCLE);
1237 DUMP_REG(DC_COM_PIN_PM1_CONTROL);
1238 DUMP_REG(DC_COM_PIN_PM1_DUTY_CYCLE);
1239 DUMP_REG(DC_COM_SPI_CONTROL);
1240 DUMP_REG(DC_COM_SPI_START_BYTE);
1241 DUMP_REG(DC_COM_HSPI_WRITE_DATA_AB);
1242 DUMP_REG(DC_COM_HSPI_WRITE_DATA_CD);
1243 DUMP_REG(DC_COM_HSPI_CS_DC);
1244 DUMP_REG(DC_COM_SCRATCH_REGISTER_A);
1245 DUMP_REG(DC_COM_SCRATCH_REGISTER_B);
1246 DUMP_REG(DC_COM_GPIO_CTRL);
1247 DUMP_REG(DC_COM_GPIO_DEBOUNCE_COUNTER);
1248 DUMP_REG(DC_COM_CRC_CHECKSUM_LATCHED);
1249 DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS0);
1250 DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS1);
1251 DUMP_REG(DC_DISP_DISP_WIN_OPTIONS);
1252 DUMP_REG(DC_DISP_DISP_MEM_HIGH_PRIORITY);
1253 DUMP_REG(DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER);
1254 DUMP_REG(DC_DISP_DISP_TIMING_OPTIONS);
1255 DUMP_REG(DC_DISP_REF_TO_SYNC);
1256 DUMP_REG(DC_DISP_SYNC_WIDTH);
1257 DUMP_REG(DC_DISP_BACK_PORCH);
1258 DUMP_REG(DC_DISP_ACTIVE);
1259 DUMP_REG(DC_DISP_FRONT_PORCH);
1260 DUMP_REG(DC_DISP_H_PULSE0_CONTROL);
1261 DUMP_REG(DC_DISP_H_PULSE0_POSITION_A);
1262 DUMP_REG(DC_DISP_H_PULSE0_POSITION_B);
1263 DUMP_REG(DC_DISP_H_PULSE0_POSITION_C);
1264 DUMP_REG(DC_DISP_H_PULSE0_POSITION_D);
1265 DUMP_REG(DC_DISP_H_PULSE1_CONTROL);
1266 DUMP_REG(DC_DISP_H_PULSE1_POSITION_A);
1267 DUMP_REG(DC_DISP_H_PULSE1_POSITION_B);
1268 DUMP_REG(DC_DISP_H_PULSE1_POSITION_C);
1269 DUMP_REG(DC_DISP_H_PULSE1_POSITION_D);
1270 DUMP_REG(DC_DISP_H_PULSE2_CONTROL);
1271 DUMP_REG(DC_DISP_H_PULSE2_POSITION_A);
1272 DUMP_REG(DC_DISP_H_PULSE2_POSITION_B);
1273 DUMP_REG(DC_DISP_H_PULSE2_POSITION_C);
1274 DUMP_REG(DC_DISP_H_PULSE2_POSITION_D);
1275 DUMP_REG(DC_DISP_V_PULSE0_CONTROL);
1276 DUMP_REG(DC_DISP_V_PULSE0_POSITION_A);
1277 DUMP_REG(DC_DISP_V_PULSE0_POSITION_B);
1278 DUMP_REG(DC_DISP_V_PULSE0_POSITION_C);
1279 DUMP_REG(DC_DISP_V_PULSE1_CONTROL);
1280 DUMP_REG(DC_DISP_V_PULSE1_POSITION_A);
1281 DUMP_REG(DC_DISP_V_PULSE1_POSITION_B);
1282 DUMP_REG(DC_DISP_V_PULSE1_POSITION_C);
1283 DUMP_REG(DC_DISP_V_PULSE2_CONTROL);
1284 DUMP_REG(DC_DISP_V_PULSE2_POSITION_A);
1285 DUMP_REG(DC_DISP_V_PULSE3_CONTROL);
1286 DUMP_REG(DC_DISP_V_PULSE3_POSITION_A);
1287 DUMP_REG(DC_DISP_M0_CONTROL);
1288 DUMP_REG(DC_DISP_M1_CONTROL);
1289 DUMP_REG(DC_DISP_DI_CONTROL);
1290 DUMP_REG(DC_DISP_PP_CONTROL);
1291 DUMP_REG(DC_DISP_PP_SELECT_A);
1292 DUMP_REG(DC_DISP_PP_SELECT_B);
1293 DUMP_REG(DC_DISP_PP_SELECT_C);
1294 DUMP_REG(DC_DISP_PP_SELECT_D);
1295 DUMP_REG(DC_DISP_DISP_CLOCK_CONTROL);
1296 DUMP_REG(DC_DISP_DISP_INTERFACE_CONTROL);
1297 DUMP_REG(DC_DISP_DISP_COLOR_CONTROL);
1298 DUMP_REG(DC_DISP_SHIFT_CLOCK_OPTIONS);
1299 DUMP_REG(DC_DISP_DATA_ENABLE_OPTIONS);
1300 DUMP_REG(DC_DISP_SERIAL_INTERFACE_OPTIONS);
1301 DUMP_REG(DC_DISP_LCD_SPI_OPTIONS);
1302 DUMP_REG(DC_DISP_BORDER_COLOR);
1303 DUMP_REG(DC_DISP_COLOR_KEY0_LOWER);
1304 DUMP_REG(DC_DISP_COLOR_KEY0_UPPER);
1305 DUMP_REG(DC_DISP_COLOR_KEY1_LOWER);
1306 DUMP_REG(DC_DISP_COLOR_KEY1_UPPER);
1307 DUMP_REG(DC_DISP_CURSOR_FOREGROUND);
1308 DUMP_REG(DC_DISP_CURSOR_BACKGROUND);
1309 DUMP_REG(DC_DISP_CURSOR_START_ADDR);
1310 DUMP_REG(DC_DISP_CURSOR_START_ADDR_NS);
1311 DUMP_REG(DC_DISP_CURSOR_POSITION);
1312 DUMP_REG(DC_DISP_CURSOR_POSITION_NS);
1313 DUMP_REG(DC_DISP_INIT_SEQ_CONTROL);
1314 DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_A);
1315 DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_B);
1316 DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_C);
1317 DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_D);
1318 DUMP_REG(DC_DISP_DC_MCCIF_FIFOCTRL);
1319 DUMP_REG(DC_DISP_MCCIF_DISPLAY0A_HYST);
1320 DUMP_REG(DC_DISP_MCCIF_DISPLAY0B_HYST);
1321 DUMP_REG(DC_DISP_MCCIF_DISPLAY1A_HYST);
1322 DUMP_REG(DC_DISP_MCCIF_DISPLAY1B_HYST);
1323 DUMP_REG(DC_DISP_DAC_CRT_CTRL);
1324 DUMP_REG(DC_DISP_DISP_MISC_CONTROL);
1325 DUMP_REG(DC_DISP_SD_CONTROL);
1326 DUMP_REG(DC_DISP_SD_CSC_COEFF);
1327 DUMP_REG(DC_DISP_SD_LUT(0));
1328 DUMP_REG(DC_DISP_SD_LUT(1));
1329 DUMP_REG(DC_DISP_SD_LUT(2));
1330 DUMP_REG(DC_DISP_SD_LUT(3));
1331 DUMP_REG(DC_DISP_SD_LUT(4));
1332 DUMP_REG(DC_DISP_SD_LUT(5));
1333 DUMP_REG(DC_DISP_SD_LUT(6));
1334 DUMP_REG(DC_DISP_SD_LUT(7));
1335 DUMP_REG(DC_DISP_SD_LUT(8));
1336 DUMP_REG(DC_DISP_SD_FLICKER_CONTROL);
1337 DUMP_REG(DC_DISP_DC_PIXEL_COUNT);
1338 DUMP_REG(DC_DISP_SD_HISTOGRAM(0));
1339 DUMP_REG(DC_DISP_SD_HISTOGRAM(1));
1340 DUMP_REG(DC_DISP_SD_HISTOGRAM(2));
1341 DUMP_REG(DC_DISP_SD_HISTOGRAM(3));
1342 DUMP_REG(DC_DISP_SD_HISTOGRAM(4));
1343 DUMP_REG(DC_DISP_SD_HISTOGRAM(5));
1344 DUMP_REG(DC_DISP_SD_HISTOGRAM(6));
1345 DUMP_REG(DC_DISP_SD_HISTOGRAM(7));
1346 DUMP_REG(DC_DISP_SD_BL_TF(0));
1347 DUMP_REG(DC_DISP_SD_BL_TF(1));
1348 DUMP_REG(DC_DISP_SD_BL_TF(2));
1349 DUMP_REG(DC_DISP_SD_BL_TF(3));
1350 DUMP_REG(DC_DISP_SD_BL_CONTROL);
1351 DUMP_REG(DC_DISP_SD_HW_K_VALUES);
1352 DUMP_REG(DC_DISP_SD_MAN_K_VALUES);
e687651b
TR
1353 DUMP_REG(DC_DISP_CURSOR_START_ADDR_HI);
1354 DUMP_REG(DC_DISP_BLEND_CURSOR_CONTROL);
d8f4a9ed
TR
1355 DUMP_REG(DC_WIN_WIN_OPTIONS);
1356 DUMP_REG(DC_WIN_BYTE_SWAP);
1357 DUMP_REG(DC_WIN_BUFFER_CONTROL);
1358 DUMP_REG(DC_WIN_COLOR_DEPTH);
1359 DUMP_REG(DC_WIN_POSITION);
1360 DUMP_REG(DC_WIN_SIZE);
1361 DUMP_REG(DC_WIN_PRESCALED_SIZE);
1362 DUMP_REG(DC_WIN_H_INITIAL_DDA);
1363 DUMP_REG(DC_WIN_V_INITIAL_DDA);
1364 DUMP_REG(DC_WIN_DDA_INC);
1365 DUMP_REG(DC_WIN_LINE_STRIDE);
1366 DUMP_REG(DC_WIN_BUF_STRIDE);
1367 DUMP_REG(DC_WIN_UV_BUF_STRIDE);
1368 DUMP_REG(DC_WIN_BUFFER_ADDR_MODE);
1369 DUMP_REG(DC_WIN_DV_CONTROL);
1370 DUMP_REG(DC_WIN_BLEND_NOKEY);
1371 DUMP_REG(DC_WIN_BLEND_1WIN);
1372 DUMP_REG(DC_WIN_BLEND_2WIN_X);
1373 DUMP_REG(DC_WIN_BLEND_2WIN_Y);
f34bc787 1374 DUMP_REG(DC_WIN_BLEND_3WIN_XY);
d8f4a9ed
TR
1375 DUMP_REG(DC_WIN_HP_FETCH_CONTROL);
1376 DUMP_REG(DC_WINBUF_START_ADDR);
1377 DUMP_REG(DC_WINBUF_START_ADDR_NS);
1378 DUMP_REG(DC_WINBUF_START_ADDR_U);
1379 DUMP_REG(DC_WINBUF_START_ADDR_U_NS);
1380 DUMP_REG(DC_WINBUF_START_ADDR_V);
1381 DUMP_REG(DC_WINBUF_START_ADDR_V_NS);
1382 DUMP_REG(DC_WINBUF_ADDR_H_OFFSET);
1383 DUMP_REG(DC_WINBUF_ADDR_H_OFFSET_NS);
1384 DUMP_REG(DC_WINBUF_ADDR_V_OFFSET);
1385 DUMP_REG(DC_WINBUF_ADDR_V_OFFSET_NS);
1386 DUMP_REG(DC_WINBUF_UFLOW_STATUS);
1387 DUMP_REG(DC_WINBUF_AD_UFLOW_STATUS);
1388 DUMP_REG(DC_WINBUF_BD_UFLOW_STATUS);
1389 DUMP_REG(DC_WINBUF_CD_UFLOW_STATUS);
1390
1391#undef DUMP_REG
1392
1393 return 0;
1394}
1395
1396static struct drm_info_list debugfs_files[] = {
1397 { "regs", tegra_dc_show_regs, 0, NULL },
1398};
1399
1400static int tegra_dc_debugfs_init(struct tegra_dc *dc, struct drm_minor *minor)
1401{
1402 unsigned int i;
1403 char *name;
1404 int err;
1405
1406 name = kasprintf(GFP_KERNEL, "dc.%d", dc->pipe);
1407 dc->debugfs = debugfs_create_dir(name, minor->debugfs_root);
1408 kfree(name);
1409
1410 if (!dc->debugfs)
1411 return -ENOMEM;
1412
1413 dc->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files),
1414 GFP_KERNEL);
1415 if (!dc->debugfs_files) {
1416 err = -ENOMEM;
1417 goto remove;
1418 }
1419
1420 for (i = 0; i < ARRAY_SIZE(debugfs_files); i++)
1421 dc->debugfs_files[i].data = dc;
1422
1423 err = drm_debugfs_create_files(dc->debugfs_files,
1424 ARRAY_SIZE(debugfs_files),
1425 dc->debugfs, minor);
1426 if (err < 0)
1427 goto free;
1428
1429 dc->minor = minor;
1430
1431 return 0;
1432
1433free:
1434 kfree(dc->debugfs_files);
1435 dc->debugfs_files = NULL;
1436remove:
1437 debugfs_remove(dc->debugfs);
1438 dc->debugfs = NULL;
1439
1440 return err;
1441}
1442
1443static int tegra_dc_debugfs_exit(struct tegra_dc *dc)
1444{
1445 drm_debugfs_remove_files(dc->debugfs_files, ARRAY_SIZE(debugfs_files),
1446 dc->minor);
1447 dc->minor = NULL;
1448
1449 kfree(dc->debugfs_files);
1450 dc->debugfs_files = NULL;
1451
1452 debugfs_remove(dc->debugfs);
1453 dc->debugfs = NULL;
1454
1455 return 0;
1456}
1457
53fa7f72 1458static int tegra_dc_init(struct host1x_client *client)
d8f4a9ed 1459{
9910f5c4 1460 struct drm_device *drm = dev_get_drvdata(client->parent);
776dc384 1461 struct tegra_dc *dc = host1x_client_to_dc(client);
d1f3e1e0 1462 struct tegra_drm *tegra = drm->dev_private;
c7679306
TR
1463 struct drm_plane *primary = NULL;
1464 struct drm_plane *cursor = NULL;
d8f4a9ed
TR
1465 int err;
1466
df06b759
TR
1467 if (tegra->domain) {
1468 err = iommu_attach_device(tegra->domain, dc->dev);
1469 if (err < 0) {
1470 dev_err(dc->dev, "failed to attach to domain: %d\n",
1471 err);
1472 return err;
1473 }
1474
1475 dc->domain = tegra->domain;
1476 }
1477
c7679306
TR
1478 primary = tegra_dc_primary_plane_create(drm, dc);
1479 if (IS_ERR(primary)) {
1480 err = PTR_ERR(primary);
1481 goto cleanup;
1482 }
1483
1484 if (dc->soc->supports_cursor) {
1485 cursor = tegra_dc_cursor_plane_create(drm, dc);
1486 if (IS_ERR(cursor)) {
1487 err = PTR_ERR(cursor);
1488 goto cleanup;
1489 }
1490 }
1491
1492 err = drm_crtc_init_with_planes(drm, &dc->base, primary, cursor,
1493 &tegra_crtc_funcs);
1494 if (err < 0)
1495 goto cleanup;
1496
d8f4a9ed
TR
1497 drm_mode_crtc_set_gamma_size(&dc->base, 256);
1498 drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs);
1499
d1f3e1e0
TR
1500 /*
1501 * Keep track of the minimum pitch alignment across all display
1502 * controllers.
1503 */
1504 if (dc->soc->pitch_align > tegra->pitch_align)
1505 tegra->pitch_align = dc->soc->pitch_align;
1506
9910f5c4 1507 err = tegra_dc_rgb_init(drm, dc);
d8f4a9ed
TR
1508 if (err < 0 && err != -ENODEV) {
1509 dev_err(dc->dev, "failed to initialize RGB output: %d\n", err);
c7679306 1510 goto cleanup;
d8f4a9ed
TR
1511 }
1512
9910f5c4 1513 err = tegra_dc_add_planes(drm, dc);
f34bc787 1514 if (err < 0)
c7679306 1515 goto cleanup;
f34bc787 1516
d8f4a9ed 1517 if (IS_ENABLED(CONFIG_DEBUG_FS)) {
9910f5c4 1518 err = tegra_dc_debugfs_init(dc, drm->primary);
d8f4a9ed
TR
1519 if (err < 0)
1520 dev_err(dc->dev, "debugfs setup failed: %d\n", err);
1521 }
1522
6e5ff998 1523 err = devm_request_irq(dc->dev, dc->irq, tegra_dc_irq, 0,
d8f4a9ed
TR
1524 dev_name(dc->dev), dc);
1525 if (err < 0) {
1526 dev_err(dc->dev, "failed to request IRQ#%u: %d\n", dc->irq,
1527 err);
c7679306 1528 goto cleanup;
d8f4a9ed
TR
1529 }
1530
1531 return 0;
c7679306
TR
1532
1533cleanup:
1534 if (cursor)
1535 drm_plane_cleanup(cursor);
1536
1537 if (primary)
1538 drm_plane_cleanup(primary);
1539
1540 if (tegra->domain) {
1541 iommu_detach_device(tegra->domain, dc->dev);
1542 dc->domain = NULL;
1543 }
1544
1545 return err;
d8f4a9ed
TR
1546}
1547
53fa7f72 1548static int tegra_dc_exit(struct host1x_client *client)
d8f4a9ed 1549{
776dc384 1550 struct tegra_dc *dc = host1x_client_to_dc(client);
d8f4a9ed
TR
1551 int err;
1552
1553 devm_free_irq(dc->dev, dc->irq, dc);
1554
1555 if (IS_ENABLED(CONFIG_DEBUG_FS)) {
1556 err = tegra_dc_debugfs_exit(dc);
1557 if (err < 0)
1558 dev_err(dc->dev, "debugfs cleanup failed: %d\n", err);
1559 }
1560
1561 err = tegra_dc_rgb_exit(dc);
1562 if (err) {
1563 dev_err(dc->dev, "failed to shutdown RGB output: %d\n", err);
1564 return err;
1565 }
1566
df06b759
TR
1567 if (dc->domain) {
1568 iommu_detach_device(dc->domain, dc->dev);
1569 dc->domain = NULL;
1570 }
1571
d8f4a9ed
TR
1572 return 0;
1573}
1574
1575static const struct host1x_client_ops dc_client_ops = {
53fa7f72
TR
1576 .init = tegra_dc_init,
1577 .exit = tegra_dc_exit,
d8f4a9ed
TR
1578};
1579
8620fc62
TR
1580static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
1581 .supports_interlacing = false,
e687651b 1582 .supports_cursor = false,
c134f019 1583 .supports_block_linear = false,
d1f3e1e0 1584 .pitch_align = 8,
9c012700 1585 .has_powergate = false,
8620fc62
TR
1586};
1587
1588static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
1589 .supports_interlacing = false,
e687651b 1590 .supports_cursor = false,
c134f019 1591 .supports_block_linear = false,
d1f3e1e0 1592 .pitch_align = 8,
9c012700 1593 .has_powergate = false,
d1f3e1e0
TR
1594};
1595
1596static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
1597 .supports_interlacing = false,
1598 .supports_cursor = false,
1599 .supports_block_linear = false,
1600 .pitch_align = 64,
9c012700 1601 .has_powergate = true,
8620fc62
TR
1602};
1603
1604static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
1605 .supports_interlacing = true,
e687651b 1606 .supports_cursor = true,
c134f019 1607 .supports_block_linear = true,
d1f3e1e0 1608 .pitch_align = 64,
9c012700 1609 .has_powergate = true,
8620fc62
TR
1610};
1611
1612static const struct of_device_id tegra_dc_of_match[] = {
1613 {
1614 .compatible = "nvidia,tegra124-dc",
1615 .data = &tegra124_dc_soc_info,
9c012700
TR
1616 }, {
1617 .compatible = "nvidia,tegra114-dc",
1618 .data = &tegra114_dc_soc_info,
8620fc62
TR
1619 }, {
1620 .compatible = "nvidia,tegra30-dc",
1621 .data = &tegra30_dc_soc_info,
1622 }, {
1623 .compatible = "nvidia,tegra20-dc",
1624 .data = &tegra20_dc_soc_info,
1625 }, {
1626 /* sentinel */
1627 }
1628};
ef70728c 1629MODULE_DEVICE_TABLE(of, tegra_dc_of_match);
8620fc62 1630
13411ddd
TR
1631static int tegra_dc_parse_dt(struct tegra_dc *dc)
1632{
1633 struct device_node *np;
1634 u32 value = 0;
1635 int err;
1636
1637 err = of_property_read_u32(dc->dev->of_node, "nvidia,head", &value);
1638 if (err < 0) {
1639 dev_err(dc->dev, "missing \"nvidia,head\" property\n");
1640
1641 /*
1642 * If the nvidia,head property isn't present, try to find the
1643 * correct head number by looking up the position of this
1644 * display controller's node within the device tree. Assuming
1645 * that the nodes are ordered properly in the DTS file and
1646 * that the translation into a flattened device tree blob
1647 * preserves that ordering this will actually yield the right
1648 * head number.
1649 *
1650 * If those assumptions don't hold, this will still work for
1651 * cases where only a single display controller is used.
1652 */
1653 for_each_matching_node(np, tegra_dc_of_match) {
1654 if (np == dc->dev->of_node)
1655 break;
1656
1657 value++;
1658 }
1659 }
1660
1661 dc->pipe = value;
1662
1663 return 0;
1664}
1665
d8f4a9ed
TR
1666static int tegra_dc_probe(struct platform_device *pdev)
1667{
8620fc62 1668 const struct of_device_id *id;
d8f4a9ed
TR
1669 struct resource *regs;
1670 struct tegra_dc *dc;
1671 int err;
1672
1673 dc = devm_kzalloc(&pdev->dev, sizeof(*dc), GFP_KERNEL);
1674 if (!dc)
1675 return -ENOMEM;
1676
8620fc62
TR
1677 id = of_match_node(tegra_dc_of_match, pdev->dev.of_node);
1678 if (!id)
1679 return -ENODEV;
1680
6e5ff998 1681 spin_lock_init(&dc->lock);
d8f4a9ed
TR
1682 INIT_LIST_HEAD(&dc->list);
1683 dc->dev = &pdev->dev;
8620fc62 1684 dc->soc = id->data;
d8f4a9ed 1685
13411ddd
TR
1686 err = tegra_dc_parse_dt(dc);
1687 if (err < 0)
1688 return err;
1689
d8f4a9ed
TR
1690 dc->clk = devm_clk_get(&pdev->dev, NULL);
1691 if (IS_ERR(dc->clk)) {
1692 dev_err(&pdev->dev, "failed to get clock\n");
1693 return PTR_ERR(dc->clk);
1694 }
1695
ca48080a
SW
1696 dc->rst = devm_reset_control_get(&pdev->dev, "dc");
1697 if (IS_ERR(dc->rst)) {
1698 dev_err(&pdev->dev, "failed to get reset\n");
1699 return PTR_ERR(dc->rst);
1700 }
1701
9c012700
TR
1702 if (dc->soc->has_powergate) {
1703 if (dc->pipe == 0)
1704 dc->powergate = TEGRA_POWERGATE_DIS;
1705 else
1706 dc->powergate = TEGRA_POWERGATE_DISB;
1707
1708 err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk,
1709 dc->rst);
1710 if (err < 0) {
1711 dev_err(&pdev->dev, "failed to power partition: %d\n",
1712 err);
1713 return err;
1714 }
1715 } else {
1716 err = clk_prepare_enable(dc->clk);
1717 if (err < 0) {
1718 dev_err(&pdev->dev, "failed to enable clock: %d\n",
1719 err);
1720 return err;
1721 }
1722
1723 err = reset_control_deassert(dc->rst);
1724 if (err < 0) {
1725 dev_err(&pdev->dev, "failed to deassert reset: %d\n",
1726 err);
1727 return err;
1728 }
1729 }
d8f4a9ed
TR
1730
1731 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
d4ed6025
TR
1732 dc->regs = devm_ioremap_resource(&pdev->dev, regs);
1733 if (IS_ERR(dc->regs))
1734 return PTR_ERR(dc->regs);
d8f4a9ed
TR
1735
1736 dc->irq = platform_get_irq(pdev, 0);
1737 if (dc->irq < 0) {
1738 dev_err(&pdev->dev, "failed to get IRQ\n");
1739 return -ENXIO;
1740 }
1741
776dc384
TR
1742 INIT_LIST_HEAD(&dc->client.list);
1743 dc->client.ops = &dc_client_ops;
1744 dc->client.dev = &pdev->dev;
d8f4a9ed
TR
1745
1746 err = tegra_dc_rgb_probe(dc);
1747 if (err < 0 && err != -ENODEV) {
1748 dev_err(&pdev->dev, "failed to probe RGB output: %d\n", err);
1749 return err;
1750 }
1751
776dc384 1752 err = host1x_client_register(&dc->client);
d8f4a9ed
TR
1753 if (err < 0) {
1754 dev_err(&pdev->dev, "failed to register host1x client: %d\n",
1755 err);
1756 return err;
1757 }
1758
1759 platform_set_drvdata(pdev, dc);
1760
1761 return 0;
1762}
1763
1764static int tegra_dc_remove(struct platform_device *pdev)
1765{
d8f4a9ed
TR
1766 struct tegra_dc *dc = platform_get_drvdata(pdev);
1767 int err;
1768
776dc384 1769 err = host1x_client_unregister(&dc->client);
d8f4a9ed
TR
1770 if (err < 0) {
1771 dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
1772 err);
1773 return err;
1774 }
1775
59d29c0e
TR
1776 err = tegra_dc_rgb_remove(dc);
1777 if (err < 0) {
1778 dev_err(&pdev->dev, "failed to remove RGB output: %d\n", err);
1779 return err;
1780 }
1781
5482d75a 1782 reset_control_assert(dc->rst);
9c012700
TR
1783
1784 if (dc->soc->has_powergate)
1785 tegra_powergate_power_off(dc->powergate);
1786
d8f4a9ed
TR
1787 clk_disable_unprepare(dc->clk);
1788
1789 return 0;
1790}
1791
d8f4a9ed
TR
1792struct platform_driver tegra_dc_driver = {
1793 .driver = {
1794 .name = "tegra-dc",
1795 .owner = THIS_MODULE,
1796 .of_match_table = tegra_dc_of_match,
1797 },
1798 .probe = tegra_dc_probe,
1799 .remove = tegra_dc_remove,
1800};
This page took 0.204948 seconds and 5 git commands to generate.