blob: 4073a7b5bf262b162f6dfd9f5a06132dfdadac88 [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>
Thierry Redingdf06b752014-06-26 21:41:53 +020012#include <linux/iommu.h>
Stephen Warrenca480802013-11-06 16:20:54 -070013#include <linux/reset.h>
Thierry Redingd8f4a9e2012-11-15 21:28:22 +000014
Thierry Reding9c012702014-07-07 15:32:53 +020015#include <soc/tegra/pmc.h>
16
Arto Merilainende2ba662013-03-22 16:34:08 +020017#include "dc.h"
18#include "drm.h"
19#include "gem.h"
Thierry Redingd8f4a9e2012-11-15 21:28:22 +000020
Thierry Reding9d441892014-11-24 17:02:53 +010021#include <drm/drm_atomic.h>
Thierry Reding4aa3df72014-11-24 16:27:13 +010022#include <drm/drm_atomic_helper.h>
Daniel Vetter3cb9ae42014-10-29 10:03:57 +010023#include <drm/drm_plane_helper.h>
24
Thierry Reding8620fc62013-12-12 11:03:59 +010025struct tegra_dc_soc_info {
Thierry Reding42d06592014-12-08 15:45:39 +010026 bool supports_border_color;
Thierry Reding8620fc62013-12-12 11:03:59 +010027 bool supports_interlacing;
Thierry Redinge6876512013-12-20 13:58:33 +010028 bool supports_cursor;
Thierry Redingc134f012014-06-03 14:48:12 +020029 bool supports_block_linear;
Thierry Redingd1f3e1e2014-07-11 08:29:14 +020030 unsigned int pitch_align;
Thierry Reding9c012702014-07-07 15:32:53 +020031 bool has_powergate;
Thierry Reding8620fc62013-12-12 11:03:59 +010032};
33
Thierry Redingf34bc782012-11-04 21:47:13 +010034struct tegra_plane {
35 struct drm_plane base;
36 unsigned int index;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +000037};
38
Thierry Redingf34bc782012-11-04 21:47:13 +010039static inline struct tegra_plane *to_tegra_plane(struct drm_plane *plane)
40{
41 return container_of(plane, struct tegra_plane, base);
42}
43
Thierry Redingca915b12014-12-08 16:14:45 +010044struct tegra_dc_state {
45 struct drm_crtc_state base;
46
47 struct clk *clk;
48 unsigned long pclk;
49 unsigned int div;
Thierry Reding47802b02014-11-26 12:28:39 +010050
51 u32 planes;
Thierry Redingca915b12014-12-08 16:14:45 +010052};
53
54static inline struct tegra_dc_state *to_dc_state(struct drm_crtc_state *state)
55{
56 if (state)
57 return container_of(state, struct tegra_dc_state, base);
58
59 return NULL;
60}
61
Thierry Redingd700ba72014-12-08 15:50:04 +010062/*
Thierry Reding86df2562014-12-08 16:03:53 +010063 * Reads the active copy of a register. This takes the dc->lock spinlock to
64 * prevent races with the VBLANK processing which also needs access to the
65 * active copy of some registers.
66 */
67static u32 tegra_dc_readl_active(struct tegra_dc *dc, unsigned long offset)
68{
69 unsigned long flags;
70 u32 value;
71
72 spin_lock_irqsave(&dc->lock, flags);
73
74 tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS);
75 value = tegra_dc_readl(dc, offset);
76 tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS);
77
78 spin_unlock_irqrestore(&dc->lock, flags);
79 return value;
80}
81
82/*
Thierry Redingd700ba72014-12-08 15:50:04 +010083 * Double-buffered registers have two copies: ASSEMBLY and ACTIVE. When the
84 * *_ACT_REQ bits are set the ASSEMBLY copy is latched into the ACTIVE copy.
85 * Latching happens mmediately if the display controller is in STOP mode or
86 * on the next frame boundary otherwise.
87 *
88 * Triple-buffered registers have three copies: ASSEMBLY, ARM and ACTIVE. The
89 * ASSEMBLY copy is latched into the ARM copy immediately after *_UPDATE bits
90 * are written. When the *_ACT_REQ bits are written, the ARM copy is latched
91 * into the ACTIVE copy, either immediately if the display controller is in
92 * STOP mode, or at the next frame boundary otherwise.
93 */
Thierry Reding62b9e062014-11-21 17:33:33 +010094void tegra_dc_commit(struct tegra_dc *dc)
Thierry Reding205d48e2014-10-21 13:41:46 +020095{
96 tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
97 tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
98}
99
Thierry Reding10288ee2014-03-14 09:54:58 +0100100static unsigned int tegra_dc_format(uint32_t format, uint32_t *swap)
101{
102 /* assume no swapping of fetched data */
103 if (swap)
104 *swap = BYTE_SWAP_NOSWAP;
105
106 switch (format) {
107 case DRM_FORMAT_XBGR8888:
108 return WIN_COLOR_DEPTH_R8G8B8A8;
109
110 case DRM_FORMAT_XRGB8888:
111 return WIN_COLOR_DEPTH_B8G8R8A8;
112
113 case DRM_FORMAT_RGB565:
114 return WIN_COLOR_DEPTH_B5G6R5;
115
116 case DRM_FORMAT_UYVY:
117 return WIN_COLOR_DEPTH_YCbCr422;
118
119 case DRM_FORMAT_YUYV:
120 if (swap)
121 *swap = BYTE_SWAP_SWAP2;
122
123 return WIN_COLOR_DEPTH_YCbCr422;
124
125 case DRM_FORMAT_YUV420:
126 return WIN_COLOR_DEPTH_YCbCr420P;
127
128 case DRM_FORMAT_YUV422:
129 return WIN_COLOR_DEPTH_YCbCr422P;
130
131 default:
132 break;
133 }
134
135 WARN(1, "unsupported pixel format %u, using default\n", format);
136 return WIN_COLOR_DEPTH_B8G8R8A8;
137}
138
139static bool tegra_dc_format_is_yuv(unsigned int format, bool *planar)
140{
141 switch (format) {
142 case WIN_COLOR_DEPTH_YCbCr422:
143 case WIN_COLOR_DEPTH_YUV422:
144 if (planar)
145 *planar = false;
146
147 return true;
148
149 case WIN_COLOR_DEPTH_YCbCr420P:
150 case WIN_COLOR_DEPTH_YUV420P:
151 case WIN_COLOR_DEPTH_YCbCr422P:
152 case WIN_COLOR_DEPTH_YUV422P:
153 case WIN_COLOR_DEPTH_YCbCr422R:
154 case WIN_COLOR_DEPTH_YUV422R:
155 case WIN_COLOR_DEPTH_YCbCr422RA:
156 case WIN_COLOR_DEPTH_YUV422RA:
157 if (planar)
158 *planar = true;
159
160 return true;
161 }
162
Thierry Redingfb35c6b2014-12-08 15:55:28 +0100163 if (planar)
164 *planar = false;
165
Thierry Reding10288ee2014-03-14 09:54:58 +0100166 return false;
167}
168
169static inline u32 compute_dda_inc(unsigned int in, unsigned int out, bool v,
170 unsigned int bpp)
171{
172 fixed20_12 outf = dfixed_init(out);
173 fixed20_12 inf = dfixed_init(in);
174 u32 dda_inc;
175 int max;
176
177 if (v)
178 max = 15;
179 else {
180 switch (bpp) {
181 case 2:
182 max = 8;
183 break;
184
185 default:
186 WARN_ON_ONCE(1);
187 /* fallthrough */
188 case 4:
189 max = 4;
190 break;
191 }
192 }
193
194 outf.full = max_t(u32, outf.full - dfixed_const(1), dfixed_const(1));
195 inf.full -= dfixed_const(1);
196
197 dda_inc = dfixed_div(inf, outf);
198 dda_inc = min_t(u32, dda_inc, dfixed_const(max));
199
200 return dda_inc;
201}
202
203static inline u32 compute_initial_dda(unsigned int in)
204{
205 fixed20_12 inf = dfixed_init(in);
206 return dfixed_frac(inf);
207}
208
Thierry Reding4aa3df72014-11-24 16:27:13 +0100209static void tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
210 const struct tegra_dc_window *window)
Thierry Reding10288ee2014-03-14 09:54:58 +0100211{
212 unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp;
Sean Paul93396d02014-11-19 13:04:49 -0500213 unsigned long value, flags;
Thierry Reding10288ee2014-03-14 09:54:58 +0100214 bool yuv, planar;
215
216 /*
217 * For YUV planar modes, the number of bytes per pixel takes into
218 * account only the luma component and therefore is 1.
219 */
220 yuv = tegra_dc_format_is_yuv(window->format, &planar);
221 if (!yuv)
222 bpp = window->bits_per_pixel / 8;
223 else
224 bpp = planar ? 1 : 2;
225
Sean Paul93396d02014-11-19 13:04:49 -0500226 spin_lock_irqsave(&dc->lock, flags);
227
Thierry Reding10288ee2014-03-14 09:54:58 +0100228 value = WINDOW_A_SELECT << index;
229 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
230
231 tegra_dc_writel(dc, window->format, DC_WIN_COLOR_DEPTH);
232 tegra_dc_writel(dc, window->swap, DC_WIN_BYTE_SWAP);
233
234 value = V_POSITION(window->dst.y) | H_POSITION(window->dst.x);
235 tegra_dc_writel(dc, value, DC_WIN_POSITION);
236
237 value = V_SIZE(window->dst.h) | H_SIZE(window->dst.w);
238 tegra_dc_writel(dc, value, DC_WIN_SIZE);
239
240 h_offset = window->src.x * bpp;
241 v_offset = window->src.y;
242 h_size = window->src.w * bpp;
243 v_size = window->src.h;
244
245 value = V_PRESCALED_SIZE(v_size) | H_PRESCALED_SIZE(h_size);
246 tegra_dc_writel(dc, value, DC_WIN_PRESCALED_SIZE);
247
248 /*
249 * For DDA computations the number of bytes per pixel for YUV planar
250 * modes needs to take into account all Y, U and V components.
251 */
252 if (yuv && planar)
253 bpp = 2;
254
255 h_dda = compute_dda_inc(window->src.w, window->dst.w, false, bpp);
256 v_dda = compute_dda_inc(window->src.h, window->dst.h, true, bpp);
257
258 value = V_DDA_INC(v_dda) | H_DDA_INC(h_dda);
259 tegra_dc_writel(dc, value, DC_WIN_DDA_INC);
260
261 h_dda = compute_initial_dda(window->src.x);
262 v_dda = compute_initial_dda(window->src.y);
263
264 tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA);
265 tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA);
266
267 tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE);
268 tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE);
269
270 tegra_dc_writel(dc, window->base[0], DC_WINBUF_START_ADDR);
271
272 if (yuv && planar) {
273 tegra_dc_writel(dc, window->base[1], DC_WINBUF_START_ADDR_U);
274 tegra_dc_writel(dc, window->base[2], DC_WINBUF_START_ADDR_V);
275 value = window->stride[1] << 16 | window->stride[0];
276 tegra_dc_writel(dc, value, DC_WIN_LINE_STRIDE);
277 } else {
278 tegra_dc_writel(dc, window->stride[0], DC_WIN_LINE_STRIDE);
279 }
280
281 if (window->bottom_up)
282 v_offset += window->src.h - 1;
283
284 tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET);
285 tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET);
286
Thierry Redingc134f012014-06-03 14:48:12 +0200287 if (dc->soc->supports_block_linear) {
288 unsigned long height = window->tiling.value;
Thierry Reding10288ee2014-03-14 09:54:58 +0100289
Thierry Redingc134f012014-06-03 14:48:12 +0200290 switch (window->tiling.mode) {
291 case TEGRA_BO_TILING_MODE_PITCH:
292 value = DC_WINBUF_SURFACE_KIND_PITCH;
293 break;
294
295 case TEGRA_BO_TILING_MODE_TILED:
296 value = DC_WINBUF_SURFACE_KIND_TILED;
297 break;
298
299 case TEGRA_BO_TILING_MODE_BLOCK:
300 value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(height) |
301 DC_WINBUF_SURFACE_KIND_BLOCK;
302 break;
303 }
304
305 tegra_dc_writel(dc, value, DC_WINBUF_SURFACE_KIND);
306 } else {
307 switch (window->tiling.mode) {
308 case TEGRA_BO_TILING_MODE_PITCH:
309 value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV |
310 DC_WIN_BUFFER_ADDR_MODE_LINEAR;
311 break;
312
313 case TEGRA_BO_TILING_MODE_TILED:
314 value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV |
315 DC_WIN_BUFFER_ADDR_MODE_TILE;
316 break;
317
318 case TEGRA_BO_TILING_MODE_BLOCK:
Thierry Reding4aa3df72014-11-24 16:27:13 +0100319 /*
320 * No need to handle this here because ->atomic_check
321 * will already have filtered it out.
322 */
323 break;
Thierry Redingc134f012014-06-03 14:48:12 +0200324 }
325
326 tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE);
327 }
Thierry Reding10288ee2014-03-14 09:54:58 +0100328
329 value = WIN_ENABLE;
330
331 if (yuv) {
332 /* setup default colorspace conversion coefficients */
333 tegra_dc_writel(dc, 0x00f0, DC_WIN_CSC_YOF);
334 tegra_dc_writel(dc, 0x012a, DC_WIN_CSC_KYRGB);
335 tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KUR);
336 tegra_dc_writel(dc, 0x0198, DC_WIN_CSC_KVR);
337 tegra_dc_writel(dc, 0x039b, DC_WIN_CSC_KUG);
338 tegra_dc_writel(dc, 0x032f, DC_WIN_CSC_KVG);
339 tegra_dc_writel(dc, 0x0204, DC_WIN_CSC_KUB);
340 tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KVB);
341
342 value |= CSC_ENABLE;
343 } else if (window->bits_per_pixel < 24) {
344 value |= COLOR_EXPAND;
345 }
346
347 if (window->bottom_up)
348 value |= V_DIRECTION;
349
350 tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
351
352 /*
353 * Disable blending and assume Window A is the bottom-most window,
354 * Window C is the top-most window and Window B is in the middle.
355 */
356 tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_NOKEY);
357 tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_1WIN);
358
359 switch (index) {
360 case 0:
361 tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_X);
362 tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y);
363 tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY);
364 break;
365
366 case 1:
367 tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X);
368 tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y);
369 tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY);
370 break;
371
372 case 2:
373 tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X);
374 tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_Y);
375 tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_3WIN_XY);
376 break;
377 }
378
Sean Paul93396d02014-11-19 13:04:49 -0500379 spin_unlock_irqrestore(&dc->lock, flags);
Thierry Redingc7679302014-10-21 13:51:53 +0200380}
381
382static void tegra_plane_destroy(struct drm_plane *plane)
383{
384 struct tegra_plane *p = to_tegra_plane(plane);
385
386 drm_plane_cleanup(plane);
387 kfree(p);
388}
389
390static const u32 tegra_primary_plane_formats[] = {
391 DRM_FORMAT_XBGR8888,
392 DRM_FORMAT_XRGB8888,
393 DRM_FORMAT_RGB565,
394};
395
Thierry Reding4aa3df72014-11-24 16:27:13 +0100396static void tegra_primary_plane_destroy(struct drm_plane *plane)
Thierry Redingc7679302014-10-21 13:51:53 +0200397{
Thierry Reding4aa3df72014-11-24 16:27:13 +0100398 tegra_plane_destroy(plane);
399}
400
401static const struct drm_plane_funcs tegra_primary_plane_funcs = {
Thierry Reding07866962014-11-24 17:08:06 +0100402 .update_plane = drm_atomic_helper_update_plane,
403 .disable_plane = drm_atomic_helper_disable_plane,
Thierry Reding4aa3df72014-11-24 16:27:13 +0100404 .destroy = tegra_primary_plane_destroy,
Thierry Reding9d441892014-11-24 17:02:53 +0100405 .reset = drm_atomic_helper_plane_reset,
406 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
Thierry Reding4aa3df72014-11-24 16:27:13 +0100407 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
408};
409
410static int tegra_plane_prepare_fb(struct drm_plane *plane,
411 struct drm_framebuffer *fb)
412{
413 return 0;
414}
415
416static void tegra_plane_cleanup_fb(struct drm_plane *plane,
417 struct drm_framebuffer *fb)
418{
419}
420
Thierry Reding47802b02014-11-26 12:28:39 +0100421static int tegra_plane_state_add(struct tegra_plane *plane,
422 struct drm_plane_state *state)
423{
424 struct drm_crtc_state *crtc_state;
425 struct tegra_dc_state *tegra;
426
427 /* Propagate errors from allocation or locking failures. */
428 crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
429 if (IS_ERR(crtc_state))
430 return PTR_ERR(crtc_state);
431
432 tegra = to_dc_state(crtc_state);
433
434 tegra->planes |= WIN_A_ACT_REQ << plane->index;
435
436 return 0;
437}
438
Thierry Reding4aa3df72014-11-24 16:27:13 +0100439static int tegra_plane_atomic_check(struct drm_plane *plane,
440 struct drm_plane_state *state)
441{
Thierry Reding47802b02014-11-26 12:28:39 +0100442 struct tegra_plane *tegra = to_tegra_plane(plane);
Thierry Reding4aa3df72014-11-24 16:27:13 +0100443 struct tegra_dc *dc = to_tegra_dc(state->crtc);
444 struct tegra_bo_tiling tiling;
Thierry Redingc7679302014-10-21 13:51:53 +0200445 int err;
446
Thierry Reding4aa3df72014-11-24 16:27:13 +0100447 /* no need for further checks if the plane is being disabled */
448 if (!state->crtc)
449 return 0;
450
451 err = tegra_fb_get_tiling(state->fb, &tiling);
452 if (err < 0)
453 return err;
454
455 if (tiling.mode == TEGRA_BO_TILING_MODE_BLOCK &&
456 !dc->soc->supports_block_linear) {
457 DRM_ERROR("hardware doesn't support block linear mode\n");
458 return -EINVAL;
459 }
460
461 /*
462 * Tegra doesn't support different strides for U and V planes so we
463 * error out if the user tries to display a framebuffer with such a
464 * configuration.
465 */
466 if (drm_format_num_planes(state->fb->pixel_format) > 2) {
467 if (state->fb->pitches[2] != state->fb->pitches[1]) {
468 DRM_ERROR("unsupported UV-plane configuration\n");
469 return -EINVAL;
470 }
471 }
472
Thierry Reding47802b02014-11-26 12:28:39 +0100473 err = tegra_plane_state_add(tegra, state);
474 if (err < 0)
475 return err;
476
Thierry Reding4aa3df72014-11-24 16:27:13 +0100477 return 0;
478}
479
480static void tegra_plane_atomic_update(struct drm_plane *plane,
481 struct drm_plane_state *old_state)
482{
483 struct tegra_dc *dc = to_tegra_dc(plane->state->crtc);
484 struct drm_framebuffer *fb = plane->state->fb;
485 struct tegra_plane *p = to_tegra_plane(plane);
486 struct tegra_dc_window window;
487 unsigned int i;
488 int err;
489
490 /* rien ne va plus */
491 if (!plane->state->crtc || !plane->state->fb)
492 return;
493
Thierry Redingc7679302014-10-21 13:51:53 +0200494 memset(&window, 0, sizeof(window));
Thierry Reding4aa3df72014-11-24 16:27:13 +0100495 window.src.x = plane->state->src_x >> 16;
496 window.src.y = plane->state->src_y >> 16;
497 window.src.w = plane->state->src_w >> 16;
498 window.src.h = plane->state->src_h >> 16;
499 window.dst.x = plane->state->crtc_x;
500 window.dst.y = plane->state->crtc_y;
501 window.dst.w = plane->state->crtc_w;
502 window.dst.h = plane->state->crtc_h;
Thierry Redingc7679302014-10-21 13:51:53 +0200503 window.format = tegra_dc_format(fb->pixel_format, &window.swap);
504 window.bits_per_pixel = fb->bits_per_pixel;
505 window.bottom_up = tegra_fb_is_bottom_up(fb);
506
507 err = tegra_fb_get_tiling(fb, &window.tiling);
Thierry Reding4aa3df72014-11-24 16:27:13 +0100508 WARN_ON(err < 0);
Thierry Redingc7679302014-10-21 13:51:53 +0200509
Thierry Reding4aa3df72014-11-24 16:27:13 +0100510 for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) {
511 struct tegra_bo *bo = tegra_fb_get_plane(fb, i);
Thierry Redingc7679302014-10-21 13:51:53 +0200512
Thierry Reding4aa3df72014-11-24 16:27:13 +0100513 window.base[i] = bo->paddr + fb->offsets[i];
514 window.stride[i] = fb->pitches[i];
515 }
Thierry Redingc7679302014-10-21 13:51:53 +0200516
Thierry Reding4aa3df72014-11-24 16:27:13 +0100517 tegra_dc_setup_window(dc, p->index, &window);
Thierry Redingc7679302014-10-21 13:51:53 +0200518}
519
Thierry Reding4aa3df72014-11-24 16:27:13 +0100520static void tegra_plane_atomic_disable(struct drm_plane *plane,
521 struct drm_plane_state *old_state)
Thierry Redingc7679302014-10-21 13:51:53 +0200522{
Thierry Reding4aa3df72014-11-24 16:27:13 +0100523 struct tegra_plane *p = to_tegra_plane(plane);
524 struct tegra_dc *dc;
525 unsigned long flags;
526 u32 value;
527
528 /* rien ne va plus */
529 if (!old_state || !old_state->crtc)
530 return;
531
532 dc = to_tegra_dc(old_state->crtc);
533
534 spin_lock_irqsave(&dc->lock, flags);
535
536 value = WINDOW_A_SELECT << p->index;
537 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
538
539 value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
540 value &= ~WIN_ENABLE;
541 tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
542
Thierry Reding4aa3df72014-11-24 16:27:13 +0100543 spin_unlock_irqrestore(&dc->lock, flags);
Thierry Redingc7679302014-10-21 13:51:53 +0200544}
545
Thierry Reding4aa3df72014-11-24 16:27:13 +0100546static const struct drm_plane_helper_funcs tegra_primary_plane_helper_funcs = {
547 .prepare_fb = tegra_plane_prepare_fb,
548 .cleanup_fb = tegra_plane_cleanup_fb,
549 .atomic_check = tegra_plane_atomic_check,
550 .atomic_update = tegra_plane_atomic_update,
551 .atomic_disable = tegra_plane_atomic_disable,
Thierry Redingc7679302014-10-21 13:51:53 +0200552};
553
554static struct drm_plane *tegra_dc_primary_plane_create(struct drm_device *drm,
555 struct tegra_dc *dc)
556{
Thierry Reding518e6222014-12-16 18:04:08 +0100557 /*
558 * Ideally this would use drm_crtc_mask(), but that would require the
559 * CRTC to already be in the mode_config's list of CRTCs. However, it
560 * will only be added to that list in the drm_crtc_init_with_planes()
561 * (in tegra_dc_init()), which in turn requires registration of these
562 * planes. So we have ourselves a nice little chicken and egg problem
563 * here.
564 *
565 * We work around this by manually creating the mask from the number
566 * of CRTCs that have been registered, and should therefore always be
567 * the same as drm_crtc_index() after registration.
568 */
569 unsigned long possible_crtcs = 1 << drm->mode_config.num_crtc;
Thierry Redingc7679302014-10-21 13:51:53 +0200570 struct tegra_plane *plane;
571 unsigned int num_formats;
572 const u32 *formats;
573 int err;
574
575 plane = kzalloc(sizeof(*plane), GFP_KERNEL);
576 if (!plane)
577 return ERR_PTR(-ENOMEM);
578
579 num_formats = ARRAY_SIZE(tegra_primary_plane_formats);
580 formats = tegra_primary_plane_formats;
581
Thierry Reding518e6222014-12-16 18:04:08 +0100582 err = drm_universal_plane_init(drm, &plane->base, possible_crtcs,
Thierry Redingc7679302014-10-21 13:51:53 +0200583 &tegra_primary_plane_funcs, formats,
584 num_formats, DRM_PLANE_TYPE_PRIMARY);
585 if (err < 0) {
586 kfree(plane);
587 return ERR_PTR(err);
588 }
589
Thierry Reding4aa3df72014-11-24 16:27:13 +0100590 drm_plane_helper_add(&plane->base, &tegra_primary_plane_helper_funcs);
591
Thierry Redingc7679302014-10-21 13:51:53 +0200592 return &plane->base;
593}
594
595static const u32 tegra_cursor_plane_formats[] = {
596 DRM_FORMAT_RGBA8888,
597};
598
Thierry Reding4aa3df72014-11-24 16:27:13 +0100599static int tegra_cursor_atomic_check(struct drm_plane *plane,
600 struct drm_plane_state *state)
Thierry Redingc7679302014-10-21 13:51:53 +0200601{
Thierry Reding47802b02014-11-26 12:28:39 +0100602 struct tegra_plane *tegra = to_tegra_plane(plane);
603 int err;
604
Thierry Reding4aa3df72014-11-24 16:27:13 +0100605 /* no need for further checks if the plane is being disabled */
606 if (!state->crtc)
607 return 0;
Thierry Redingc7679302014-10-21 13:51:53 +0200608
609 /* scaling not supported for cursor */
Thierry Reding4aa3df72014-11-24 16:27:13 +0100610 if ((state->src_w >> 16 != state->crtc_w) ||
611 (state->src_h >> 16 != state->crtc_h))
Thierry Redingc7679302014-10-21 13:51:53 +0200612 return -EINVAL;
613
614 /* only square cursors supported */
Thierry Reding4aa3df72014-11-24 16:27:13 +0100615 if (state->src_w != state->src_h)
Thierry Redingc7679302014-10-21 13:51:53 +0200616 return -EINVAL;
617
Thierry Reding4aa3df72014-11-24 16:27:13 +0100618 if (state->crtc_w != 32 && state->crtc_w != 64 &&
619 state->crtc_w != 128 && state->crtc_w != 256)
620 return -EINVAL;
621
Thierry Reding47802b02014-11-26 12:28:39 +0100622 err = tegra_plane_state_add(tegra, state);
623 if (err < 0)
624 return err;
625
Thierry Reding4aa3df72014-11-24 16:27:13 +0100626 return 0;
627}
628
629static void tegra_cursor_atomic_update(struct drm_plane *plane,
630 struct drm_plane_state *old_state)
631{
632 struct tegra_bo *bo = tegra_fb_get_plane(plane->state->fb, 0);
633 struct tegra_dc *dc = to_tegra_dc(plane->state->crtc);
634 struct drm_plane_state *state = plane->state;
635 u32 value = CURSOR_CLIP_DISPLAY;
636
637 /* rien ne va plus */
638 if (!plane->state->crtc || !plane->state->fb)
639 return;
640
641 switch (state->crtc_w) {
Thierry Redingc7679302014-10-21 13:51:53 +0200642 case 32:
643 value |= CURSOR_SIZE_32x32;
644 break;
645
646 case 64:
647 value |= CURSOR_SIZE_64x64;
648 break;
649
650 case 128:
651 value |= CURSOR_SIZE_128x128;
652 break;
653
654 case 256:
655 value |= CURSOR_SIZE_256x256;
656 break;
657
658 default:
Thierry Reding4aa3df72014-11-24 16:27:13 +0100659 WARN(1, "cursor size %ux%u not supported\n", state->crtc_w,
660 state->crtc_h);
661 return;
Thierry Redingc7679302014-10-21 13:51:53 +0200662 }
663
664 value |= (bo->paddr >> 10) & 0x3fffff;
665 tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR);
666
667#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
668 value = (bo->paddr >> 32) & 0x3;
669 tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR_HI);
670#endif
671
672 /* enable cursor and set blend mode */
673 value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
674 value |= CURSOR_ENABLE;
675 tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
676
677 value = tegra_dc_readl(dc, DC_DISP_BLEND_CURSOR_CONTROL);
678 value &= ~CURSOR_DST_BLEND_MASK;
679 value &= ~CURSOR_SRC_BLEND_MASK;
680 value |= CURSOR_MODE_NORMAL;
681 value |= CURSOR_DST_BLEND_NEG_K1_TIMES_SRC;
682 value |= CURSOR_SRC_BLEND_K1_TIMES_SRC;
683 value |= CURSOR_ALPHA;
684 tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL);
685
686 /* position the cursor */
Thierry Reding4aa3df72014-11-24 16:27:13 +0100687 value = (state->crtc_y & 0x3fff) << 16 | (state->crtc_x & 0x3fff);
Thierry Redingc7679302014-10-21 13:51:53 +0200688 tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION);
689
Thierry Redingc7679302014-10-21 13:51:53 +0200690}
691
Thierry Reding4aa3df72014-11-24 16:27:13 +0100692static void tegra_cursor_atomic_disable(struct drm_plane *plane,
693 struct drm_plane_state *old_state)
Thierry Redingc7679302014-10-21 13:51:53 +0200694{
Thierry Reding4aa3df72014-11-24 16:27:13 +0100695 struct tegra_dc *dc;
Thierry Redingc7679302014-10-21 13:51:53 +0200696 u32 value;
697
Thierry Reding4aa3df72014-11-24 16:27:13 +0100698 /* rien ne va plus */
699 if (!old_state || !old_state->crtc)
700 return;
701
702 dc = to_tegra_dc(old_state->crtc);
Thierry Redingc7679302014-10-21 13:51:53 +0200703
704 value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
705 value &= ~CURSOR_ENABLE;
706 tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
Thierry Redingc7679302014-10-21 13:51:53 +0200707}
708
709static const struct drm_plane_funcs tegra_cursor_plane_funcs = {
Thierry Reding07866962014-11-24 17:08:06 +0100710 .update_plane = drm_atomic_helper_update_plane,
711 .disable_plane = drm_atomic_helper_disable_plane,
Thierry Redingc7679302014-10-21 13:51:53 +0200712 .destroy = tegra_plane_destroy,
Thierry Reding9d441892014-11-24 17:02:53 +0100713 .reset = drm_atomic_helper_plane_reset,
714 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
Thierry Reding4aa3df72014-11-24 16:27:13 +0100715 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
716};
717
718static const struct drm_plane_helper_funcs tegra_cursor_plane_helper_funcs = {
719 .prepare_fb = tegra_plane_prepare_fb,
720 .cleanup_fb = tegra_plane_cleanup_fb,
721 .atomic_check = tegra_cursor_atomic_check,
722 .atomic_update = tegra_cursor_atomic_update,
723 .atomic_disable = tegra_cursor_atomic_disable,
Thierry Redingc7679302014-10-21 13:51:53 +0200724};
725
726static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm,
727 struct tegra_dc *dc)
728{
729 struct tegra_plane *plane;
730 unsigned int num_formats;
731 const u32 *formats;
732 int err;
733
734 plane = kzalloc(sizeof(*plane), GFP_KERNEL);
735 if (!plane)
736 return ERR_PTR(-ENOMEM);
737
Thierry Reding47802b02014-11-26 12:28:39 +0100738 /*
739 * We'll treat the cursor as an overlay plane with index 6 here so
740 * that the update and activation request bits in DC_CMD_STATE_CONTROL
741 * match up.
742 */
743 plane->index = 6;
744
Thierry Redingc7679302014-10-21 13:51:53 +0200745 num_formats = ARRAY_SIZE(tegra_cursor_plane_formats);
746 formats = tegra_cursor_plane_formats;
747
748 err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe,
749 &tegra_cursor_plane_funcs, formats,
750 num_formats, DRM_PLANE_TYPE_CURSOR);
751 if (err < 0) {
752 kfree(plane);
753 return ERR_PTR(err);
754 }
755
Thierry Reding4aa3df72014-11-24 16:27:13 +0100756 drm_plane_helper_add(&plane->base, &tegra_cursor_plane_helper_funcs);
757
Thierry Redingc7679302014-10-21 13:51:53 +0200758 return &plane->base;
759}
760
Thierry Redingc7679302014-10-21 13:51:53 +0200761static void tegra_overlay_plane_destroy(struct drm_plane *plane)
Thierry Redingf34bc782012-11-04 21:47:13 +0100762{
Thierry Redingc7679302014-10-21 13:51:53 +0200763 tegra_plane_destroy(plane);
Thierry Redingf34bc782012-11-04 21:47:13 +0100764}
765
Thierry Redingc7679302014-10-21 13:51:53 +0200766static const struct drm_plane_funcs tegra_overlay_plane_funcs = {
Thierry Reding07866962014-11-24 17:08:06 +0100767 .update_plane = drm_atomic_helper_update_plane,
768 .disable_plane = drm_atomic_helper_disable_plane,
Thierry Redingc7679302014-10-21 13:51:53 +0200769 .destroy = tegra_overlay_plane_destroy,
Thierry Reding9d441892014-11-24 17:02:53 +0100770 .reset = drm_atomic_helper_plane_reset,
771 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
Thierry Reding4aa3df72014-11-24 16:27:13 +0100772 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
Thierry Redingf34bc782012-11-04 21:47:13 +0100773};
774
Thierry Redingc7679302014-10-21 13:51:53 +0200775static const uint32_t tegra_overlay_plane_formats[] = {
Thierry Redingdbe4d9a2013-03-22 15:37:30 +0100776 DRM_FORMAT_XBGR8888,
Thierry Redingf34bc782012-11-04 21:47:13 +0100777 DRM_FORMAT_XRGB8888,
Thierry Redingdbe4d9a2013-03-22 15:37:30 +0100778 DRM_FORMAT_RGB565,
Thierry Redingf34bc782012-11-04 21:47:13 +0100779 DRM_FORMAT_UYVY,
Thierry Redingf9253902014-01-29 20:31:17 +0100780 DRM_FORMAT_YUYV,
Thierry Redingf34bc782012-11-04 21:47:13 +0100781 DRM_FORMAT_YUV420,
782 DRM_FORMAT_YUV422,
783};
784
Thierry Reding4aa3df72014-11-24 16:27:13 +0100785static const struct drm_plane_helper_funcs tegra_overlay_plane_helper_funcs = {
786 .prepare_fb = tegra_plane_prepare_fb,
787 .cleanup_fb = tegra_plane_cleanup_fb,
788 .atomic_check = tegra_plane_atomic_check,
789 .atomic_update = tegra_plane_atomic_update,
790 .atomic_disable = tegra_plane_atomic_disable,
791};
792
Thierry Redingc7679302014-10-21 13:51:53 +0200793static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
794 struct tegra_dc *dc,
795 unsigned int index)
796{
797 struct tegra_plane *plane;
798 unsigned int num_formats;
799 const u32 *formats;
800 int err;
801
802 plane = kzalloc(sizeof(*plane), GFP_KERNEL);
803 if (!plane)
804 return ERR_PTR(-ENOMEM);
805
806 plane->index = index;
807
808 num_formats = ARRAY_SIZE(tegra_overlay_plane_formats);
809 formats = tegra_overlay_plane_formats;
810
811 err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe,
812 &tegra_overlay_plane_funcs, formats,
813 num_formats, DRM_PLANE_TYPE_OVERLAY);
814 if (err < 0) {
815 kfree(plane);
816 return ERR_PTR(err);
817 }
818
Thierry Reding4aa3df72014-11-24 16:27:13 +0100819 drm_plane_helper_add(&plane->base, &tegra_overlay_plane_helper_funcs);
820
Thierry Redingc7679302014-10-21 13:51:53 +0200821 return &plane->base;
822}
823
Thierry Redingf34bc782012-11-04 21:47:13 +0100824static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc)
825{
Thierry Redingc7679302014-10-21 13:51:53 +0200826 struct drm_plane *plane;
Thierry Redingf34bc782012-11-04 21:47:13 +0100827 unsigned int i;
Thierry Redingf34bc782012-11-04 21:47:13 +0100828
829 for (i = 0; i < 2; i++) {
Thierry Redingc7679302014-10-21 13:51:53 +0200830 plane = tegra_dc_overlay_plane_create(drm, dc, 1 + i);
831 if (IS_ERR(plane))
832 return PTR_ERR(plane);
Thierry Redingf34bc782012-11-04 21:47:13 +0100833 }
834
835 return 0;
836}
837
Thierry Reding6e5ff992012-11-28 11:45:47 +0100838void tegra_dc_enable_vblank(struct tegra_dc *dc)
839{
840 unsigned long value, flags;
841
842 spin_lock_irqsave(&dc->lock, flags);
843
844 value = tegra_dc_readl(dc, DC_CMD_INT_MASK);
845 value |= VBLANK_INT;
846 tegra_dc_writel(dc, value, DC_CMD_INT_MASK);
847
848 spin_unlock_irqrestore(&dc->lock, flags);
849}
850
851void tegra_dc_disable_vblank(struct tegra_dc *dc)
852{
853 unsigned long value, flags;
854
855 spin_lock_irqsave(&dc->lock, flags);
856
857 value = tegra_dc_readl(dc, DC_CMD_INT_MASK);
858 value &= ~VBLANK_INT;
859 tegra_dc_writel(dc, value, DC_CMD_INT_MASK);
860
861 spin_unlock_irqrestore(&dc->lock, flags);
862}
863
Thierry Reding3c03c462012-11-28 12:00:18 +0100864static void tegra_dc_finish_page_flip(struct tegra_dc *dc)
865{
866 struct drm_device *drm = dc->base.dev;
867 struct drm_crtc *crtc = &dc->base;
Thierry Reding3c03c462012-11-28 12:00:18 +0100868 unsigned long flags, base;
Arto Merilainende2ba662013-03-22 16:34:08 +0200869 struct tegra_bo *bo;
Thierry Reding3c03c462012-11-28 12:00:18 +0100870
Thierry Reding6b59cc12014-12-16 16:33:27 +0100871 spin_lock_irqsave(&drm->event_lock, flags);
872
873 if (!dc->event) {
874 spin_unlock_irqrestore(&drm->event_lock, flags);
Thierry Reding3c03c462012-11-28 12:00:18 +0100875 return;
Thierry Reding6b59cc12014-12-16 16:33:27 +0100876 }
Thierry Reding3c03c462012-11-28 12:00:18 +0100877
Matt Roperf4510a22014-04-01 15:22:40 -0700878 bo = tegra_fb_get_plane(crtc->primary->fb, 0);
Thierry Reding3c03c462012-11-28 12:00:18 +0100879
Dan Carpenter8643bc62015-01-07 14:01:26 +0300880 spin_lock(&dc->lock);
Sean Paul93396d02014-11-19 13:04:49 -0500881
Thierry Reding3c03c462012-11-28 12:00:18 +0100882 /* check if new start address has been latched */
Sean Paul93396d02014-11-19 13:04:49 -0500883 tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);
Thierry Reding3c03c462012-11-28 12:00:18 +0100884 tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS);
885 base = tegra_dc_readl(dc, DC_WINBUF_START_ADDR);
886 tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS);
887
Dan Carpenter8643bc62015-01-07 14:01:26 +0300888 spin_unlock(&dc->lock);
Sean Paul93396d02014-11-19 13:04:49 -0500889
Matt Roperf4510a22014-04-01 15:22:40 -0700890 if (base == bo->paddr + crtc->primary->fb->offsets[0]) {
Thierry Redinged7dae52014-12-16 16:03:13 +0100891 drm_crtc_send_vblank_event(crtc, dc->event);
892 drm_crtc_vblank_put(crtc);
Thierry Reding3c03c462012-11-28 12:00:18 +0100893 dc->event = NULL;
Thierry Reding3c03c462012-11-28 12:00:18 +0100894 }
Thierry Reding6b59cc12014-12-16 16:33:27 +0100895
896 spin_unlock_irqrestore(&drm->event_lock, flags);
Thierry Reding3c03c462012-11-28 12:00:18 +0100897}
898
899void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
900{
901 struct tegra_dc *dc = to_tegra_dc(crtc);
902 struct drm_device *drm = crtc->dev;
903 unsigned long flags;
904
905 spin_lock_irqsave(&drm->event_lock, flags);
906
907 if (dc->event && dc->event->base.file_priv == file) {
908 dc->event->base.destroy(&dc->event->base);
Thierry Redinged7dae52014-12-16 16:03:13 +0100909 drm_crtc_vblank_put(crtc);
Thierry Reding3c03c462012-11-28 12:00:18 +0100910 dc->event = NULL;
911 }
912
913 spin_unlock_irqrestore(&drm->event_lock, flags);
914}
915
Thierry Redingf002abc2013-10-14 14:06:02 +0200916static void tegra_dc_destroy(struct drm_crtc *crtc)
917{
918 drm_crtc_cleanup(crtc);
Thierry Redingf002abc2013-10-14 14:06:02 +0200919}
920
Thierry Redingca915b12014-12-08 16:14:45 +0100921static void tegra_crtc_reset(struct drm_crtc *crtc)
922{
923 struct tegra_dc_state *state;
924
925 kfree(crtc->state);
926 crtc->state = NULL;
927
928 state = kzalloc(sizeof(*state), GFP_KERNEL);
929 if (state)
930 crtc->state = &state->base;
931}
932
933static struct drm_crtc_state *
934tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
935{
936 struct tegra_dc_state *state = to_dc_state(crtc->state);
937 struct tegra_dc_state *copy;
938
939 copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
940 if (!copy)
941 return NULL;
942
943 copy->base.mode_changed = false;
944 copy->base.planes_changed = false;
945 copy->base.event = NULL;
946
947 return &copy->base;
948}
949
950static void tegra_crtc_atomic_destroy_state(struct drm_crtc *crtc,
951 struct drm_crtc_state *state)
952{
953 kfree(state);
954}
955
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000956static const struct drm_crtc_funcs tegra_crtc_funcs = {
Thierry Reding1503ca42014-11-24 17:41:23 +0100957 .page_flip = drm_atomic_helper_page_flip,
Thierry Reding74f48792014-11-24 17:08:20 +0100958 .set_config = drm_atomic_helper_set_config,
Thierry Redingf002abc2013-10-14 14:06:02 +0200959 .destroy = tegra_dc_destroy,
Thierry Redingca915b12014-12-08 16:14:45 +0100960 .reset = tegra_crtc_reset,
961 .atomic_duplicate_state = tegra_crtc_atomic_duplicate_state,
962 .atomic_destroy_state = tegra_crtc_atomic_destroy_state,
Thierry Redingd8f4a9e2012-11-15 21:28:22 +0000963};
964
Thierry Reding86df2562014-12-08 16:03:53 +0100965static void tegra_dc_stop(struct tegra_dc *dc)
966{
967 u32 value;
968
969 /* stop the display controller */
970 value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
971 value &= ~DISP_CTRL_MODE_MASK;
972 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
973
974 tegra_dc_commit(dc);
975}
976
977static bool tegra_dc_idle(struct tegra_dc *dc)
978{
979 u32 value;
980
981 value = tegra_dc_readl_active(dc, DC_CMD_DISPLAY_COMMAND);
982
983 return (value & DISP_CTRL_MODE_MASK) == 0;
984}
985
986static int tegra_dc_wait_idle(struct tegra_dc *dc, unsigned long timeout)
987{
988 timeout = jiffies + msecs_to_jiffies(timeout);
989
990 while (time_before(jiffies, timeout)) {
991 if (tegra_dc_idle(dc))
992 return 0;
993
994 usleep_range(1000, 2000);
995 }
996
997 dev_dbg(dc->dev, "timeout waiting for DC to become idle\n");
998 return -ETIMEDOUT;
999}
1000
Thierry Redingf34bc782012-11-04 21:47:13 +01001001static void tegra_crtc_disable(struct drm_crtc *crtc)
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001002{
Thierry Redingf002abc2013-10-14 14:06:02 +02001003 struct tegra_dc *dc = to_tegra_dc(crtc);
Thierry Reding3b0e5852014-12-16 18:30:16 +01001004 u32 value;
Thierry Redingf002abc2013-10-14 14:06:02 +02001005
Thierry Reding86df2562014-12-08 16:03:53 +01001006 if (!tegra_dc_idle(dc)) {
1007 tegra_dc_stop(dc);
1008
1009 /*
1010 * Ignore the return value, there isn't anything useful to do
1011 * in case this fails.
1012 */
1013 tegra_dc_wait_idle(dc, 100);
1014 }
Thierry Reding36904ad2014-11-21 17:35:54 +01001015
Thierry Reding3b0e5852014-12-16 18:30:16 +01001016 /*
1017 * This should really be part of the RGB encoder driver, but clearing
1018 * these bits has the side-effect of stopping the display controller.
1019 * When that happens no VBLANK interrupts will be raised. At the same
1020 * time the encoder is disabled before the display controller, so the
1021 * above code is always going to timeout waiting for the controller
1022 * to go idle.
1023 *
1024 * Given the close coupling between the RGB encoder and the display
1025 * controller doing it here is still kind of okay. None of the other
1026 * encoder drivers require these bits to be cleared.
1027 *
1028 * XXX: Perhaps given that the display controller is switched off at
1029 * this point anyway maybe clearing these bits isn't even useful for
1030 * the RGB encoder?
1031 */
1032 if (dc->rgb) {
1033 value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
1034 value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
1035 PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
1036 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
1037 }
1038
Thierry Reding8ff64c12014-10-08 14:48:51 +02001039 drm_crtc_vblank_off(crtc);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001040}
1041
1042static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc,
1043 const struct drm_display_mode *mode,
1044 struct drm_display_mode *adjusted)
1045{
1046 return true;
1047}
1048
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001049static int tegra_dc_set_timings(struct tegra_dc *dc,
1050 struct drm_display_mode *mode)
1051{
Thierry Reding0444c0f2014-04-16 09:22:38 +02001052 unsigned int h_ref_to_sync = 1;
1053 unsigned int v_ref_to_sync = 1;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001054 unsigned long value;
1055
1056 tegra_dc_writel(dc, 0x0, DC_DISP_DISP_TIMING_OPTIONS);
1057
1058 value = (v_ref_to_sync << 16) | h_ref_to_sync;
1059 tegra_dc_writel(dc, value, DC_DISP_REF_TO_SYNC);
1060
1061 value = ((mode->vsync_end - mode->vsync_start) << 16) |
1062 ((mode->hsync_end - mode->hsync_start) << 0);
1063 tegra_dc_writel(dc, value, DC_DISP_SYNC_WIDTH);
1064
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001065 value = ((mode->vtotal - mode->vsync_end) << 16) |
1066 ((mode->htotal - mode->hsync_end) << 0);
Lucas Stach40495082012-12-19 21:38:52 +00001067 tegra_dc_writel(dc, value, DC_DISP_BACK_PORCH);
1068
1069 value = ((mode->vsync_start - mode->vdisplay) << 16) |
1070 ((mode->hsync_start - mode->hdisplay) << 0);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001071 tegra_dc_writel(dc, value, DC_DISP_FRONT_PORCH);
1072
1073 value = (mode->vdisplay << 16) | mode->hdisplay;
1074 tegra_dc_writel(dc, value, DC_DISP_ACTIVE);
1075
1076 return 0;
1077}
1078
Thierry Redingc5a107d2014-12-02 15:15:06 +01001079int tegra_dc_setup_clock(struct tegra_dc *dc, struct clk *parent,
1080 unsigned long pclk, unsigned int div)
1081{
1082 u32 value;
1083 int err;
1084
1085 err = clk_set_parent(dc->clk, parent);
1086 if (err < 0) {
1087 dev_err(dc->dev, "failed to set parent clock: %d\n", err);
1088 return err;
1089 }
1090
1091 DRM_DEBUG_KMS("rate: %lu, div: %u\n", clk_get_rate(dc->clk), div);
1092
1093 value = SHIFT_CLK_DIVIDER(div) | PIXEL_CLK_DIVIDER_PCD1;
1094 tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL);
1095
1096 return 0;
1097}
1098
Thierry Redingca915b12014-12-08 16:14:45 +01001099int tegra_dc_state_setup_clock(struct tegra_dc *dc,
1100 struct drm_crtc_state *crtc_state,
1101 struct clk *clk, unsigned long pclk,
1102 unsigned int div)
1103{
1104 struct tegra_dc_state *state = to_dc_state(crtc_state);
1105
1106 state->clk = clk;
1107 state->pclk = pclk;
1108 state->div = div;
1109
1110 return 0;
1111}
1112
Thierry Reding76d59ed2014-12-19 15:09:16 +01001113static void tegra_dc_commit_state(struct tegra_dc *dc,
1114 struct tegra_dc_state *state)
1115{
1116 u32 value;
1117 int err;
1118
1119 err = clk_set_parent(dc->clk, state->clk);
1120 if (err < 0)
1121 dev_err(dc->dev, "failed to set parent clock: %d\n", err);
1122
1123 /*
1124 * Outputs may not want to change the parent clock rate. This is only
1125 * relevant to Tegra20 where only a single display PLL is available.
1126 * Since that PLL would typically be used for HDMI, an internal LVDS
1127 * panel would need to be driven by some other clock such as PLL_P
1128 * which is shared with other peripherals. Changing the clock rate
1129 * should therefore be avoided.
1130 */
1131 if (state->pclk > 0) {
1132 err = clk_set_rate(state->clk, state->pclk);
1133 if (err < 0)
1134 dev_err(dc->dev,
1135 "failed to set clock rate to %lu Hz\n",
1136 state->pclk);
1137 }
1138
1139 DRM_DEBUG_KMS("rate: %lu, div: %u\n", clk_get_rate(dc->clk),
1140 state->div);
1141 DRM_DEBUG_KMS("pclk: %lu\n", state->pclk);
1142
1143 value = SHIFT_CLK_DIVIDER(state->div) | PIXEL_CLK_DIVIDER_PCD1;
1144 tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL);
1145}
1146
Thierry Reding4aa3df72014-11-24 16:27:13 +01001147static void tegra_crtc_mode_set_nofb(struct drm_crtc *crtc)
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001148{
Thierry Reding4aa3df72014-11-24 16:27:13 +01001149 struct drm_display_mode *mode = &crtc->state->adjusted_mode;
Thierry Reding76d59ed2014-12-19 15:09:16 +01001150 struct tegra_dc_state *state = to_dc_state(crtc->state);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001151 struct tegra_dc *dc = to_tegra_dc(crtc);
Thierry Redingdbb3f2f2014-03-26 12:32:14 +01001152 u32 value;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001153
Thierry Reding76d59ed2014-12-19 15:09:16 +01001154 tegra_dc_commit_state(dc, state);
1155
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001156 /* program display mode */
1157 tegra_dc_set_timings(dc, mode);
1158
Thierry Reding42d06592014-12-08 15:45:39 +01001159 if (dc->soc->supports_border_color)
1160 tegra_dc_writel(dc, 0, DC_DISP_BORDER_COLOR);
1161
Thierry Reding8620fc62013-12-12 11:03:59 +01001162 /* interlacing isn't supported yet, so disable it */
1163 if (dc->soc->supports_interlacing) {
1164 value = tegra_dc_readl(dc, DC_DISP_INTERLACE_CONTROL);
1165 value &= ~INTERLACE_ENABLE;
1166 tegra_dc_writel(dc, value, DC_DISP_INTERLACE_CONTROL);
1167 }
Thierry Reding23fb4742012-11-28 11:38:24 +01001168}
1169
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001170static void tegra_crtc_prepare(struct drm_crtc *crtc)
1171{
1172 struct tegra_dc *dc = to_tegra_dc(crtc);
1173 unsigned int syncpt;
1174 unsigned long value;
1175
Thierry Reding8ff64c12014-10-08 14:48:51 +02001176 drm_crtc_vblank_off(crtc);
1177
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001178 if (dc->pipe)
1179 syncpt = SYNCPT_VBLANK1;
1180 else
1181 syncpt = SYNCPT_VBLANK0;
1182
1183 /* initialize display controller */
1184 tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
1185 tegra_dc_writel(dc, 0x100 | syncpt, DC_CMD_CONT_SYNCPT_VSYNC);
1186
1187 value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | WIN_A_OF_INT;
1188 tegra_dc_writel(dc, value, DC_CMD_INT_TYPE);
1189
1190 value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
1191 WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT;
1192 tegra_dc_writel(dc, value, DC_CMD_INT_POLARITY);
1193
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001194 /* initialize timer */
1195 value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) |
1196 WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20);
1197 tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY);
1198
1199 value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(1) |
1200 WINDOW_B_THRESHOLD(1) | WINDOW_C_THRESHOLD(1);
1201 tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER);
1202
1203 value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001204 tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE);
Thierry Reding6e5ff992012-11-28 11:45:47 +01001205
1206 value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT;
1207 tegra_dc_writel(dc, value, DC_CMD_INT_MASK);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001208}
1209
1210static void tegra_crtc_commit(struct drm_crtc *crtc)
1211{
Thierry Reding8ff64c12014-10-08 14:48:51 +02001212 drm_crtc_vblank_on(crtc);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001213}
1214
Thierry Reding4aa3df72014-11-24 16:27:13 +01001215static int tegra_crtc_atomic_check(struct drm_crtc *crtc,
1216 struct drm_crtc_state *state)
1217{
1218 return 0;
1219}
1220
1221static void tegra_crtc_atomic_begin(struct drm_crtc *crtc)
1222{
Thierry Reding1503ca42014-11-24 17:41:23 +01001223 struct tegra_dc *dc = to_tegra_dc(crtc);
1224
1225 if (crtc->state->event) {
1226 crtc->state->event->pipe = drm_crtc_index(crtc);
1227
1228 WARN_ON(drm_crtc_vblank_get(crtc) != 0);
1229
1230 dc->event = crtc->state->event;
1231 crtc->state->event = NULL;
1232 }
Thierry Reding4aa3df72014-11-24 16:27:13 +01001233}
1234
1235static void tegra_crtc_atomic_flush(struct drm_crtc *crtc)
1236{
Thierry Reding47802b02014-11-26 12:28:39 +01001237 struct tegra_dc_state *state = to_dc_state(crtc->state);
1238 struct tegra_dc *dc = to_tegra_dc(crtc);
1239
1240 tegra_dc_writel(dc, state->planes << 8, DC_CMD_STATE_CONTROL);
1241 tegra_dc_writel(dc, state->planes, DC_CMD_STATE_CONTROL);
Thierry Reding4aa3df72014-11-24 16:27:13 +01001242}
1243
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001244static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = {
Thierry Redingf34bc782012-11-04 21:47:13 +01001245 .disable = tegra_crtc_disable,
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001246 .mode_fixup = tegra_crtc_mode_fixup,
Thierry Reding4aa3df72014-11-24 16:27:13 +01001247 .mode_set = drm_helper_crtc_mode_set,
1248 .mode_set_nofb = tegra_crtc_mode_set_nofb,
1249 .mode_set_base = drm_helper_crtc_mode_set_base,
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001250 .prepare = tegra_crtc_prepare,
1251 .commit = tegra_crtc_commit,
Thierry Reding4aa3df72014-11-24 16:27:13 +01001252 .atomic_check = tegra_crtc_atomic_check,
1253 .atomic_begin = tegra_crtc_atomic_begin,
1254 .atomic_flush = tegra_crtc_atomic_flush,
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001255};
1256
Thierry Reding6e5ff992012-11-28 11:45:47 +01001257static irqreturn_t tegra_dc_irq(int irq, void *data)
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001258{
1259 struct tegra_dc *dc = data;
1260 unsigned long status;
1261
1262 status = tegra_dc_readl(dc, DC_CMD_INT_STATUS);
1263 tegra_dc_writel(dc, status, DC_CMD_INT_STATUS);
1264
1265 if (status & FRAME_END_INT) {
1266 /*
1267 dev_dbg(dc->dev, "%s(): frame end\n", __func__);
1268 */
1269 }
1270
1271 if (status & VBLANK_INT) {
1272 /*
1273 dev_dbg(dc->dev, "%s(): vertical blank\n", __func__);
1274 */
Thierry Redinged7dae52014-12-16 16:03:13 +01001275 drm_crtc_handle_vblank(&dc->base);
Thierry Reding3c03c462012-11-28 12:00:18 +01001276 tegra_dc_finish_page_flip(dc);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001277 }
1278
1279 if (status & (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT)) {
1280 /*
1281 dev_dbg(dc->dev, "%s(): underflow\n", __func__);
1282 */
1283 }
1284
1285 return IRQ_HANDLED;
1286}
1287
1288static int tegra_dc_show_regs(struct seq_file *s, void *data)
1289{
1290 struct drm_info_node *node = s->private;
1291 struct tegra_dc *dc = node->info_ent->data;
1292
1293#define DUMP_REG(name) \
Thierry Reding03a60562014-10-21 13:48:48 +02001294 seq_printf(s, "%-40s %#05x %08x\n", #name, name, \
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001295 tegra_dc_readl(dc, name))
1296
1297 DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT);
1298 DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
1299 DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT_ERROR);
1300 DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT);
1301 DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT_CNTRL);
1302 DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT_ERROR);
1303 DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT);
1304 DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT_CNTRL);
1305 DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT_ERROR);
1306 DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT);
1307 DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT_CNTRL);
1308 DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT_ERROR);
1309 DUMP_REG(DC_CMD_CONT_SYNCPT_VSYNC);
1310 DUMP_REG(DC_CMD_DISPLAY_COMMAND_OPTION0);
1311 DUMP_REG(DC_CMD_DISPLAY_COMMAND);
1312 DUMP_REG(DC_CMD_SIGNAL_RAISE);
1313 DUMP_REG(DC_CMD_DISPLAY_POWER_CONTROL);
1314 DUMP_REG(DC_CMD_INT_STATUS);
1315 DUMP_REG(DC_CMD_INT_MASK);
1316 DUMP_REG(DC_CMD_INT_ENABLE);
1317 DUMP_REG(DC_CMD_INT_TYPE);
1318 DUMP_REG(DC_CMD_INT_POLARITY);
1319 DUMP_REG(DC_CMD_SIGNAL_RAISE1);
1320 DUMP_REG(DC_CMD_SIGNAL_RAISE2);
1321 DUMP_REG(DC_CMD_SIGNAL_RAISE3);
1322 DUMP_REG(DC_CMD_STATE_ACCESS);
1323 DUMP_REG(DC_CMD_STATE_CONTROL);
1324 DUMP_REG(DC_CMD_DISPLAY_WINDOW_HEADER);
1325 DUMP_REG(DC_CMD_REG_ACT_CONTROL);
1326 DUMP_REG(DC_COM_CRC_CONTROL);
1327 DUMP_REG(DC_COM_CRC_CHECKSUM);
1328 DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(0));
1329 DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(1));
1330 DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(2));
1331 DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(3));
1332 DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(0));
1333 DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(1));
1334 DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(2));
1335 DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(3));
1336 DUMP_REG(DC_COM_PIN_OUTPUT_DATA(0));
1337 DUMP_REG(DC_COM_PIN_OUTPUT_DATA(1));
1338 DUMP_REG(DC_COM_PIN_OUTPUT_DATA(2));
1339 DUMP_REG(DC_COM_PIN_OUTPUT_DATA(3));
1340 DUMP_REG(DC_COM_PIN_INPUT_ENABLE(0));
1341 DUMP_REG(DC_COM_PIN_INPUT_ENABLE(1));
1342 DUMP_REG(DC_COM_PIN_INPUT_ENABLE(2));
1343 DUMP_REG(DC_COM_PIN_INPUT_ENABLE(3));
1344 DUMP_REG(DC_COM_PIN_INPUT_DATA(0));
1345 DUMP_REG(DC_COM_PIN_INPUT_DATA(1));
1346 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(0));
1347 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(1));
1348 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(2));
1349 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(3));
1350 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(4));
1351 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(5));
1352 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(6));
1353 DUMP_REG(DC_COM_PIN_MISC_CONTROL);
1354 DUMP_REG(DC_COM_PIN_PM0_CONTROL);
1355 DUMP_REG(DC_COM_PIN_PM0_DUTY_CYCLE);
1356 DUMP_REG(DC_COM_PIN_PM1_CONTROL);
1357 DUMP_REG(DC_COM_PIN_PM1_DUTY_CYCLE);
1358 DUMP_REG(DC_COM_SPI_CONTROL);
1359 DUMP_REG(DC_COM_SPI_START_BYTE);
1360 DUMP_REG(DC_COM_HSPI_WRITE_DATA_AB);
1361 DUMP_REG(DC_COM_HSPI_WRITE_DATA_CD);
1362 DUMP_REG(DC_COM_HSPI_CS_DC);
1363 DUMP_REG(DC_COM_SCRATCH_REGISTER_A);
1364 DUMP_REG(DC_COM_SCRATCH_REGISTER_B);
1365 DUMP_REG(DC_COM_GPIO_CTRL);
1366 DUMP_REG(DC_COM_GPIO_DEBOUNCE_COUNTER);
1367 DUMP_REG(DC_COM_CRC_CHECKSUM_LATCHED);
1368 DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS0);
1369 DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS1);
1370 DUMP_REG(DC_DISP_DISP_WIN_OPTIONS);
1371 DUMP_REG(DC_DISP_DISP_MEM_HIGH_PRIORITY);
1372 DUMP_REG(DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER);
1373 DUMP_REG(DC_DISP_DISP_TIMING_OPTIONS);
1374 DUMP_REG(DC_DISP_REF_TO_SYNC);
1375 DUMP_REG(DC_DISP_SYNC_WIDTH);
1376 DUMP_REG(DC_DISP_BACK_PORCH);
1377 DUMP_REG(DC_DISP_ACTIVE);
1378 DUMP_REG(DC_DISP_FRONT_PORCH);
1379 DUMP_REG(DC_DISP_H_PULSE0_CONTROL);
1380 DUMP_REG(DC_DISP_H_PULSE0_POSITION_A);
1381 DUMP_REG(DC_DISP_H_PULSE0_POSITION_B);
1382 DUMP_REG(DC_DISP_H_PULSE0_POSITION_C);
1383 DUMP_REG(DC_DISP_H_PULSE0_POSITION_D);
1384 DUMP_REG(DC_DISP_H_PULSE1_CONTROL);
1385 DUMP_REG(DC_DISP_H_PULSE1_POSITION_A);
1386 DUMP_REG(DC_DISP_H_PULSE1_POSITION_B);
1387 DUMP_REG(DC_DISP_H_PULSE1_POSITION_C);
1388 DUMP_REG(DC_DISP_H_PULSE1_POSITION_D);
1389 DUMP_REG(DC_DISP_H_PULSE2_CONTROL);
1390 DUMP_REG(DC_DISP_H_PULSE2_POSITION_A);
1391 DUMP_REG(DC_DISP_H_PULSE2_POSITION_B);
1392 DUMP_REG(DC_DISP_H_PULSE2_POSITION_C);
1393 DUMP_REG(DC_DISP_H_PULSE2_POSITION_D);
1394 DUMP_REG(DC_DISP_V_PULSE0_CONTROL);
1395 DUMP_REG(DC_DISP_V_PULSE0_POSITION_A);
1396 DUMP_REG(DC_DISP_V_PULSE0_POSITION_B);
1397 DUMP_REG(DC_DISP_V_PULSE0_POSITION_C);
1398 DUMP_REG(DC_DISP_V_PULSE1_CONTROL);
1399 DUMP_REG(DC_DISP_V_PULSE1_POSITION_A);
1400 DUMP_REG(DC_DISP_V_PULSE1_POSITION_B);
1401 DUMP_REG(DC_DISP_V_PULSE1_POSITION_C);
1402 DUMP_REG(DC_DISP_V_PULSE2_CONTROL);
1403 DUMP_REG(DC_DISP_V_PULSE2_POSITION_A);
1404 DUMP_REG(DC_DISP_V_PULSE3_CONTROL);
1405 DUMP_REG(DC_DISP_V_PULSE3_POSITION_A);
1406 DUMP_REG(DC_DISP_M0_CONTROL);
1407 DUMP_REG(DC_DISP_M1_CONTROL);
1408 DUMP_REG(DC_DISP_DI_CONTROL);
1409 DUMP_REG(DC_DISP_PP_CONTROL);
1410 DUMP_REG(DC_DISP_PP_SELECT_A);
1411 DUMP_REG(DC_DISP_PP_SELECT_B);
1412 DUMP_REG(DC_DISP_PP_SELECT_C);
1413 DUMP_REG(DC_DISP_PP_SELECT_D);
1414 DUMP_REG(DC_DISP_DISP_CLOCK_CONTROL);
1415 DUMP_REG(DC_DISP_DISP_INTERFACE_CONTROL);
1416 DUMP_REG(DC_DISP_DISP_COLOR_CONTROL);
1417 DUMP_REG(DC_DISP_SHIFT_CLOCK_OPTIONS);
1418 DUMP_REG(DC_DISP_DATA_ENABLE_OPTIONS);
1419 DUMP_REG(DC_DISP_SERIAL_INTERFACE_OPTIONS);
1420 DUMP_REG(DC_DISP_LCD_SPI_OPTIONS);
1421 DUMP_REG(DC_DISP_BORDER_COLOR);
1422 DUMP_REG(DC_DISP_COLOR_KEY0_LOWER);
1423 DUMP_REG(DC_DISP_COLOR_KEY0_UPPER);
1424 DUMP_REG(DC_DISP_COLOR_KEY1_LOWER);
1425 DUMP_REG(DC_DISP_COLOR_KEY1_UPPER);
1426 DUMP_REG(DC_DISP_CURSOR_FOREGROUND);
1427 DUMP_REG(DC_DISP_CURSOR_BACKGROUND);
1428 DUMP_REG(DC_DISP_CURSOR_START_ADDR);
1429 DUMP_REG(DC_DISP_CURSOR_START_ADDR_NS);
1430 DUMP_REG(DC_DISP_CURSOR_POSITION);
1431 DUMP_REG(DC_DISP_CURSOR_POSITION_NS);
1432 DUMP_REG(DC_DISP_INIT_SEQ_CONTROL);
1433 DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_A);
1434 DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_B);
1435 DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_C);
1436 DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_D);
1437 DUMP_REG(DC_DISP_DC_MCCIF_FIFOCTRL);
1438 DUMP_REG(DC_DISP_MCCIF_DISPLAY0A_HYST);
1439 DUMP_REG(DC_DISP_MCCIF_DISPLAY0B_HYST);
1440 DUMP_REG(DC_DISP_MCCIF_DISPLAY1A_HYST);
1441 DUMP_REG(DC_DISP_MCCIF_DISPLAY1B_HYST);
1442 DUMP_REG(DC_DISP_DAC_CRT_CTRL);
1443 DUMP_REG(DC_DISP_DISP_MISC_CONTROL);
1444 DUMP_REG(DC_DISP_SD_CONTROL);
1445 DUMP_REG(DC_DISP_SD_CSC_COEFF);
1446 DUMP_REG(DC_DISP_SD_LUT(0));
1447 DUMP_REG(DC_DISP_SD_LUT(1));
1448 DUMP_REG(DC_DISP_SD_LUT(2));
1449 DUMP_REG(DC_DISP_SD_LUT(3));
1450 DUMP_REG(DC_DISP_SD_LUT(4));
1451 DUMP_REG(DC_DISP_SD_LUT(5));
1452 DUMP_REG(DC_DISP_SD_LUT(6));
1453 DUMP_REG(DC_DISP_SD_LUT(7));
1454 DUMP_REG(DC_DISP_SD_LUT(8));
1455 DUMP_REG(DC_DISP_SD_FLICKER_CONTROL);
1456 DUMP_REG(DC_DISP_DC_PIXEL_COUNT);
1457 DUMP_REG(DC_DISP_SD_HISTOGRAM(0));
1458 DUMP_REG(DC_DISP_SD_HISTOGRAM(1));
1459 DUMP_REG(DC_DISP_SD_HISTOGRAM(2));
1460 DUMP_REG(DC_DISP_SD_HISTOGRAM(3));
1461 DUMP_REG(DC_DISP_SD_HISTOGRAM(4));
1462 DUMP_REG(DC_DISP_SD_HISTOGRAM(5));
1463 DUMP_REG(DC_DISP_SD_HISTOGRAM(6));
1464 DUMP_REG(DC_DISP_SD_HISTOGRAM(7));
1465 DUMP_REG(DC_DISP_SD_BL_TF(0));
1466 DUMP_REG(DC_DISP_SD_BL_TF(1));
1467 DUMP_REG(DC_DISP_SD_BL_TF(2));
1468 DUMP_REG(DC_DISP_SD_BL_TF(3));
1469 DUMP_REG(DC_DISP_SD_BL_CONTROL);
1470 DUMP_REG(DC_DISP_SD_HW_K_VALUES);
1471 DUMP_REG(DC_DISP_SD_MAN_K_VALUES);
Thierry Redinge6876512013-12-20 13:58:33 +01001472 DUMP_REG(DC_DISP_CURSOR_START_ADDR_HI);
1473 DUMP_REG(DC_DISP_BLEND_CURSOR_CONTROL);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001474 DUMP_REG(DC_WIN_WIN_OPTIONS);
1475 DUMP_REG(DC_WIN_BYTE_SWAP);
1476 DUMP_REG(DC_WIN_BUFFER_CONTROL);
1477 DUMP_REG(DC_WIN_COLOR_DEPTH);
1478 DUMP_REG(DC_WIN_POSITION);
1479 DUMP_REG(DC_WIN_SIZE);
1480 DUMP_REG(DC_WIN_PRESCALED_SIZE);
1481 DUMP_REG(DC_WIN_H_INITIAL_DDA);
1482 DUMP_REG(DC_WIN_V_INITIAL_DDA);
1483 DUMP_REG(DC_WIN_DDA_INC);
1484 DUMP_REG(DC_WIN_LINE_STRIDE);
1485 DUMP_REG(DC_WIN_BUF_STRIDE);
1486 DUMP_REG(DC_WIN_UV_BUF_STRIDE);
1487 DUMP_REG(DC_WIN_BUFFER_ADDR_MODE);
1488 DUMP_REG(DC_WIN_DV_CONTROL);
1489 DUMP_REG(DC_WIN_BLEND_NOKEY);
1490 DUMP_REG(DC_WIN_BLEND_1WIN);
1491 DUMP_REG(DC_WIN_BLEND_2WIN_X);
1492 DUMP_REG(DC_WIN_BLEND_2WIN_Y);
Thierry Redingf34bc782012-11-04 21:47:13 +01001493 DUMP_REG(DC_WIN_BLEND_3WIN_XY);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001494 DUMP_REG(DC_WIN_HP_FETCH_CONTROL);
1495 DUMP_REG(DC_WINBUF_START_ADDR);
1496 DUMP_REG(DC_WINBUF_START_ADDR_NS);
1497 DUMP_REG(DC_WINBUF_START_ADDR_U);
1498 DUMP_REG(DC_WINBUF_START_ADDR_U_NS);
1499 DUMP_REG(DC_WINBUF_START_ADDR_V);
1500 DUMP_REG(DC_WINBUF_START_ADDR_V_NS);
1501 DUMP_REG(DC_WINBUF_ADDR_H_OFFSET);
1502 DUMP_REG(DC_WINBUF_ADDR_H_OFFSET_NS);
1503 DUMP_REG(DC_WINBUF_ADDR_V_OFFSET);
1504 DUMP_REG(DC_WINBUF_ADDR_V_OFFSET_NS);
1505 DUMP_REG(DC_WINBUF_UFLOW_STATUS);
1506 DUMP_REG(DC_WINBUF_AD_UFLOW_STATUS);
1507 DUMP_REG(DC_WINBUF_BD_UFLOW_STATUS);
1508 DUMP_REG(DC_WINBUF_CD_UFLOW_STATUS);
1509
1510#undef DUMP_REG
1511
1512 return 0;
1513}
1514
1515static struct drm_info_list debugfs_files[] = {
1516 { "regs", tegra_dc_show_regs, 0, NULL },
1517};
1518
1519static int tegra_dc_debugfs_init(struct tegra_dc *dc, struct drm_minor *minor)
1520{
1521 unsigned int i;
1522 char *name;
1523 int err;
1524
1525 name = kasprintf(GFP_KERNEL, "dc.%d", dc->pipe);
1526 dc->debugfs = debugfs_create_dir(name, minor->debugfs_root);
1527 kfree(name);
1528
1529 if (!dc->debugfs)
1530 return -ENOMEM;
1531
1532 dc->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files),
1533 GFP_KERNEL);
1534 if (!dc->debugfs_files) {
1535 err = -ENOMEM;
1536 goto remove;
1537 }
1538
1539 for (i = 0; i < ARRAY_SIZE(debugfs_files); i++)
1540 dc->debugfs_files[i].data = dc;
1541
1542 err = drm_debugfs_create_files(dc->debugfs_files,
1543 ARRAY_SIZE(debugfs_files),
1544 dc->debugfs, minor);
1545 if (err < 0)
1546 goto free;
1547
1548 dc->minor = minor;
1549
1550 return 0;
1551
1552free:
1553 kfree(dc->debugfs_files);
1554 dc->debugfs_files = NULL;
1555remove:
1556 debugfs_remove(dc->debugfs);
1557 dc->debugfs = NULL;
1558
1559 return err;
1560}
1561
1562static int tegra_dc_debugfs_exit(struct tegra_dc *dc)
1563{
1564 drm_debugfs_remove_files(dc->debugfs_files, ARRAY_SIZE(debugfs_files),
1565 dc->minor);
1566 dc->minor = NULL;
1567
1568 kfree(dc->debugfs_files);
1569 dc->debugfs_files = NULL;
1570
1571 debugfs_remove(dc->debugfs);
1572 dc->debugfs = NULL;
1573
1574 return 0;
1575}
1576
Thierry Reding53fa7f72013-09-24 15:35:40 +02001577static int tegra_dc_init(struct host1x_client *client)
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001578{
Thierry Reding9910f5c2014-05-22 09:57:15 +02001579 struct drm_device *drm = dev_get_drvdata(client->parent);
Thierry Reding776dc382013-10-14 14:43:22 +02001580 struct tegra_dc *dc = host1x_client_to_dc(client);
Thierry Redingd1f3e1e2014-07-11 08:29:14 +02001581 struct tegra_drm *tegra = drm->dev_private;
Thierry Redingc7679302014-10-21 13:51:53 +02001582 struct drm_plane *primary = NULL;
1583 struct drm_plane *cursor = NULL;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001584 int err;
1585
Thierry Redingdf06b752014-06-26 21:41:53 +02001586 if (tegra->domain) {
1587 err = iommu_attach_device(tegra->domain, dc->dev);
1588 if (err < 0) {
1589 dev_err(dc->dev, "failed to attach to domain: %d\n",
1590 err);
1591 return err;
1592 }
1593
1594 dc->domain = tegra->domain;
1595 }
1596
Thierry Redingc7679302014-10-21 13:51:53 +02001597 primary = tegra_dc_primary_plane_create(drm, dc);
1598 if (IS_ERR(primary)) {
1599 err = PTR_ERR(primary);
1600 goto cleanup;
1601 }
1602
1603 if (dc->soc->supports_cursor) {
1604 cursor = tegra_dc_cursor_plane_create(drm, dc);
1605 if (IS_ERR(cursor)) {
1606 err = PTR_ERR(cursor);
1607 goto cleanup;
1608 }
1609 }
1610
1611 err = drm_crtc_init_with_planes(drm, &dc->base, primary, cursor,
1612 &tegra_crtc_funcs);
1613 if (err < 0)
1614 goto cleanup;
1615
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001616 drm_mode_crtc_set_gamma_size(&dc->base, 256);
1617 drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs);
1618
Thierry Redingd1f3e1e2014-07-11 08:29:14 +02001619 /*
1620 * Keep track of the minimum pitch alignment across all display
1621 * controllers.
1622 */
1623 if (dc->soc->pitch_align > tegra->pitch_align)
1624 tegra->pitch_align = dc->soc->pitch_align;
1625
Thierry Reding9910f5c2014-05-22 09:57:15 +02001626 err = tegra_dc_rgb_init(drm, dc);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001627 if (err < 0 && err != -ENODEV) {
1628 dev_err(dc->dev, "failed to initialize RGB output: %d\n", err);
Thierry Redingc7679302014-10-21 13:51:53 +02001629 goto cleanup;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001630 }
1631
Thierry Reding9910f5c2014-05-22 09:57:15 +02001632 err = tegra_dc_add_planes(drm, dc);
Thierry Redingf34bc782012-11-04 21:47:13 +01001633 if (err < 0)
Thierry Redingc7679302014-10-21 13:51:53 +02001634 goto cleanup;
Thierry Redingf34bc782012-11-04 21:47:13 +01001635
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001636 if (IS_ENABLED(CONFIG_DEBUG_FS)) {
Thierry Reding9910f5c2014-05-22 09:57:15 +02001637 err = tegra_dc_debugfs_init(dc, drm->primary);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001638 if (err < 0)
1639 dev_err(dc->dev, "debugfs setup failed: %d\n", err);
1640 }
1641
Thierry Reding6e5ff992012-11-28 11:45:47 +01001642 err = devm_request_irq(dc->dev, dc->irq, tegra_dc_irq, 0,
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001643 dev_name(dc->dev), dc);
1644 if (err < 0) {
1645 dev_err(dc->dev, "failed to request IRQ#%u: %d\n", dc->irq,
1646 err);
Thierry Redingc7679302014-10-21 13:51:53 +02001647 goto cleanup;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001648 }
1649
1650 return 0;
Thierry Redingc7679302014-10-21 13:51:53 +02001651
1652cleanup:
1653 if (cursor)
1654 drm_plane_cleanup(cursor);
1655
1656 if (primary)
1657 drm_plane_cleanup(primary);
1658
1659 if (tegra->domain) {
1660 iommu_detach_device(tegra->domain, dc->dev);
1661 dc->domain = NULL;
1662 }
1663
1664 return err;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001665}
1666
Thierry Reding53fa7f72013-09-24 15:35:40 +02001667static int tegra_dc_exit(struct host1x_client *client)
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001668{
Thierry Reding776dc382013-10-14 14:43:22 +02001669 struct tegra_dc *dc = host1x_client_to_dc(client);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001670 int err;
1671
1672 devm_free_irq(dc->dev, dc->irq, dc);
1673
1674 if (IS_ENABLED(CONFIG_DEBUG_FS)) {
1675 err = tegra_dc_debugfs_exit(dc);
1676 if (err < 0)
1677 dev_err(dc->dev, "debugfs cleanup failed: %d\n", err);
1678 }
1679
1680 err = tegra_dc_rgb_exit(dc);
1681 if (err) {
1682 dev_err(dc->dev, "failed to shutdown RGB output: %d\n", err);
1683 return err;
1684 }
1685
Thierry Redingdf06b752014-06-26 21:41:53 +02001686 if (dc->domain) {
1687 iommu_detach_device(dc->domain, dc->dev);
1688 dc->domain = NULL;
1689 }
1690
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001691 return 0;
1692}
1693
1694static const struct host1x_client_ops dc_client_ops = {
Thierry Reding53fa7f72013-09-24 15:35:40 +02001695 .init = tegra_dc_init,
1696 .exit = tegra_dc_exit,
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001697};
1698
Thierry Reding8620fc62013-12-12 11:03:59 +01001699static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
Thierry Reding42d06592014-12-08 15:45:39 +01001700 .supports_border_color = true,
Thierry Reding8620fc62013-12-12 11:03:59 +01001701 .supports_interlacing = false,
Thierry Redinge6876512013-12-20 13:58:33 +01001702 .supports_cursor = false,
Thierry Redingc134f012014-06-03 14:48:12 +02001703 .supports_block_linear = false,
Thierry Redingd1f3e1e2014-07-11 08:29:14 +02001704 .pitch_align = 8,
Thierry Reding9c012702014-07-07 15:32:53 +02001705 .has_powergate = false,
Thierry Reding8620fc62013-12-12 11:03:59 +01001706};
1707
1708static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
Thierry Reding42d06592014-12-08 15:45:39 +01001709 .supports_border_color = true,
Thierry Reding8620fc62013-12-12 11:03:59 +01001710 .supports_interlacing = false,
Thierry Redinge6876512013-12-20 13:58:33 +01001711 .supports_cursor = false,
Thierry Redingc134f012014-06-03 14:48:12 +02001712 .supports_block_linear = false,
Thierry Redingd1f3e1e2014-07-11 08:29:14 +02001713 .pitch_align = 8,
Thierry Reding9c012702014-07-07 15:32:53 +02001714 .has_powergate = false,
Thierry Redingd1f3e1e2014-07-11 08:29:14 +02001715};
1716
1717static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
Thierry Reding42d06592014-12-08 15:45:39 +01001718 .supports_border_color = true,
Thierry Redingd1f3e1e2014-07-11 08:29:14 +02001719 .supports_interlacing = false,
1720 .supports_cursor = false,
1721 .supports_block_linear = false,
1722 .pitch_align = 64,
Thierry Reding9c012702014-07-07 15:32:53 +02001723 .has_powergate = true,
Thierry Reding8620fc62013-12-12 11:03:59 +01001724};
1725
1726static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
Thierry Reding42d06592014-12-08 15:45:39 +01001727 .supports_border_color = false,
Thierry Reding8620fc62013-12-12 11:03:59 +01001728 .supports_interlacing = true,
Thierry Redinge6876512013-12-20 13:58:33 +01001729 .supports_cursor = true,
Thierry Redingc134f012014-06-03 14:48:12 +02001730 .supports_block_linear = true,
Thierry Redingd1f3e1e2014-07-11 08:29:14 +02001731 .pitch_align = 64,
Thierry Reding9c012702014-07-07 15:32:53 +02001732 .has_powergate = true,
Thierry Reding8620fc62013-12-12 11:03:59 +01001733};
1734
1735static const struct of_device_id tegra_dc_of_match[] = {
1736 {
1737 .compatible = "nvidia,tegra124-dc",
1738 .data = &tegra124_dc_soc_info,
1739 }, {
Thierry Reding9c012702014-07-07 15:32:53 +02001740 .compatible = "nvidia,tegra114-dc",
1741 .data = &tegra114_dc_soc_info,
1742 }, {
Thierry Reding8620fc62013-12-12 11:03:59 +01001743 .compatible = "nvidia,tegra30-dc",
1744 .data = &tegra30_dc_soc_info,
1745 }, {
1746 .compatible = "nvidia,tegra20-dc",
1747 .data = &tegra20_dc_soc_info,
1748 }, {
1749 /* sentinel */
1750 }
1751};
Stephen Warrenef707282014-06-18 16:21:55 -06001752MODULE_DEVICE_TABLE(of, tegra_dc_of_match);
Thierry Reding8620fc62013-12-12 11:03:59 +01001753
Thierry Reding13411dd2014-01-09 17:08:36 +01001754static int tegra_dc_parse_dt(struct tegra_dc *dc)
1755{
1756 struct device_node *np;
1757 u32 value = 0;
1758 int err;
1759
1760 err = of_property_read_u32(dc->dev->of_node, "nvidia,head", &value);
1761 if (err < 0) {
1762 dev_err(dc->dev, "missing \"nvidia,head\" property\n");
1763
1764 /*
1765 * If the nvidia,head property isn't present, try to find the
1766 * correct head number by looking up the position of this
1767 * display controller's node within the device tree. Assuming
1768 * that the nodes are ordered properly in the DTS file and
1769 * that the translation into a flattened device tree blob
1770 * preserves that ordering this will actually yield the right
1771 * head number.
1772 *
1773 * If those assumptions don't hold, this will still work for
1774 * cases where only a single display controller is used.
1775 */
1776 for_each_matching_node(np, tegra_dc_of_match) {
1777 if (np == dc->dev->of_node)
1778 break;
1779
1780 value++;
1781 }
1782 }
1783
1784 dc->pipe = value;
1785
1786 return 0;
1787}
1788
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001789static int tegra_dc_probe(struct platform_device *pdev)
1790{
Thierry Reding8620fc62013-12-12 11:03:59 +01001791 const struct of_device_id *id;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001792 struct resource *regs;
1793 struct tegra_dc *dc;
1794 int err;
1795
1796 dc = devm_kzalloc(&pdev->dev, sizeof(*dc), GFP_KERNEL);
1797 if (!dc)
1798 return -ENOMEM;
1799
Thierry Reding8620fc62013-12-12 11:03:59 +01001800 id = of_match_node(tegra_dc_of_match, pdev->dev.of_node);
1801 if (!id)
1802 return -ENODEV;
1803
Thierry Reding6e5ff992012-11-28 11:45:47 +01001804 spin_lock_init(&dc->lock);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001805 INIT_LIST_HEAD(&dc->list);
1806 dc->dev = &pdev->dev;
Thierry Reding8620fc62013-12-12 11:03:59 +01001807 dc->soc = id->data;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001808
Thierry Reding13411dd2014-01-09 17:08:36 +01001809 err = tegra_dc_parse_dt(dc);
1810 if (err < 0)
1811 return err;
1812
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001813 dc->clk = devm_clk_get(&pdev->dev, NULL);
1814 if (IS_ERR(dc->clk)) {
1815 dev_err(&pdev->dev, "failed to get clock\n");
1816 return PTR_ERR(dc->clk);
1817 }
1818
Stephen Warrenca480802013-11-06 16:20:54 -07001819 dc->rst = devm_reset_control_get(&pdev->dev, "dc");
1820 if (IS_ERR(dc->rst)) {
1821 dev_err(&pdev->dev, "failed to get reset\n");
1822 return PTR_ERR(dc->rst);
1823 }
1824
Thierry Reding9c012702014-07-07 15:32:53 +02001825 if (dc->soc->has_powergate) {
1826 if (dc->pipe == 0)
1827 dc->powergate = TEGRA_POWERGATE_DIS;
1828 else
1829 dc->powergate = TEGRA_POWERGATE_DISB;
1830
1831 err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk,
1832 dc->rst);
1833 if (err < 0) {
1834 dev_err(&pdev->dev, "failed to power partition: %d\n",
1835 err);
1836 return err;
1837 }
1838 } else {
1839 err = clk_prepare_enable(dc->clk);
1840 if (err < 0) {
1841 dev_err(&pdev->dev, "failed to enable clock: %d\n",
1842 err);
1843 return err;
1844 }
1845
1846 err = reset_control_deassert(dc->rst);
1847 if (err < 0) {
1848 dev_err(&pdev->dev, "failed to deassert reset: %d\n",
1849 err);
1850 return err;
1851 }
1852 }
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001853
1854 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Thierry Redingd4ed6022013-01-21 11:09:02 +01001855 dc->regs = devm_ioremap_resource(&pdev->dev, regs);
1856 if (IS_ERR(dc->regs))
1857 return PTR_ERR(dc->regs);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001858
1859 dc->irq = platform_get_irq(pdev, 0);
1860 if (dc->irq < 0) {
1861 dev_err(&pdev->dev, "failed to get IRQ\n");
1862 return -ENXIO;
1863 }
1864
Thierry Reding776dc382013-10-14 14:43:22 +02001865 INIT_LIST_HEAD(&dc->client.list);
1866 dc->client.ops = &dc_client_ops;
1867 dc->client.dev = &pdev->dev;
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001868
1869 err = tegra_dc_rgb_probe(dc);
1870 if (err < 0 && err != -ENODEV) {
1871 dev_err(&pdev->dev, "failed to probe RGB output: %d\n", err);
1872 return err;
1873 }
1874
Thierry Reding776dc382013-10-14 14:43:22 +02001875 err = host1x_client_register(&dc->client);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001876 if (err < 0) {
1877 dev_err(&pdev->dev, "failed to register host1x client: %d\n",
1878 err);
1879 return err;
1880 }
1881
1882 platform_set_drvdata(pdev, dc);
1883
1884 return 0;
1885}
1886
1887static int tegra_dc_remove(struct platform_device *pdev)
1888{
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001889 struct tegra_dc *dc = platform_get_drvdata(pdev);
1890 int err;
1891
Thierry Reding776dc382013-10-14 14:43:22 +02001892 err = host1x_client_unregister(&dc->client);
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001893 if (err < 0) {
1894 dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
1895 err);
1896 return err;
1897 }
1898
Thierry Reding59d29c02013-10-14 14:26:42 +02001899 err = tegra_dc_rgb_remove(dc);
1900 if (err < 0) {
1901 dev_err(&pdev->dev, "failed to remove RGB output: %d\n", err);
1902 return err;
1903 }
1904
Thierry Reding5482d752014-07-11 08:39:03 +02001905 reset_control_assert(dc->rst);
Thierry Reding9c012702014-07-07 15:32:53 +02001906
1907 if (dc->soc->has_powergate)
1908 tegra_powergate_power_off(dc->powergate);
1909
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001910 clk_disable_unprepare(dc->clk);
1911
1912 return 0;
1913}
1914
Thierry Redingd8f4a9e2012-11-15 21:28:22 +00001915struct platform_driver tegra_dc_driver = {
1916 .driver = {
1917 .name = "tegra-dc",
1918 .owner = THIS_MODULE,
1919 .of_match_table = tegra_dc_of_match,
1920 },
1921 .probe = tegra_dc_probe,
1922 .remove = tegra_dc_remove,
1923};