blob: cdfa126a47257b3c72adbc09780f55755139676c [file] [log] [blame]
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001/*
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>
Thierry Reding9eb9b222013-09-24 16:32:47 +020011#include <linux/debugfs.h>
Stephen Warrenca480802013-11-06 16:20:54 -070012#include <linux/reset.h>
Thierry Redingd8f4a9e2012-11-15 21:28:22 +000013
Arto Merilainende2ba662013-03-22 16:34:08 +020014#include "dc.h"
15#include "drm.h"
16#include "gem.h"
Thierry Redingd8f4a9e2012-11-15 21:28:22 +000017
Daniel Vetter3cb9ae42014-10-29 10:03:57 +010018#include <drm/drm_plane_helper.h>
19
Thierry Reding8620fc62013-12-12 11:03:59 +010020struct tegra_dc_soc_info {
21 bool supports_interlacing;
Thierry Redinge6876512013-12-20 13:58:33 +010022 bool supports_cursor;
Thierry Redingc134f012014-06-03 14:48:12 +020023 bool supports_block_linear;
Thierry Redingd1f3e1e2014-07-11 08:29:14 +020024 unsigned int pitch_align;
Thierry Reding8620fc62013-12-12 11:03:59 +010025};
26
Thierry Redingf34bc782012-11-04 21:47:13 +010027struct tegra_plane {
28 struct drm_plane base;
29 unsigned int index;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +000030};
31
Thierry Redingf34bc782012-11-04 21:47:13 +010032static inline struct tegra_plane *to_tegra_plane(struct drm_plane *plane)
33{
34 return container_of(plane, struct tegra_plane, base);
35}
36
Thierry Reding10288ee2014-03-14 09:54:58 +010037static unsigned int tegra_dc_format(uint32_t format, uint32_t *swap)
38{
39 /* assume no swapping of fetched data */
40 if (swap)
41 *swap = BYTE_SWAP_NOSWAP;
42
43 switch (format) {
44 case DRM_FORMAT_XBGR8888:
45 return WIN_COLOR_DEPTH_R8G8B8A8;
46
47 case DRM_FORMAT_XRGB8888:
48 return WIN_COLOR_DEPTH_B8G8R8A8;
49
50 case DRM_FORMAT_RGB565:
51 return WIN_COLOR_DEPTH_B5G6R5;
52
53 case DRM_FORMAT_UYVY:
54 return WIN_COLOR_DEPTH_YCbCr422;
55
56 case DRM_FORMAT_YUYV:
57 if (swap)
58 *swap = BYTE_SWAP_SWAP2;
59
60 return WIN_COLOR_DEPTH_YCbCr422;
61
62 case DRM_FORMAT_YUV420:
63 return WIN_COLOR_DEPTH_YCbCr420P;
64
65 case DRM_FORMAT_YUV422:
66 return WIN_COLOR_DEPTH_YCbCr422P;
67
68 default:
69 break;
70 }
71
72 WARN(1, "unsupported pixel format %u, using default\n", format);
73 return WIN_COLOR_DEPTH_B8G8R8A8;
74}
75
76static bool tegra_dc_format_is_yuv(unsigned int format, bool *planar)
77{
78 switch (format) {
79 case WIN_COLOR_DEPTH_YCbCr422:
80 case WIN_COLOR_DEPTH_YUV422:
81 if (planar)
82 *planar = false;
83
84 return true;
85
86 case WIN_COLOR_DEPTH_YCbCr420P:
87 case WIN_COLOR_DEPTH_YUV420P:
88 case WIN_COLOR_DEPTH_YCbCr422P:
89 case WIN_COLOR_DEPTH_YUV422P:
90 case WIN_COLOR_DEPTH_YCbCr422R:
91 case WIN_COLOR_DEPTH_YUV422R:
92 case WIN_COLOR_DEPTH_YCbCr422RA:
93 case WIN_COLOR_DEPTH_YUV422RA:
94 if (planar)
95 *planar = true;
96
97 return true;
98 }
99
100 return false;
101}
102
103static inline u32 compute_dda_inc(unsigned int in, unsigned int out, bool v,
104 unsigned int bpp)
105{
106 fixed20_12 outf = dfixed_init(out);
107 fixed20_12 inf = dfixed_init(in);
108 u32 dda_inc;
109 int max;
110
111 if (v)
112 max = 15;
113 else {
114 switch (bpp) {
115 case 2:
116 max = 8;
117 break;
118
119 default:
120 WARN_ON_ONCE(1);
121 /* fallthrough */
122 case 4:
123 max = 4;
124 break;
125 }
126 }
127
128 outf.full = max_t(u32, outf.full - dfixed_const(1), dfixed_const(1));
129 inf.full -= dfixed_const(1);
130
131 dda_inc = dfixed_div(inf, outf);
132 dda_inc = min_t(u32, dda_inc, dfixed_const(max));
133
134 return dda_inc;
135}
136
137static inline u32 compute_initial_dda(unsigned int in)
138{
139 fixed20_12 inf = dfixed_init(in);
140 return dfixed_frac(inf);
141}
142
143static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
144 const struct tegra_dc_window *window)
145{
146 unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp;
147 unsigned long value;
148 bool yuv, planar;
149
150 /*
151 * For YUV planar modes, the number of bytes per pixel takes into
152 * account only the luma component and therefore is 1.
153 */
154 yuv = tegra_dc_format_is_yuv(window->format, &planar);
155 if (!yuv)
156 bpp = window->bits_per_pixel / 8;
157 else
158 bpp = planar ? 1 : 2;
159
160 value = WINDOW_A_SELECT << index;
161 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
162
163 tegra_dc_writel(dc, window->format, DC_WIN_COLOR_DEPTH);
164 tegra_dc_writel(dc, window->swap, DC_WIN_BYTE_SWAP);
165
166 value = V_POSITION(window->dst.y) | H_POSITION(window->dst.x);
167 tegra_dc_writel(dc, value, DC_WIN_POSITION);
168
169 value = V_SIZE(window->dst.h) | H_SIZE(window->dst.w);
170 tegra_dc_writel(dc, value, DC_WIN_SIZE);
171
172 h_offset = window->src.x * bpp;
173 v_offset = window->src.y;
174 h_size = window->src.w * bpp;
175 v_size = window->src.h;
176
177 value = V_PRESCALED_SIZE(v_size) | H_PRESCALED_SIZE(h_size);
178 tegra_dc_writel(dc, value, DC_WIN_PRESCALED_SIZE);
179
180 /*
181 * For DDA computations the number of bytes per pixel for YUV planar
182 * modes needs to take into account all Y, U and V components.
183 */
184 if (yuv && planar)
185 bpp = 2;
186
187 h_dda = compute_dda_inc(window->src.w, window->dst.w, false, bpp);
188 v_dda = compute_dda_inc(window->src.h, window->dst.h, true, bpp);
189
190 value = V_DDA_INC(v_dda) | H_DDA_INC(h_dda);
191 tegra_dc_writel(dc, value, DC_WIN_DDA_INC);
192
193 h_dda = compute_initial_dda(window->src.x);
194 v_dda = compute_initial_dda(window->src.y);
195
196 tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA);
197 tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA);
198
199 tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE);
200 tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE);
201
202 tegra_dc_writel(dc, window->base[0], DC_WINBUF_START_ADDR);
203
204 if (yuv && planar) {
205 tegra_dc_writel(dc, window->base[1], DC_WINBUF_START_ADDR_U);
206 tegra_dc_writel(dc, window->base[2], DC_WINBUF_START_ADDR_V);
207 value = window->stride[1] << 16 | window->stride[0];
208 tegra_dc_writel(dc, value, DC_WIN_LINE_STRIDE);
209 } else {
210 tegra_dc_writel(dc, window->stride[0], DC_WIN_LINE_STRIDE);
211 }
212
213 if (window->bottom_up)
214 v_offset += window->src.h - 1;
215
216 tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET);
217 tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET);
218
Thierry Redingc134f012014-06-03 14:48:12 +0200219 if (dc->soc->supports_block_linear) {
220 unsigned long height = window->tiling.value;
Thierry Reding10288ee2014-03-14 09:54:58 +0100221
Thierry Redingc134f012014-06-03 14:48:12 +0200222 switch (window->tiling.mode) {
223 case TEGRA_BO_TILING_MODE_PITCH:
224 value = DC_WINBUF_SURFACE_KIND_PITCH;
225 break;
226
227 case TEGRA_BO_TILING_MODE_TILED:
228 value = DC_WINBUF_SURFACE_KIND_TILED;
229 break;
230
231 case TEGRA_BO_TILING_MODE_BLOCK:
232 value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(height) |
233 DC_WINBUF_SURFACE_KIND_BLOCK;
234 break;
235 }
236
237 tegra_dc_writel(dc, value, DC_WINBUF_SURFACE_KIND);
238 } else {
239 switch (window->tiling.mode) {
240 case TEGRA_BO_TILING_MODE_PITCH:
241 value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV |
242 DC_WIN_BUFFER_ADDR_MODE_LINEAR;
243 break;
244
245 case TEGRA_BO_TILING_MODE_TILED:
246 value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV |
247 DC_WIN_BUFFER_ADDR_MODE_TILE;
248 break;
249
250 case TEGRA_BO_TILING_MODE_BLOCK:
251 DRM_ERROR("hardware doesn't support block linear mode\n");
252 return -EINVAL;
253 }
254
255 tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE);
256 }
Thierry Reding10288ee2014-03-14 09:54:58 +0100257
258 value = WIN_ENABLE;
259
260 if (yuv) {
261 /* setup default colorspace conversion coefficients */
262 tegra_dc_writel(dc, 0x00f0, DC_WIN_CSC_YOF);
263 tegra_dc_writel(dc, 0x012a, DC_WIN_CSC_KYRGB);
264 tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KUR);
265 tegra_dc_writel(dc, 0x0198, DC_WIN_CSC_KVR);
266 tegra_dc_writel(dc, 0x039b, DC_WIN_CSC_KUG);
267 tegra_dc_writel(dc, 0x032f, DC_WIN_CSC_KVG);
268 tegra_dc_writel(dc, 0x0204, DC_WIN_CSC_KUB);
269 tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KVB);
270
271 value |= CSC_ENABLE;
272 } else if (window->bits_per_pixel < 24) {
273 value |= COLOR_EXPAND;
274 }
275
276 if (window->bottom_up)
277 value |= V_DIRECTION;
278
279 tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
280
281 /*
282 * Disable blending and assume Window A is the bottom-most window,
283 * Window C is the top-most window and Window B is in the middle.
284 */
285 tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_NOKEY);
286 tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_1WIN);
287
288 switch (index) {
289 case 0:
290 tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_X);
291 tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y);
292 tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY);
293 break;
294
295 case 1:
296 tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X);
297 tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y);
298 tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY);
299 break;
300
301 case 2:
302 tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X);
303 tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_Y);
304 tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_3WIN_XY);
305 break;
306 }
307
308 tegra_dc_writel(dc, WIN_A_UPDATE << index, DC_CMD_STATE_CONTROL);
309 tegra_dc_writel(dc, WIN_A_ACT_REQ << index, DC_CMD_STATE_CONTROL);
310
311 return 0;
312}
313
Thierry Redingf34bc782012-11-04 21:47:13 +0100314static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
315 struct drm_framebuffer *fb, int crtc_x,
316 int crtc_y, unsigned int crtc_w,
317 unsigned int crtc_h, uint32_t src_x,
318 uint32_t src_y, uint32_t src_w, uint32_t src_h)
319{
320 struct tegra_plane *p = to_tegra_plane(plane);
321 struct tegra_dc *dc = to_tegra_dc(crtc);
322 struct tegra_dc_window window;
323 unsigned int i;
Thierry Redingc134f012014-06-03 14:48:12 +0200324 int err;
Thierry Redingf34bc782012-11-04 21:47:13 +0100325
326 memset(&window, 0, sizeof(window));
327 window.src.x = src_x >> 16;
328 window.src.y = src_y >> 16;
329 window.src.w = src_w >> 16;
330 window.src.h = src_h >> 16;
331 window.dst.x = crtc_x;
332 window.dst.y = crtc_y;
333 window.dst.w = crtc_w;
334 window.dst.h = crtc_h;
Thierry Redingf9253902014-01-29 20:31:17 +0100335 window.format = tegra_dc_format(fb->pixel_format, &window.swap);
Thierry Redingf34bc782012-11-04 21:47:13 +0100336 window.bits_per_pixel = fb->bits_per_pixel;
Thierry Redingdb7fbdf2013-10-07 09:47:58 +0200337 window.bottom_up = tegra_fb_is_bottom_up(fb);
Thierry Redingc134f012014-06-03 14:48:12 +0200338
339 err = tegra_fb_get_tiling(fb, &window.tiling);
340 if (err < 0)
341 return err;
Thierry Redingf34bc782012-11-04 21:47:13 +0100342
343 for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) {
Arto Merilainende2ba662013-03-22 16:34:08 +0200344 struct tegra_bo *bo = tegra_fb_get_plane(fb, i);
Thierry Redingf34bc782012-11-04 21:47:13 +0100345
Arto Merilainende2ba662013-03-22 16:34:08 +0200346 window.base[i] = bo->paddr + fb->offsets[i];
Thierry Redingf34bc782012-11-04 21:47:13 +0100347
348 /*
349 * Tegra doesn't support different strides for U and V planes
350 * so we display a warning if the user tries to display a
351 * framebuffer with such a configuration.
352 */
353 if (i >= 2) {
354 if (fb->pitches[i] != window.stride[1])
355 DRM_ERROR("unsupported UV-plane configuration\n");
356 } else {
357 window.stride[i] = fb->pitches[i];
358 }
359 }
360
361 return tegra_dc_setup_window(dc, p->index, &window);
362}
363
364static int tegra_plane_disable(struct drm_plane *plane)
365{
366 struct tegra_dc *dc = to_tegra_dc(plane->crtc);
367 struct tegra_plane *p = to_tegra_plane(plane);
368 unsigned long value;
369
Thierry Reding2678aeb2013-03-18 11:09:13 +0100370 if (!plane->crtc)
371 return 0;
372
Thierry Redingf34bc782012-11-04 21:47:13 +0100373 value = WINDOW_A_SELECT << p->index;
374 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
375
376 value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
377 value &= ~WIN_ENABLE;
378 tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
379
380 tegra_dc_writel(dc, WIN_A_UPDATE << p->index, DC_CMD_STATE_CONTROL);
381 tegra_dc_writel(dc, WIN_A_ACT_REQ << p->index, DC_CMD_STATE_CONTROL);
382
383 return 0;
384}
385
386static void tegra_plane_destroy(struct drm_plane *plane)
387{
Thierry Redingf002abc2013-10-14 14:06:02 +0200388 struct tegra_plane *p = to_tegra_plane(plane);
389
Thierry Redingf34bc782012-11-04 21:47:13 +0100390 tegra_plane_disable(plane);
391 drm_plane_cleanup(plane);
Thierry Redingf002abc2013-10-14 14:06:02 +0200392 kfree(p);
Thierry Redingf34bc782012-11-04 21:47:13 +0100393}
394
395static const struct drm_plane_funcs tegra_plane_funcs = {
396 .update_plane = tegra_plane_update,
397 .disable_plane = tegra_plane_disable,
398 .destroy = tegra_plane_destroy,
399};
400
401static const uint32_t plane_formats[] = {
Thierry Redingdbe4d9a2013-03-22 15:37:30 +0100402 DRM_FORMAT_XBGR8888,
Thierry Redingf34bc782012-11-04 21:47:13 +0100403 DRM_FORMAT_XRGB8888,
Thierry Redingdbe4d9a2013-03-22 15:37:30 +0100404 DRM_FORMAT_RGB565,
Thierry Redingf34bc782012-11-04 21:47:13 +0100405 DRM_FORMAT_UYVY,
Thierry Redingf9253902014-01-29 20:31:17 +0100406 DRM_FORMAT_YUYV,
Thierry Redingf34bc782012-11-04 21:47:13 +0100407 DRM_FORMAT_YUV420,
408 DRM_FORMAT_YUV422,
409};
410
411static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc)
412{
413 unsigned int i;
414 int err = 0;
415
416 for (i = 0; i < 2; i++) {
417 struct tegra_plane *plane;
418
Thierry Redingf002abc2013-10-14 14:06:02 +0200419 plane = kzalloc(sizeof(*plane), GFP_KERNEL);
Thierry Redingf34bc782012-11-04 21:47:13 +0100420 if (!plane)
421 return -ENOMEM;
422
423 plane->index = 1 + i;
424
425 err = drm_plane_init(drm, &plane->base, 1 << dc->pipe,
426 &tegra_plane_funcs, plane_formats,
427 ARRAY_SIZE(plane_formats), false);
Thierry Redingf002abc2013-10-14 14:06:02 +0200428 if (err < 0) {
429 kfree(plane);
Thierry Redingf34bc782012-11-04 21:47:13 +0100430 return err;
Thierry Redingf002abc2013-10-14 14:06:02 +0200431 }
Thierry Redingf34bc782012-11-04 21:47:13 +0100432 }
433
434 return 0;
435}
436
Thierry Reding23fb4742012-11-28 11:38:24 +0100437static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
438 struct drm_framebuffer *fb)
439{
Arto Merilainende2ba662013-03-22 16:34:08 +0200440 struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
Thierry Redingdb7fbdf2013-10-07 09:47:58 +0200441 unsigned int h_offset = 0, v_offset = 0;
Thierry Redingc134f012014-06-03 14:48:12 +0200442 struct tegra_bo_tiling tiling;
Thierry Redingf9253902014-01-29 20:31:17 +0100443 unsigned int format, swap;
Thierry Reding23fb4742012-11-28 11:38:24 +0100444 unsigned long value;
Thierry Redingc134f012014-06-03 14:48:12 +0200445 int err;
446
447 err = tegra_fb_get_tiling(fb, &tiling);
448 if (err < 0)
449 return err;
Thierry Reding23fb4742012-11-28 11:38:24 +0100450
451 tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);
452
453 value = fb->offsets[0] + y * fb->pitches[0] +
454 x * fb->bits_per_pixel / 8;
455
Arto Merilainende2ba662013-03-22 16:34:08 +0200456 tegra_dc_writel(dc, bo->paddr + value, DC_WINBUF_START_ADDR);
Thierry Reding23fb4742012-11-28 11:38:24 +0100457 tegra_dc_writel(dc, fb->pitches[0], DC_WIN_LINE_STRIDE);
Thierry Redingf9253902014-01-29 20:31:17 +0100458
459 format = tegra_dc_format(fb->pixel_format, &swap);
Thierry Redinged683ae2013-04-22 21:31:15 +0200460 tegra_dc_writel(dc, format, DC_WIN_COLOR_DEPTH);
Thierry Redingf9253902014-01-29 20:31:17 +0100461 tegra_dc_writel(dc, swap, DC_WIN_BYTE_SWAP);
Thierry Reding23fb4742012-11-28 11:38:24 +0100462
Thierry Redingc134f012014-06-03 14:48:12 +0200463 if (dc->soc->supports_block_linear) {
464 unsigned long height = tiling.value;
Thierry Reding773af772013-10-04 22:34:01 +0200465
Thierry Redingc134f012014-06-03 14:48:12 +0200466 switch (tiling.mode) {
467 case TEGRA_BO_TILING_MODE_PITCH:
468 value = DC_WINBUF_SURFACE_KIND_PITCH;
469 break;
470
471 case TEGRA_BO_TILING_MODE_TILED:
472 value = DC_WINBUF_SURFACE_KIND_TILED;
473 break;
474
475 case TEGRA_BO_TILING_MODE_BLOCK:
476 value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(height) |
477 DC_WINBUF_SURFACE_KIND_BLOCK;
478 break;
479 }
480
481 tegra_dc_writel(dc, value, DC_WINBUF_SURFACE_KIND);
482 } else {
483 switch (tiling.mode) {
484 case TEGRA_BO_TILING_MODE_PITCH:
485 value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV |
486 DC_WIN_BUFFER_ADDR_MODE_LINEAR;
487 break;
488
489 case TEGRA_BO_TILING_MODE_TILED:
490 value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV |
491 DC_WIN_BUFFER_ADDR_MODE_TILE;
492 break;
493
494 case TEGRA_BO_TILING_MODE_BLOCK:
495 DRM_ERROR("hardware doesn't support block linear mode\n");
496 return -EINVAL;
497 }
498
499 tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE);
500 }
Thierry Reding773af772013-10-04 22:34:01 +0200501
Thierry Redingdb7fbdf2013-10-07 09:47:58 +0200502 /* make sure bottom-up buffers are properly displayed */
503 if (tegra_fb_is_bottom_up(fb)) {
504 value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
Thierry Redingeba66502014-02-25 12:04:06 +0100505 value |= V_DIRECTION;
Thierry Redingdb7fbdf2013-10-07 09:47:58 +0200506 tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
507
508 v_offset += fb->height - 1;
509 } else {
510 value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
Thierry Redingeba66502014-02-25 12:04:06 +0100511 value &= ~V_DIRECTION;
Thierry Redingdb7fbdf2013-10-07 09:47:58 +0200512 tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
513 }
514
515 tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET);
516 tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET);
517
Thierry Reding23fb4742012-11-28 11:38:24 +0100518 value = GENERAL_UPDATE | WIN_A_UPDATE;
519 tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
520
521 value = GENERAL_ACT_REQ | WIN_A_ACT_REQ;
522 tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
523
524 return 0;
525}
526
Thierry Reding6e5ff992012-11-28 11:45:47 +0100527void tegra_dc_enable_vblank(struct tegra_dc *dc)
528{
529 unsigned long value, flags;
530
531 spin_lock_irqsave(&dc->lock, flags);
532
533 value = tegra_dc_readl(dc, DC_CMD_INT_MASK);
534 value |= VBLANK_INT;
535 tegra_dc_writel(dc, value, DC_CMD_INT_MASK);
536
537 spin_unlock_irqrestore(&dc->lock, flags);
538}
539
540void tegra_dc_disable_vblank(struct tegra_dc *dc)
541{
542 unsigned long value, flags;
543
544 spin_lock_irqsave(&dc->lock, flags);
545
546 value = tegra_dc_readl(dc, DC_CMD_INT_MASK);
547 value &= ~VBLANK_INT;
548 tegra_dc_writel(dc, value, DC_CMD_INT_MASK);
549
550 spin_unlock_irqrestore(&dc->lock, flags);
551}
552
Thierry Redinge6876512013-12-20 13:58:33 +0100553static int tegra_dc_cursor_set2(struct drm_crtc *crtc, struct drm_file *file,
554 uint32_t handle, uint32_t width,
555 uint32_t height, int32_t hot_x, int32_t hot_y)
556{
557 unsigned long value = CURSOR_CLIP_DISPLAY;
558 struct tegra_dc *dc = to_tegra_dc(crtc);
559 struct drm_gem_object *gem;
560 struct tegra_bo *bo = NULL;
561
562 if (!dc->soc->supports_cursor)
563 return -ENXIO;
564
565 if (width != height)
566 return -EINVAL;
567
568 switch (width) {
569 case 32:
570 value |= CURSOR_SIZE_32x32;
571 break;
572
573 case 64:
574 value |= CURSOR_SIZE_64x64;
575 break;
576
577 case 128:
578 value |= CURSOR_SIZE_128x128;
579
580 case 256:
581 value |= CURSOR_SIZE_256x256;
582 break;
583
584 default:
585 return -EINVAL;
586 }
587
588 if (handle) {
589 gem = drm_gem_object_lookup(crtc->dev, file, handle);
590 if (!gem)
591 return -ENOENT;
592
593 bo = to_tegra_bo(gem);
594 }
595
596 if (bo) {
597 unsigned long addr = (bo->paddr & 0xfffffc00) >> 10;
598#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
599 unsigned long high = (bo->paddr & 0xfffffffc) >> 32;
600#endif
601
602 tegra_dc_writel(dc, value | addr, DC_DISP_CURSOR_START_ADDR);
603
604#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
605 tegra_dc_writel(dc, high, DC_DISP_CURSOR_START_ADDR_HI);
606#endif
607
608 value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
609 value |= CURSOR_ENABLE;
610 tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
611
612 value = tegra_dc_readl(dc, DC_DISP_BLEND_CURSOR_CONTROL);
613 value &= ~CURSOR_DST_BLEND_MASK;
614 value &= ~CURSOR_SRC_BLEND_MASK;
615 value |= CURSOR_MODE_NORMAL;
616 value |= CURSOR_DST_BLEND_NEG_K1_TIMES_SRC;
617 value |= CURSOR_SRC_BLEND_K1_TIMES_SRC;
618 value |= CURSOR_ALPHA;
619 tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL);
620 } else {
621 value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
622 value &= ~CURSOR_ENABLE;
623 tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
624 }
625
626 tegra_dc_writel(dc, CURSOR_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
627 tegra_dc_writel(dc, CURSOR_ACT_REQ, DC_CMD_STATE_CONTROL);
628
629 tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
630 tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
631
632 return 0;
633}
634
635static int tegra_dc_cursor_move(struct drm_crtc *crtc, int x, int y)
636{
637 struct tegra_dc *dc = to_tegra_dc(crtc);
638 unsigned long value;
639
640 if (!dc->soc->supports_cursor)
641 return -ENXIO;
642
643 value = ((y & 0x3fff) << 16) | (x & 0x3fff);
644 tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION);
645
646 tegra_dc_writel(dc, CURSOR_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
647 tegra_dc_writel(dc, CURSOR_ACT_REQ, DC_CMD_STATE_CONTROL);
648
649 /* XXX: only required on generations earlier than Tegra124? */
650 tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
651 tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
652
653 return 0;
654}
655
Thierry Reding3c03c462012-11-28 12:00:18 +0100656static void tegra_dc_finish_page_flip(struct tegra_dc *dc)
657{
658 struct drm_device *drm = dc->base.dev;
659 struct drm_crtc *crtc = &dc->base;
Thierry Reding3c03c462012-11-28 12:00:18 +0100660 unsigned long flags, base;
Arto Merilainende2ba662013-03-22 16:34:08 +0200661 struct tegra_bo *bo;
Thierry Reding3c03c462012-11-28 12:00:18 +0100662
663 if (!dc->event)
664 return;
665
Matt Roperf4510a22014-04-01 15:22:40 -0700666 bo = tegra_fb_get_plane(crtc->primary->fb, 0);
Thierry Reding3c03c462012-11-28 12:00:18 +0100667
668 /* check if new start address has been latched */
669 tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS);
670 base = tegra_dc_readl(dc, DC_WINBUF_START_ADDR);
671 tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS);
672
Matt Roperf4510a22014-04-01 15:22:40 -0700673 if (base == bo->paddr + crtc->primary->fb->offsets[0]) {
Thierry Reding3c03c462012-11-28 12:00:18 +0100674 spin_lock_irqsave(&drm->event_lock, flags);
675 drm_send_vblank_event(drm, dc->pipe, dc->event);
676 drm_vblank_put(drm, dc->pipe);
677 dc->event = NULL;
678 spin_unlock_irqrestore(&drm->event_lock, flags);
679 }
680}
681
682void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
683{
684 struct tegra_dc *dc = to_tegra_dc(crtc);
685 struct drm_device *drm = crtc->dev;
686 unsigned long flags;
687
688 spin_lock_irqsave(&drm->event_lock, flags);
689
690 if (dc->event && dc->event->base.file_priv == file) {
691 dc->event->base.destroy(&dc->event->base);
692 drm_vblank_put(drm, dc->pipe);
693 dc->event = NULL;
694 }
695
696 spin_unlock_irqrestore(&drm->event_lock, flags);
697}
698
699static int tegra_dc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
Dave Airliea5b6f742013-09-02 09:47:56 +1000700 struct drm_pending_vblank_event *event, uint32_t page_flip_flags)
Thierry Reding3c03c462012-11-28 12:00:18 +0100701{
702 struct tegra_dc *dc = to_tegra_dc(crtc);
703 struct drm_device *drm = crtc->dev;
704
705 if (dc->event)
706 return -EBUSY;
707
708 if (event) {
709 event->pipe = dc->pipe;
710 dc->event = event;
711 drm_vblank_get(drm, dc->pipe);
712 }
713
714 tegra_dc_set_base(dc, 0, 0, fb);
Matt Roperf4510a22014-04-01 15:22:40 -0700715 crtc->primary->fb = fb;
Thierry Reding3c03c462012-11-28 12:00:18 +0100716
717 return 0;
718}
719
Thierry Redingf002abc2013-10-14 14:06:02 +0200720static void drm_crtc_clear(struct drm_crtc *crtc)
721{
722 memset(crtc, 0, sizeof(*crtc));
723}
724
725static void tegra_dc_destroy(struct drm_crtc *crtc)
726{
727 drm_crtc_cleanup(crtc);
728 drm_crtc_clear(crtc);
729}
730
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000731static const struct drm_crtc_funcs tegra_crtc_funcs = {
Thierry Redinge6876512013-12-20 13:58:33 +0100732 .cursor_set2 = tegra_dc_cursor_set2,
733 .cursor_move = tegra_dc_cursor_move,
Thierry Reding3c03c462012-11-28 12:00:18 +0100734 .page_flip = tegra_dc_page_flip,
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000735 .set_config = drm_crtc_helper_set_config,
Thierry Redingf002abc2013-10-14 14:06:02 +0200736 .destroy = tegra_dc_destroy,
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000737};
738
Thierry Redingf34bc782012-11-04 21:47:13 +0100739static void tegra_crtc_disable(struct drm_crtc *crtc)
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000740{
Thierry Redingf002abc2013-10-14 14:06:02 +0200741 struct tegra_dc *dc = to_tegra_dc(crtc);
Thierry Redingf34bc782012-11-04 21:47:13 +0100742 struct drm_device *drm = crtc->dev;
743 struct drm_plane *plane;
744
Daniel Vetter2b4c3662014-04-23 15:15:32 +0200745 drm_for_each_legacy_plane(plane, &drm->mode_config.plane_list) {
Thierry Redingf34bc782012-11-04 21:47:13 +0100746 if (plane->crtc == crtc) {
747 tegra_plane_disable(plane);
748 plane->crtc = NULL;
749
750 if (plane->fb) {
751 drm_framebuffer_unreference(plane->fb);
752 plane->fb = NULL;
753 }
754 }
755 }
Thierry Redingf002abc2013-10-14 14:06:02 +0200756
757 drm_vblank_off(drm, dc->pipe);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000758}
759
760static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc,
761 const struct drm_display_mode *mode,
762 struct drm_display_mode *adjusted)
763{
764 return true;
765}
766
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000767static int tegra_dc_set_timings(struct tegra_dc *dc,
768 struct drm_display_mode *mode)
769{
Thierry Reding0444c0f2014-04-16 09:22:38 +0200770 unsigned int h_ref_to_sync = 1;
771 unsigned int v_ref_to_sync = 1;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000772 unsigned long value;
773
774 tegra_dc_writel(dc, 0x0, DC_DISP_DISP_TIMING_OPTIONS);
775
776 value = (v_ref_to_sync << 16) | h_ref_to_sync;
777 tegra_dc_writel(dc, value, DC_DISP_REF_TO_SYNC);
778
779 value = ((mode->vsync_end - mode->vsync_start) << 16) |
780 ((mode->hsync_end - mode->hsync_start) << 0);
781 tegra_dc_writel(dc, value, DC_DISP_SYNC_WIDTH);
782
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000783 value = ((mode->vtotal - mode->vsync_end) << 16) |
784 ((mode->htotal - mode->hsync_end) << 0);
Lucas Stach40495082012-12-19 21:38:52 +0000785 tegra_dc_writel(dc, value, DC_DISP_BACK_PORCH);
786
787 value = ((mode->vsync_start - mode->vdisplay) << 16) |
788 ((mode->hsync_start - mode->hdisplay) << 0);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000789 tegra_dc_writel(dc, value, DC_DISP_FRONT_PORCH);
790
791 value = (mode->vdisplay << 16) | mode->hdisplay;
792 tegra_dc_writel(dc, value, DC_DISP_ACTIVE);
793
794 return 0;
795}
796
797static int tegra_crtc_setup_clk(struct drm_crtc *crtc,
Thierry Redingdbb3f2f2014-03-26 12:32:14 +0100798 struct drm_display_mode *mode)
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000799{
Thierry Reding91eded92014-03-26 13:32:21 +0100800 unsigned long pclk = mode->clock * 1000;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000801 struct tegra_dc *dc = to_tegra_dc(crtc);
802 struct tegra_output *output = NULL;
803 struct drm_encoder *encoder;
Thierry Redingdbb3f2f2014-03-26 12:32:14 +0100804 unsigned int div;
805 u32 value;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000806 long err;
807
808 list_for_each_entry(encoder, &crtc->dev->mode_config.encoder_list, head)
809 if (encoder->crtc == crtc) {
810 output = encoder_to_output(encoder);
811 break;
812 }
813
814 if (!output)
815 return -ENODEV;
816
817 /*
Thierry Reding91eded92014-03-26 13:32:21 +0100818 * This assumes that the parent clock is pll_d_out0 or pll_d2_out
819 * respectively, each of which divides the base pll_d by 2.
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000820 */
Thierry Reding91eded92014-03-26 13:32:21 +0100821 err = tegra_output_setup_clock(output, dc->clk, pclk, &div);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000822 if (err < 0) {
823 dev_err(dc->dev, "failed to setup clock: %ld\n", err);
824 return err;
825 }
826
Thierry Reding91eded92014-03-26 13:32:21 +0100827 DRM_DEBUG_KMS("rate: %lu, div: %u\n", clk_get_rate(dc->clk), div);
Thierry Redingdbb3f2f2014-03-26 12:32:14 +0100828
829 value = SHIFT_CLK_DIVIDER(div) | PIXEL_CLK_DIVIDER_PCD1;
830 tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000831
832 return 0;
833}
834
835static int tegra_crtc_mode_set(struct drm_crtc *crtc,
836 struct drm_display_mode *mode,
837 struct drm_display_mode *adjusted,
838 int x, int y, struct drm_framebuffer *old_fb)
839{
Matt Roperf4510a22014-04-01 15:22:40 -0700840 struct tegra_bo *bo = tegra_fb_get_plane(crtc->primary->fb, 0);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000841 struct tegra_dc *dc = to_tegra_dc(crtc);
Thierry Redingf34bc782012-11-04 21:47:13 +0100842 struct tegra_dc_window window;
Thierry Redingdbb3f2f2014-03-26 12:32:14 +0100843 u32 value;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000844 int err;
845
Thierry Reding6e5ff992012-11-28 11:45:47 +0100846 drm_vblank_pre_modeset(crtc->dev, dc->pipe);
847
Thierry Redingdbb3f2f2014-03-26 12:32:14 +0100848 err = tegra_crtc_setup_clk(crtc, mode);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000849 if (err) {
850 dev_err(dc->dev, "failed to setup clock for CRTC: %d\n", err);
851 return err;
852 }
853
854 /* program display mode */
855 tegra_dc_set_timings(dc, mode);
856
Thierry Reding8620fc62013-12-12 11:03:59 +0100857 /* interlacing isn't supported yet, so disable it */
858 if (dc->soc->supports_interlacing) {
859 value = tegra_dc_readl(dc, DC_DISP_INTERLACE_CONTROL);
860 value &= ~INTERLACE_ENABLE;
861 tegra_dc_writel(dc, value, DC_DISP_INTERLACE_CONTROL);
862 }
863
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000864 /* setup window parameters */
Thierry Redingf34bc782012-11-04 21:47:13 +0100865 memset(&window, 0, sizeof(window));
866 window.src.x = 0;
867 window.src.y = 0;
868 window.src.w = mode->hdisplay;
869 window.src.h = mode->vdisplay;
870 window.dst.x = 0;
871 window.dst.y = 0;
872 window.dst.w = mode->hdisplay;
873 window.dst.h = mode->vdisplay;
Thierry Redingf9253902014-01-29 20:31:17 +0100874 window.format = tegra_dc_format(crtc->primary->fb->pixel_format,
875 &window.swap);
Matt Roperf4510a22014-04-01 15:22:40 -0700876 window.bits_per_pixel = crtc->primary->fb->bits_per_pixel;
877 window.stride[0] = crtc->primary->fb->pitches[0];
Arto Merilainende2ba662013-03-22 16:34:08 +0200878 window.base[0] = bo->paddr;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000879
Thierry Redingf34bc782012-11-04 21:47:13 +0100880 err = tegra_dc_setup_window(dc, 0, &window);
881 if (err < 0)
882 dev_err(dc->dev, "failed to enable root plane\n");
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000883
884 return 0;
885}
886
Thierry Reding23fb4742012-11-28 11:38:24 +0100887static int tegra_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
888 struct drm_framebuffer *old_fb)
889{
890 struct tegra_dc *dc = to_tegra_dc(crtc);
891
Matt Roperf4510a22014-04-01 15:22:40 -0700892 return tegra_dc_set_base(dc, x, y, crtc->primary->fb);
Thierry Reding23fb4742012-11-28 11:38:24 +0100893}
894
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000895static void tegra_crtc_prepare(struct drm_crtc *crtc)
896{
897 struct tegra_dc *dc = to_tegra_dc(crtc);
898 unsigned int syncpt;
899 unsigned long value;
900
901 /* hardware initialization */
Stephen Warrenca480802013-11-06 16:20:54 -0700902 reset_control_deassert(dc->rst);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000903 usleep_range(10000, 20000);
904
905 if (dc->pipe)
906 syncpt = SYNCPT_VBLANK1;
907 else
908 syncpt = SYNCPT_VBLANK0;
909
910 /* initialize display controller */
911 tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
912 tegra_dc_writel(dc, 0x100 | syncpt, DC_CMD_CONT_SYNCPT_VSYNC);
913
914 value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | WIN_A_OF_INT;
915 tegra_dc_writel(dc, value, DC_CMD_INT_TYPE);
916
917 value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
918 WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT;
919 tegra_dc_writel(dc, value, DC_CMD_INT_POLARITY);
920
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000921 /* initialize timer */
922 value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) |
923 WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20);
924 tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY);
925
926 value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(1) |
927 WINDOW_B_THRESHOLD(1) | WINDOW_C_THRESHOLD(1);
928 tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER);
929
930 value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000931 tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE);
Thierry Reding6e5ff992012-11-28 11:45:47 +0100932
933 value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT;
934 tegra_dc_writel(dc, value, DC_CMD_INT_MASK);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000935}
936
937static void tegra_crtc_commit(struct drm_crtc *crtc)
938{
939 struct tegra_dc *dc = to_tegra_dc(crtc);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000940 unsigned long value;
941
Thierry Reding3b9e71e2013-01-15 12:21:36 +0100942 value = GENERAL_UPDATE | WIN_A_UPDATE;
943 tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000944
Thierry Reding3b9e71e2013-01-15 12:21:36 +0100945 value = GENERAL_ACT_REQ | WIN_A_ACT_REQ;
Thierry Reding6e5ff992012-11-28 11:45:47 +0100946 tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000947
Thierry Reding6e5ff992012-11-28 11:45:47 +0100948 drm_vblank_post_modeset(crtc->dev, dc->pipe);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000949}
950
951static void tegra_crtc_load_lut(struct drm_crtc *crtc)
952{
953}
954
955static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = {
Thierry Redingf34bc782012-11-04 21:47:13 +0100956 .disable = tegra_crtc_disable,
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000957 .mode_fixup = tegra_crtc_mode_fixup,
958 .mode_set = tegra_crtc_mode_set,
Thierry Reding23fb4742012-11-28 11:38:24 +0100959 .mode_set_base = tegra_crtc_mode_set_base,
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000960 .prepare = tegra_crtc_prepare,
961 .commit = tegra_crtc_commit,
962 .load_lut = tegra_crtc_load_lut,
963};
964
Thierry Reding6e5ff992012-11-28 11:45:47 +0100965static irqreturn_t tegra_dc_irq(int irq, void *data)
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000966{
967 struct tegra_dc *dc = data;
968 unsigned long status;
969
970 status = tegra_dc_readl(dc, DC_CMD_INT_STATUS);
971 tegra_dc_writel(dc, status, DC_CMD_INT_STATUS);
972
973 if (status & FRAME_END_INT) {
974 /*
975 dev_dbg(dc->dev, "%s(): frame end\n", __func__);
976 */
977 }
978
979 if (status & VBLANK_INT) {
980 /*
981 dev_dbg(dc->dev, "%s(): vertical blank\n", __func__);
982 */
983 drm_handle_vblank(dc->base.dev, dc->pipe);
Thierry Reding3c03c462012-11-28 12:00:18 +0100984 tegra_dc_finish_page_flip(dc);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000985 }
986
987 if (status & (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT)) {
988 /*
989 dev_dbg(dc->dev, "%s(): underflow\n", __func__);
990 */
991 }
992
993 return IRQ_HANDLED;
994}
995
996static int tegra_dc_show_regs(struct seq_file *s, void *data)
997{
998 struct drm_info_node *node = s->private;
999 struct tegra_dc *dc = node->info_ent->data;
1000
1001#define DUMP_REG(name) \
1002 seq_printf(s, "%-40s %#05x %08lx\n", #name, name, \
1003 tegra_dc_readl(dc, name))
1004
1005 DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT);
1006 DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
1007 DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT_ERROR);
1008 DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT);
1009 DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT_CNTRL);
1010 DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT_ERROR);
1011 DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT);
1012 DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT_CNTRL);
1013 DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT_ERROR);
1014 DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT);
1015 DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT_CNTRL);
1016 DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT_ERROR);
1017 DUMP_REG(DC_CMD_CONT_SYNCPT_VSYNC);
1018 DUMP_REG(DC_CMD_DISPLAY_COMMAND_OPTION0);
1019 DUMP_REG(DC_CMD_DISPLAY_COMMAND);
1020 DUMP_REG(DC_CMD_SIGNAL_RAISE);
1021 DUMP_REG(DC_CMD_DISPLAY_POWER_CONTROL);
1022 DUMP_REG(DC_CMD_INT_STATUS);
1023 DUMP_REG(DC_CMD_INT_MASK);
1024 DUMP_REG(DC_CMD_INT_ENABLE);
1025 DUMP_REG(DC_CMD_INT_TYPE);
1026 DUMP_REG(DC_CMD_INT_POLARITY);
1027 DUMP_REG(DC_CMD_SIGNAL_RAISE1);
1028 DUMP_REG(DC_CMD_SIGNAL_RAISE2);
1029 DUMP_REG(DC_CMD_SIGNAL_RAISE3);
1030 DUMP_REG(DC_CMD_STATE_ACCESS);
1031 DUMP_REG(DC_CMD_STATE_CONTROL);
1032 DUMP_REG(DC_CMD_DISPLAY_WINDOW_HEADER);
1033 DUMP_REG(DC_CMD_REG_ACT_CONTROL);
1034 DUMP_REG(DC_COM_CRC_CONTROL);
1035 DUMP_REG(DC_COM_CRC_CHECKSUM);
1036 DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(0));
1037 DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(1));
1038 DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(2));
1039 DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(3));
1040 DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(0));
1041 DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(1));
1042 DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(2));
1043 DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(3));
1044 DUMP_REG(DC_COM_PIN_OUTPUT_DATA(0));
1045 DUMP_REG(DC_COM_PIN_OUTPUT_DATA(1));
1046 DUMP_REG(DC_COM_PIN_OUTPUT_DATA(2));
1047 DUMP_REG(DC_COM_PIN_OUTPUT_DATA(3));
1048 DUMP_REG(DC_COM_PIN_INPUT_ENABLE(0));
1049 DUMP_REG(DC_COM_PIN_INPUT_ENABLE(1));
1050 DUMP_REG(DC_COM_PIN_INPUT_ENABLE(2));
1051 DUMP_REG(DC_COM_PIN_INPUT_ENABLE(3));
1052 DUMP_REG(DC_COM_PIN_INPUT_DATA(0));
1053 DUMP_REG(DC_COM_PIN_INPUT_DATA(1));
1054 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(0));
1055 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(1));
1056 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(2));
1057 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(3));
1058 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(4));
1059 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(5));
1060 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(6));
1061 DUMP_REG(DC_COM_PIN_MISC_CONTROL);
1062 DUMP_REG(DC_COM_PIN_PM0_CONTROL);
1063 DUMP_REG(DC_COM_PIN_PM0_DUTY_CYCLE);
1064 DUMP_REG(DC_COM_PIN_PM1_CONTROL);
1065 DUMP_REG(DC_COM_PIN_PM1_DUTY_CYCLE);
1066 DUMP_REG(DC_COM_SPI_CONTROL);
1067 DUMP_REG(DC_COM_SPI_START_BYTE);
1068 DUMP_REG(DC_COM_HSPI_WRITE_DATA_AB);
1069 DUMP_REG(DC_COM_HSPI_WRITE_DATA_CD);
1070 DUMP_REG(DC_COM_HSPI_CS_DC);
1071 DUMP_REG(DC_COM_SCRATCH_REGISTER_A);
1072 DUMP_REG(DC_COM_SCRATCH_REGISTER_B);
1073 DUMP_REG(DC_COM_GPIO_CTRL);
1074 DUMP_REG(DC_COM_GPIO_DEBOUNCE_COUNTER);
1075 DUMP_REG(DC_COM_CRC_CHECKSUM_LATCHED);
1076 DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS0);
1077 DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS1);
1078 DUMP_REG(DC_DISP_DISP_WIN_OPTIONS);
1079 DUMP_REG(DC_DISP_DISP_MEM_HIGH_PRIORITY);
1080 DUMP_REG(DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER);
1081 DUMP_REG(DC_DISP_DISP_TIMING_OPTIONS);
1082 DUMP_REG(DC_DISP_REF_TO_SYNC);
1083 DUMP_REG(DC_DISP_SYNC_WIDTH);
1084 DUMP_REG(DC_DISP_BACK_PORCH);
1085 DUMP_REG(DC_DISP_ACTIVE);
1086 DUMP_REG(DC_DISP_FRONT_PORCH);
1087 DUMP_REG(DC_DISP_H_PULSE0_CONTROL);
1088 DUMP_REG(DC_DISP_H_PULSE0_POSITION_A);
1089 DUMP_REG(DC_DISP_H_PULSE0_POSITION_B);
1090 DUMP_REG(DC_DISP_H_PULSE0_POSITION_C);
1091 DUMP_REG(DC_DISP_H_PULSE0_POSITION_D);
1092 DUMP_REG(DC_DISP_H_PULSE1_CONTROL);
1093 DUMP_REG(DC_DISP_H_PULSE1_POSITION_A);
1094 DUMP_REG(DC_DISP_H_PULSE1_POSITION_B);
1095 DUMP_REG(DC_DISP_H_PULSE1_POSITION_C);
1096 DUMP_REG(DC_DISP_H_PULSE1_POSITION_D);
1097 DUMP_REG(DC_DISP_H_PULSE2_CONTROL);
1098 DUMP_REG(DC_DISP_H_PULSE2_POSITION_A);
1099 DUMP_REG(DC_DISP_H_PULSE2_POSITION_B);
1100 DUMP_REG(DC_DISP_H_PULSE2_POSITION_C);
1101 DUMP_REG(DC_DISP_H_PULSE2_POSITION_D);
1102 DUMP_REG(DC_DISP_V_PULSE0_CONTROL);
1103 DUMP_REG(DC_DISP_V_PULSE0_POSITION_A);
1104 DUMP_REG(DC_DISP_V_PULSE0_POSITION_B);
1105 DUMP_REG(DC_DISP_V_PULSE0_POSITION_C);
1106 DUMP_REG(DC_DISP_V_PULSE1_CONTROL);
1107 DUMP_REG(DC_DISP_V_PULSE1_POSITION_A);
1108 DUMP_REG(DC_DISP_V_PULSE1_POSITION_B);
1109 DUMP_REG(DC_DISP_V_PULSE1_POSITION_C);
1110 DUMP_REG(DC_DISP_V_PULSE2_CONTROL);
1111 DUMP_REG(DC_DISP_V_PULSE2_POSITION_A);
1112 DUMP_REG(DC_DISP_V_PULSE3_CONTROL);
1113 DUMP_REG(DC_DISP_V_PULSE3_POSITION_A);
1114 DUMP_REG(DC_DISP_M0_CONTROL);
1115 DUMP_REG(DC_DISP_M1_CONTROL);
1116 DUMP_REG(DC_DISP_DI_CONTROL);
1117 DUMP_REG(DC_DISP_PP_CONTROL);
1118 DUMP_REG(DC_DISP_PP_SELECT_A);
1119 DUMP_REG(DC_DISP_PP_SELECT_B);
1120 DUMP_REG(DC_DISP_PP_SELECT_C);
1121 DUMP_REG(DC_DISP_PP_SELECT_D);
1122 DUMP_REG(DC_DISP_DISP_CLOCK_CONTROL);
1123 DUMP_REG(DC_DISP_DISP_INTERFACE_CONTROL);
1124 DUMP_REG(DC_DISP_DISP_COLOR_CONTROL);
1125 DUMP_REG(DC_DISP_SHIFT_CLOCK_OPTIONS);
1126 DUMP_REG(DC_DISP_DATA_ENABLE_OPTIONS);
1127 DUMP_REG(DC_DISP_SERIAL_INTERFACE_OPTIONS);
1128 DUMP_REG(DC_DISP_LCD_SPI_OPTIONS);
1129 DUMP_REG(DC_DISP_BORDER_COLOR);
1130 DUMP_REG(DC_DISP_COLOR_KEY0_LOWER);
1131 DUMP_REG(DC_DISP_COLOR_KEY0_UPPER);
1132 DUMP_REG(DC_DISP_COLOR_KEY1_LOWER);
1133 DUMP_REG(DC_DISP_COLOR_KEY1_UPPER);
1134 DUMP_REG(DC_DISP_CURSOR_FOREGROUND);
1135 DUMP_REG(DC_DISP_CURSOR_BACKGROUND);
1136 DUMP_REG(DC_DISP_CURSOR_START_ADDR);
1137 DUMP_REG(DC_DISP_CURSOR_START_ADDR_NS);
1138 DUMP_REG(DC_DISP_CURSOR_POSITION);
1139 DUMP_REG(DC_DISP_CURSOR_POSITION_NS);
1140 DUMP_REG(DC_DISP_INIT_SEQ_CONTROL);
1141 DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_A);
1142 DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_B);
1143 DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_C);
1144 DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_D);
1145 DUMP_REG(DC_DISP_DC_MCCIF_FIFOCTRL);
1146 DUMP_REG(DC_DISP_MCCIF_DISPLAY0A_HYST);
1147 DUMP_REG(DC_DISP_MCCIF_DISPLAY0B_HYST);
1148 DUMP_REG(DC_DISP_MCCIF_DISPLAY1A_HYST);
1149 DUMP_REG(DC_DISP_MCCIF_DISPLAY1B_HYST);
1150 DUMP_REG(DC_DISP_DAC_CRT_CTRL);
1151 DUMP_REG(DC_DISP_DISP_MISC_CONTROL);
1152 DUMP_REG(DC_DISP_SD_CONTROL);
1153 DUMP_REG(DC_DISP_SD_CSC_COEFF);
1154 DUMP_REG(DC_DISP_SD_LUT(0));
1155 DUMP_REG(DC_DISP_SD_LUT(1));
1156 DUMP_REG(DC_DISP_SD_LUT(2));
1157 DUMP_REG(DC_DISP_SD_LUT(3));
1158 DUMP_REG(DC_DISP_SD_LUT(4));
1159 DUMP_REG(DC_DISP_SD_LUT(5));
1160 DUMP_REG(DC_DISP_SD_LUT(6));
1161 DUMP_REG(DC_DISP_SD_LUT(7));
1162 DUMP_REG(DC_DISP_SD_LUT(8));
1163 DUMP_REG(DC_DISP_SD_FLICKER_CONTROL);
1164 DUMP_REG(DC_DISP_DC_PIXEL_COUNT);
1165 DUMP_REG(DC_DISP_SD_HISTOGRAM(0));
1166 DUMP_REG(DC_DISP_SD_HISTOGRAM(1));
1167 DUMP_REG(DC_DISP_SD_HISTOGRAM(2));
1168 DUMP_REG(DC_DISP_SD_HISTOGRAM(3));
1169 DUMP_REG(DC_DISP_SD_HISTOGRAM(4));
1170 DUMP_REG(DC_DISP_SD_HISTOGRAM(5));
1171 DUMP_REG(DC_DISP_SD_HISTOGRAM(6));
1172 DUMP_REG(DC_DISP_SD_HISTOGRAM(7));
1173 DUMP_REG(DC_DISP_SD_BL_TF(0));
1174 DUMP_REG(DC_DISP_SD_BL_TF(1));
1175 DUMP_REG(DC_DISP_SD_BL_TF(2));
1176 DUMP_REG(DC_DISP_SD_BL_TF(3));
1177 DUMP_REG(DC_DISP_SD_BL_CONTROL);
1178 DUMP_REG(DC_DISP_SD_HW_K_VALUES);
1179 DUMP_REG(DC_DISP_SD_MAN_K_VALUES);
Thierry Redinge6876512013-12-20 13:58:33 +01001180 DUMP_REG(DC_DISP_CURSOR_START_ADDR_HI);
1181 DUMP_REG(DC_DISP_BLEND_CURSOR_CONTROL);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001182 DUMP_REG(DC_WIN_WIN_OPTIONS);
1183 DUMP_REG(DC_WIN_BYTE_SWAP);
1184 DUMP_REG(DC_WIN_BUFFER_CONTROL);
1185 DUMP_REG(DC_WIN_COLOR_DEPTH);
1186 DUMP_REG(DC_WIN_POSITION);
1187 DUMP_REG(DC_WIN_SIZE);
1188 DUMP_REG(DC_WIN_PRESCALED_SIZE);
1189 DUMP_REG(DC_WIN_H_INITIAL_DDA);
1190 DUMP_REG(DC_WIN_V_INITIAL_DDA);
1191 DUMP_REG(DC_WIN_DDA_INC);
1192 DUMP_REG(DC_WIN_LINE_STRIDE);
1193 DUMP_REG(DC_WIN_BUF_STRIDE);
1194 DUMP_REG(DC_WIN_UV_BUF_STRIDE);
1195 DUMP_REG(DC_WIN_BUFFER_ADDR_MODE);
1196 DUMP_REG(DC_WIN_DV_CONTROL);
1197 DUMP_REG(DC_WIN_BLEND_NOKEY);
1198 DUMP_REG(DC_WIN_BLEND_1WIN);
1199 DUMP_REG(DC_WIN_BLEND_2WIN_X);
1200 DUMP_REG(DC_WIN_BLEND_2WIN_Y);
Thierry Redingf34bc782012-11-04 21:47:13 +01001201 DUMP_REG(DC_WIN_BLEND_3WIN_XY);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001202 DUMP_REG(DC_WIN_HP_FETCH_CONTROL);
1203 DUMP_REG(DC_WINBUF_START_ADDR);
1204 DUMP_REG(DC_WINBUF_START_ADDR_NS);
1205 DUMP_REG(DC_WINBUF_START_ADDR_U);
1206 DUMP_REG(DC_WINBUF_START_ADDR_U_NS);
1207 DUMP_REG(DC_WINBUF_START_ADDR_V);
1208 DUMP_REG(DC_WINBUF_START_ADDR_V_NS);
1209 DUMP_REG(DC_WINBUF_ADDR_H_OFFSET);
1210 DUMP_REG(DC_WINBUF_ADDR_H_OFFSET_NS);
1211 DUMP_REG(DC_WINBUF_ADDR_V_OFFSET);
1212 DUMP_REG(DC_WINBUF_ADDR_V_OFFSET_NS);
1213 DUMP_REG(DC_WINBUF_UFLOW_STATUS);
1214 DUMP_REG(DC_WINBUF_AD_UFLOW_STATUS);
1215 DUMP_REG(DC_WINBUF_BD_UFLOW_STATUS);
1216 DUMP_REG(DC_WINBUF_CD_UFLOW_STATUS);
1217
1218#undef DUMP_REG
1219
1220 return 0;
1221}
1222
1223static struct drm_info_list debugfs_files[] = {
1224 { "regs", tegra_dc_show_regs, 0, NULL },
1225};
1226
1227static int tegra_dc_debugfs_init(struct tegra_dc *dc, struct drm_minor *minor)
1228{
1229 unsigned int i;
1230 char *name;
1231 int err;
1232
1233 name = kasprintf(GFP_KERNEL, "dc.%d", dc->pipe);
1234 dc->debugfs = debugfs_create_dir(name, minor->debugfs_root);
1235 kfree(name);
1236
1237 if (!dc->debugfs)
1238 return -ENOMEM;
1239
1240 dc->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files),
1241 GFP_KERNEL);
1242 if (!dc->debugfs_files) {
1243 err = -ENOMEM;
1244 goto remove;
1245 }
1246
1247 for (i = 0; i < ARRAY_SIZE(debugfs_files); i++)
1248 dc->debugfs_files[i].data = dc;
1249
1250 err = drm_debugfs_create_files(dc->debugfs_files,
1251 ARRAY_SIZE(debugfs_files),
1252 dc->debugfs, minor);
1253 if (err < 0)
1254 goto free;
1255
1256 dc->minor = minor;
1257
1258 return 0;
1259
1260free:
1261 kfree(dc->debugfs_files);
1262 dc->debugfs_files = NULL;
1263remove:
1264 debugfs_remove(dc->debugfs);
1265 dc->debugfs = NULL;
1266
1267 return err;
1268}
1269
1270static int tegra_dc_debugfs_exit(struct tegra_dc *dc)
1271{
1272 drm_debugfs_remove_files(dc->debugfs_files, ARRAY_SIZE(debugfs_files),
1273 dc->minor);
1274 dc->minor = NULL;
1275
1276 kfree(dc->debugfs_files);
1277 dc->debugfs_files = NULL;
1278
1279 debugfs_remove(dc->debugfs);
1280 dc->debugfs = NULL;
1281
1282 return 0;
1283}
1284
Thierry Reding53fa7f72013-09-24 15:35:40 +02001285static int tegra_dc_init(struct host1x_client *client)
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001286{
Thierry Reding9910f5c2014-05-22 09:57:15 +02001287 struct drm_device *drm = dev_get_drvdata(client->parent);
Thierry Reding776dc382013-10-14 14:43:22 +02001288 struct tegra_dc *dc = host1x_client_to_dc(client);
Thierry Redingd1f3e1e2014-07-11 08:29:14 +02001289 struct tegra_drm *tegra = drm->dev_private;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001290 int err;
1291
Thierry Reding9910f5c2014-05-22 09:57:15 +02001292 drm_crtc_init(drm, &dc->base, &tegra_crtc_funcs);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001293 drm_mode_crtc_set_gamma_size(&dc->base, 256);
1294 drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs);
1295
Thierry Redingd1f3e1e2014-07-11 08:29:14 +02001296 /*
1297 * Keep track of the minimum pitch alignment across all display
1298 * controllers.
1299 */
1300 if (dc->soc->pitch_align > tegra->pitch_align)
1301 tegra->pitch_align = dc->soc->pitch_align;
1302
Thierry Reding9910f5c2014-05-22 09:57:15 +02001303 err = tegra_dc_rgb_init(drm, dc);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001304 if (err < 0 && err != -ENODEV) {
1305 dev_err(dc->dev, "failed to initialize RGB output: %d\n", err);
1306 return err;
1307 }
1308
Thierry Reding9910f5c2014-05-22 09:57:15 +02001309 err = tegra_dc_add_planes(drm, dc);
Thierry Redingf34bc782012-11-04 21:47:13 +01001310 if (err < 0)
1311 return err;
1312
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001313 if (IS_ENABLED(CONFIG_DEBUG_FS)) {
Thierry Reding9910f5c2014-05-22 09:57:15 +02001314 err = tegra_dc_debugfs_init(dc, drm->primary);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001315 if (err < 0)
1316 dev_err(dc->dev, "debugfs setup failed: %d\n", err);
1317 }
1318
Thierry Reding6e5ff992012-11-28 11:45:47 +01001319 err = devm_request_irq(dc->dev, dc->irq, tegra_dc_irq, 0,
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001320 dev_name(dc->dev), dc);
1321 if (err < 0) {
1322 dev_err(dc->dev, "failed to request IRQ#%u: %d\n", dc->irq,
1323 err);
1324 return err;
1325 }
1326
1327 return 0;
1328}
1329
Thierry Reding53fa7f72013-09-24 15:35:40 +02001330static int tegra_dc_exit(struct host1x_client *client)
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001331{
Thierry Reding776dc382013-10-14 14:43:22 +02001332 struct tegra_dc *dc = host1x_client_to_dc(client);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001333 int err;
1334
1335 devm_free_irq(dc->dev, dc->irq, dc);
1336
1337 if (IS_ENABLED(CONFIG_DEBUG_FS)) {
1338 err = tegra_dc_debugfs_exit(dc);
1339 if (err < 0)
1340 dev_err(dc->dev, "debugfs cleanup failed: %d\n", err);
1341 }
1342
1343 err = tegra_dc_rgb_exit(dc);
1344 if (err) {
1345 dev_err(dc->dev, "failed to shutdown RGB output: %d\n", err);
1346 return err;
1347 }
1348
1349 return 0;
1350}
1351
1352static const struct host1x_client_ops dc_client_ops = {
Thierry Reding53fa7f72013-09-24 15:35:40 +02001353 .init = tegra_dc_init,
1354 .exit = tegra_dc_exit,
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001355};
1356
Thierry Reding8620fc62013-12-12 11:03:59 +01001357static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
1358 .supports_interlacing = false,
Thierry Redinge6876512013-12-20 13:58:33 +01001359 .supports_cursor = false,
Thierry Redingc134f012014-06-03 14:48:12 +02001360 .supports_block_linear = false,
Thierry Redingd1f3e1e2014-07-11 08:29:14 +02001361 .pitch_align = 8,
Thierry Reding8620fc62013-12-12 11:03:59 +01001362};
1363
1364static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
1365 .supports_interlacing = false,
Thierry Redinge6876512013-12-20 13:58:33 +01001366 .supports_cursor = false,
Thierry Redingc134f012014-06-03 14:48:12 +02001367 .supports_block_linear = false,
Thierry Redingd1f3e1e2014-07-11 08:29:14 +02001368 .pitch_align = 8,
1369};
1370
1371static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
1372 .supports_interlacing = false,
1373 .supports_cursor = false,
1374 .supports_block_linear = false,
1375 .pitch_align = 64,
Thierry Reding8620fc62013-12-12 11:03:59 +01001376};
1377
1378static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
1379 .supports_interlacing = true,
Thierry Redinge6876512013-12-20 13:58:33 +01001380 .supports_cursor = true,
Thierry Redingc134f012014-06-03 14:48:12 +02001381 .supports_block_linear = true,
Thierry Redingd1f3e1e2014-07-11 08:29:14 +02001382 .pitch_align = 64,
Thierry Reding8620fc62013-12-12 11:03:59 +01001383};
1384
1385static const struct of_device_id tegra_dc_of_match[] = {
1386 {
1387 .compatible = "nvidia,tegra124-dc",
1388 .data = &tegra124_dc_soc_info,
1389 }, {
1390 .compatible = "nvidia,tegra30-dc",
1391 .data = &tegra30_dc_soc_info,
1392 }, {
1393 .compatible = "nvidia,tegra20-dc",
1394 .data = &tegra20_dc_soc_info,
1395 }, {
1396 /* sentinel */
1397 }
1398};
Stephen Warrenef707282014-06-18 16:21:55 -06001399MODULE_DEVICE_TABLE(of, tegra_dc_of_match);
Thierry Reding8620fc62013-12-12 11:03:59 +01001400
Thierry Reding13411dd2014-01-09 17:08:36 +01001401static int tegra_dc_parse_dt(struct tegra_dc *dc)
1402{
1403 struct device_node *np;
1404 u32 value = 0;
1405 int err;
1406
1407 err = of_property_read_u32(dc->dev->of_node, "nvidia,head", &value);
1408 if (err < 0) {
1409 dev_err(dc->dev, "missing \"nvidia,head\" property\n");
1410
1411 /*
1412 * If the nvidia,head property isn't present, try to find the
1413 * correct head number by looking up the position of this
1414 * display controller's node within the device tree. Assuming
1415 * that the nodes are ordered properly in the DTS file and
1416 * that the translation into a flattened device tree blob
1417 * preserves that ordering this will actually yield the right
1418 * head number.
1419 *
1420 * If those assumptions don't hold, this will still work for
1421 * cases where only a single display controller is used.
1422 */
1423 for_each_matching_node(np, tegra_dc_of_match) {
1424 if (np == dc->dev->of_node)
1425 break;
1426
1427 value++;
1428 }
1429 }
1430
1431 dc->pipe = value;
1432
1433 return 0;
1434}
1435
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001436static int tegra_dc_probe(struct platform_device *pdev)
1437{
Thierry Reding8620fc62013-12-12 11:03:59 +01001438 const struct of_device_id *id;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001439 struct resource *regs;
1440 struct tegra_dc *dc;
1441 int err;
1442
1443 dc = devm_kzalloc(&pdev->dev, sizeof(*dc), GFP_KERNEL);
1444 if (!dc)
1445 return -ENOMEM;
1446
Thierry Reding8620fc62013-12-12 11:03:59 +01001447 id = of_match_node(tegra_dc_of_match, pdev->dev.of_node);
1448 if (!id)
1449 return -ENODEV;
1450
Thierry Reding6e5ff992012-11-28 11:45:47 +01001451 spin_lock_init(&dc->lock);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001452 INIT_LIST_HEAD(&dc->list);
1453 dc->dev = &pdev->dev;
Thierry Reding8620fc62013-12-12 11:03:59 +01001454 dc->soc = id->data;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001455
Thierry Reding13411dd2014-01-09 17:08:36 +01001456 err = tegra_dc_parse_dt(dc);
1457 if (err < 0)
1458 return err;
1459
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001460 dc->clk = devm_clk_get(&pdev->dev, NULL);
1461 if (IS_ERR(dc->clk)) {
1462 dev_err(&pdev->dev, "failed to get clock\n");
1463 return PTR_ERR(dc->clk);
1464 }
1465
Stephen Warrenca480802013-11-06 16:20:54 -07001466 dc->rst = devm_reset_control_get(&pdev->dev, "dc");
1467 if (IS_ERR(dc->rst)) {
1468 dev_err(&pdev->dev, "failed to get reset\n");
1469 return PTR_ERR(dc->rst);
1470 }
1471
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001472 err = clk_prepare_enable(dc->clk);
1473 if (err < 0)
1474 return err;
1475
1476 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Thierry Redingd4ed6022013-01-21 11:09:02 +01001477 dc->regs = devm_ioremap_resource(&pdev->dev, regs);
1478 if (IS_ERR(dc->regs))
1479 return PTR_ERR(dc->regs);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001480
1481 dc->irq = platform_get_irq(pdev, 0);
1482 if (dc->irq < 0) {
1483 dev_err(&pdev->dev, "failed to get IRQ\n");
1484 return -ENXIO;
1485 }
1486
Thierry Reding776dc382013-10-14 14:43:22 +02001487 INIT_LIST_HEAD(&dc->client.list);
1488 dc->client.ops = &dc_client_ops;
1489 dc->client.dev = &pdev->dev;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001490
1491 err = tegra_dc_rgb_probe(dc);
1492 if (err < 0 && err != -ENODEV) {
1493 dev_err(&pdev->dev, "failed to probe RGB output: %d\n", err);
1494 return err;
1495 }
1496
Thierry Reding776dc382013-10-14 14:43:22 +02001497 err = host1x_client_register(&dc->client);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001498 if (err < 0) {
1499 dev_err(&pdev->dev, "failed to register host1x client: %d\n",
1500 err);
1501 return err;
1502 }
1503
1504 platform_set_drvdata(pdev, dc);
1505
1506 return 0;
1507}
1508
1509static int tegra_dc_remove(struct platform_device *pdev)
1510{
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001511 struct tegra_dc *dc = platform_get_drvdata(pdev);
1512 int err;
1513
Thierry Reding776dc382013-10-14 14:43:22 +02001514 err = host1x_client_unregister(&dc->client);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001515 if (err < 0) {
1516 dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
1517 err);
1518 return err;
1519 }
1520
Thierry Reding59d29c02013-10-14 14:26:42 +02001521 err = tegra_dc_rgb_remove(dc);
1522 if (err < 0) {
1523 dev_err(&pdev->dev, "failed to remove RGB output: %d\n", err);
1524 return err;
1525 }
1526
Thierry Reding5482d752014-07-11 08:39:03 +02001527 reset_control_assert(dc->rst);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001528 clk_disable_unprepare(dc->clk);
1529
1530 return 0;
1531}
1532
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001533struct platform_driver tegra_dc_driver = {
1534 .driver = {
1535 .name = "tegra-dc",
1536 .owner = THIS_MODULE,
1537 .of_match_table = tegra_dc_of_match,
1538 },
1539 .probe = tegra_dc_probe,
1540 .remove = tegra_dc_remove,
1541};