]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/nvidia/drm2/tegra_dc.c
MFV r368207:
[FreeBSD/FreeBSD.git] / sys / arm / nvidia / drm2 / tegra_dc.c
1 /*-
2  * Copyright (c) 2015 Michal Meloun
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/bus.h>
33 #include <sys/gpio.h>
34 #include <sys/kernel.h>
35 #include <sys/module.h>
36 #include <sys/malloc.h>
37 #include <sys/rman.h>
38 #include <sys/sysctl.h>
39
40 #include <machine/bus.h>
41
42 #include <dev/extres/clk/clk.h>
43 #include <dev/extres/hwreset/hwreset.h>
44 #include <dev/drm2/drmP.h>
45 #include <dev/drm2/drm_crtc_helper.h>
46 #include <dev/drm2/drm_fb_helper.h>
47 #include <dev/drm2/drm_fixed.h>
48 #include <dev/ofw/ofw_bus.h>
49 #include <dev/ofw/ofw_bus_subr.h>
50
51 #include <arm/nvidia/drm2/tegra_dc_reg.h>
52 #include <arm/nvidia/drm2/tegra_drm.h>
53 #include <arm/nvidia/tegra_pmc.h>
54
55 #include "tegra_drm_if.h"
56 #include "tegra_dc_if.h"
57
58 #define WR4(_sc, _r, _v)        bus_write_4((_sc)->mem_res, 4 * (_r), (_v))
59 #define RD4(_sc, _r)            bus_read_4((_sc)->mem_res, 4 * (_r))
60
61 #define LOCK(_sc)               mtx_lock(&(_sc)->mtx)
62 #define UNLOCK(_sc)             mtx_unlock(&(_sc)->mtx)
63 #define SLEEP(_sc, timeout)                                             \
64         mtx_sleep(sc, &sc->mtx, 0, "tegra_dc_wait", timeout);
65 #define LOCK_INIT(_sc)                                                  \
66         mtx_init(&_sc->mtx, device_get_nameunit(_sc->dev), "tegra_dc", MTX_DEF)
67 #define LOCK_DESTROY(_sc)       mtx_destroy(&_sc->mtx)
68 #define ASSERT_LOCKED(_sc)      mtx_assert(&_sc->mtx, MA_OWNED)
69 #define ASSERT_UNLOCKED(_sc)    mtx_assert(&_sc->mtx, MA_NOTOWNED)
70
71 #define SYNCPT_VBLANK0 26
72 #define SYNCPT_VBLANK1 27
73
74 #define DC_MAX_PLANES 2         /* Maximum planes */
75
76 /* DRM Formats supported by DC */
77 /* XXXX expand me */
78 static uint32_t dc_plane_formats[] = {
79         DRM_FORMAT_XBGR8888,
80         DRM_FORMAT_XRGB8888,
81         DRM_FORMAT_RGB565,
82         DRM_FORMAT_UYVY,
83         DRM_FORMAT_YUYV,
84         DRM_FORMAT_YUV420,
85         DRM_FORMAT_YUV422,
86 };
87
88 /* Complete description of one window (plane) */
89 struct dc_window {
90         /* Source (in framebuffer) rectangle, in pixels */
91         u_int                   src_x;
92         u_int                   src_y;
93         u_int                   src_w;
94         u_int                   src_h;
95
96         /* Destination (on display) rectangle, in pixels */
97         u_int                   dst_x;
98         u_int                   dst_y;
99         u_int                   dst_w;
100         u_int                   dst_h;
101
102         /* Parsed pixel format */
103         u_int                   bits_per_pixel;
104         bool                    is_yuv;         /* any YUV mode */
105         bool                    is_yuv_planar;  /* planar YUV mode */
106         uint32_t                color_mode;     /* DC_WIN_COLOR_DEPTH */
107         uint32_t                swap;           /* DC_WIN_BYTE_SWAP */
108         uint32_t                surface_kind;   /* DC_WINBUF_SURFACE_KIND */
109         uint32_t                block_height;   /* DC_WINBUF_SURFACE_KIND */
110
111         /* Parsed flipping, rotation is not supported for pitched modes */
112         bool                    flip_x;         /* inverted X-axis */
113         bool                    flip_y;         /* inverted Y-axis */
114         bool                    transpose_xy;   /* swap X and Y-axis */
115
116         /* Color planes base addresses and strides */
117         bus_size_t              base[3];
118         uint32_t                stride[3];      /* stride[2] isn't used by HW */
119 };
120
121 struct dc_softc {
122         device_t                dev;
123         struct resource         *mem_res;
124         struct resource         *irq_res;
125         void                    *irq_ih;
126         struct mtx              mtx;
127
128         clk_t                   clk_parent;
129         clk_t                   clk_dc;
130         hwreset_t               hwreset_dc;
131
132         int                     pitch_align;
133
134         struct tegra_crtc       tegra_crtc;
135         struct drm_pending_vblank_event *event;
136         struct drm_gem_object   *cursor_gem;
137 };
138
139 static struct ofw_compat_data compat_data[] = {
140         {"nvidia,tegra124-dc",  1},
141         {NULL,                  0},
142 };
143
144 /* Convert standard drm pixel format to tegra windows parameters. */
145 static int
146 dc_parse_drm_format(struct tegra_fb *fb, struct dc_window *win)
147 {
148         struct tegra_bo *bo;
149         uint32_t cm;
150         uint32_t sw;
151         bool is_yuv, is_yuv_planar;
152         int nplanes, i;
153
154         switch (fb->drm_fb.pixel_format) {
155         case DRM_FORMAT_XBGR8888:
156                 sw = BYTE_SWAP(NOSWAP);
157                 cm = WIN_COLOR_DEPTH_R8G8B8A8;
158                 is_yuv = false;
159                 is_yuv_planar = false;
160                 break;
161
162         case DRM_FORMAT_XRGB8888:
163                 sw = BYTE_SWAP(NOSWAP);
164                 cm = WIN_COLOR_DEPTH_B8G8R8A8;
165                 is_yuv = false;
166                 is_yuv_planar = false;
167                 break;
168
169         case DRM_FORMAT_RGB565:
170                 sw = BYTE_SWAP(NOSWAP);
171                 cm = WIN_COLOR_DEPTH_B5G6R5;
172                 is_yuv = false;
173                 is_yuv_planar = false;
174                 break;
175
176         case DRM_FORMAT_UYVY:
177                 sw = BYTE_SWAP(NOSWAP);
178                 cm = WIN_COLOR_DEPTH_YCbCr422;
179                 is_yuv = true;
180                 is_yuv_planar = false;
181                 break;
182
183         case DRM_FORMAT_YUYV:
184                 sw = BYTE_SWAP(SWAP2);
185                 cm = WIN_COLOR_DEPTH_YCbCr422;
186                 is_yuv = true;
187                 is_yuv_planar = false;
188                 break;
189
190         case DRM_FORMAT_YUV420:
191                 sw = BYTE_SWAP(NOSWAP);
192                 cm = WIN_COLOR_DEPTH_YCbCr420P;
193                 is_yuv = true;
194                 is_yuv_planar = true;
195                 break;
196
197         case DRM_FORMAT_YUV422:
198                 sw = BYTE_SWAP(NOSWAP);
199                 cm = WIN_COLOR_DEPTH_YCbCr422P;
200                 is_yuv = true;
201                 is_yuv_planar = true;
202                 break;
203
204         default:
205                 /* Unsupported format */
206                 return (-EINVAL);
207         }
208
209         /* Basic check of arguments. */
210         switch (fb->rotation) {
211         case 0:
212         case 180:
213                 break;
214
215         case 90:                /* Rotation is supported only */
216         case 270:               /*  for block linear surfaces */
217                 if (!fb->block_linear)
218                         return (-EINVAL);
219                 break;
220
221         default:
222                 return (-EINVAL);
223         }
224         /* XXX Add more checks (sizes, scaling...) */
225
226         if (win == NULL)
227                 return (0);
228
229         win->surface_kind =
230             fb->block_linear ? SURFACE_KIND_BL_16B2: SURFACE_KIND_PITCH;
231         win->block_height = fb->block_height;
232         switch (fb->rotation) {
233         case 0:                                 /* (0,0,0) */
234                 win->transpose_xy = false;
235                 win->flip_x = false;
236                 win->flip_y = false;
237                 break;
238
239         case 90:                                /* (1,0,1) */
240                 win->transpose_xy = true;
241                 win->flip_x = false;
242                 win->flip_y = true;
243                 break;
244
245         case 180:                               /* (0,1,1) */
246                 win->transpose_xy = false;
247                 win->flip_x = true;
248                 win->flip_y = true;
249                 break;
250
251         case 270:                               /* (1,1,0) */
252                 win->transpose_xy = true;
253                 win->flip_x = true;
254                 win->flip_y = false;
255                 break;
256         }
257         win->flip_x ^= fb->flip_x;
258         win->flip_y ^= fb->flip_y;
259
260         win->color_mode = cm;
261         win->swap = sw;
262         win->bits_per_pixel = fb->drm_fb.bits_per_pixel;
263         win->is_yuv = is_yuv;
264         win->is_yuv_planar = is_yuv_planar;
265
266         nplanes = drm_format_num_planes(fb->drm_fb.pixel_format);
267         for (i = 0; i < nplanes; i++) {
268                 bo = fb->planes[i];
269                 win->base[i] = bo->pbase + fb->drm_fb.offsets[i];
270                 win->stride[i] = fb->drm_fb.pitches[i];
271         }
272         return (0);
273 }
274
275 /*
276  * Scaling functions.
277  *
278  * It's unclear if we want/must program the fractional portion
279  * (aka bias) of init_dda registers, mainly when mirrored axis
280  * modes are used.
281  * For now, we use 1.0 as recommended by TRM.
282  */
283 static inline uint32_t
284 dc_scaling_init(uint32_t start)
285 {
286
287         return (1 << 12);
288 }
289
290 static inline uint32_t
291 dc_scaling_incr(uint32_t src, uint32_t dst, uint32_t maxscale)
292 {
293         uint32_t val;
294
295         val = (src - 1) << 12 ; /* 4.12 fixed float */
296         val /= (dst - 1);
297         if (val  > (maxscale << 12))
298                 val = maxscale << 12;
299         return val;
300 }
301
302 /* -------------------------------------------------------------------
303  *
304  *    HW Access.
305  *
306  */
307
308 /*
309  * Setup pixel clock.
310  * Minimal frequency is pixel clock, but output is free to select
311  * any higher.
312  */
313 static int
314 dc_setup_clk(struct dc_softc *sc, struct drm_crtc *crtc,
315     struct drm_display_mode *mode, uint32_t *div)
316 {
317         uint64_t pclk, freq;
318         struct tegra_drm_encoder *output;
319         struct drm_encoder *encoder;
320         long rv;
321
322         pclk = mode->clock * 1000;
323
324         /* Find attached encoder */
325         output = NULL;
326         list_for_each_entry(encoder, &crtc->dev->mode_config.encoder_list,
327             head) {
328                 if (encoder->crtc == crtc) {
329                         output = container_of(encoder, struct tegra_drm_encoder,
330                             encoder);
331                         break;
332                 }
333         }
334         if (output == NULL)
335                 return (-ENODEV);
336
337         if (output->setup_clock == NULL)
338                 panic("Output have not setup_clock function.\n");
339         rv = output->setup_clock(output, sc->clk_dc, pclk);
340         if (rv != 0) {
341                 device_printf(sc->dev, "Cannot setup pixel clock: %llu\n",
342                     pclk);
343                 return (rv);
344         }
345
346         rv = clk_get_freq(sc->clk_dc, &freq);
347         *div = (freq * 2 / pclk) - 2;
348
349         DRM_DEBUG_KMS("frequency: %llu, DC divider: %u\n", freq, *div);
350
351         return 0;
352 }
353
354 static void
355 dc_setup_window(struct dc_softc *sc, unsigned int index, struct dc_window *win)
356 {
357         uint32_t h_offset, v_offset, h_size, v_size, bpp;
358         uint32_t h_init_dda, v_init_dda, h_incr_dda, v_incr_dda;
359         uint32_t val;
360
361 #ifdef DMR_DEBUG_WINDOW
362         printf("%s window: %d\n", __func__, index);
363         printf("  src: x: %d, y: %d, w: %d, h: %d\n",
364            win->src_x, win->src_y, win->src_w, win->src_h);
365         printf("  dst: x: %d, y: %d, w: %d, h: %d\n",
366            win->dst_x, win->dst_y, win->dst_w, win->dst_h);
367         printf("  bpp: %d, color_mode: %d, swap: %d\n",
368            win->bits_per_pixel, win->color_mode, win->swap);
369 #endif
370
371         if (win->is_yuv)
372                 bpp = win->is_yuv_planar ? 1 : 2;
373         else
374                 bpp = (win->bits_per_pixel + 7) / 8;
375
376         if (!win->transpose_xy) {
377                 h_size = win->src_w * bpp;
378                 v_size = win->src_h;
379         } else {
380                 h_size = win->src_h * bpp;
381                 v_size = win->src_w;
382         }
383
384         h_offset = win->src_x * bpp;
385         v_offset = win->src_y;
386         if (win->flip_x) {
387                 h_offset += win->src_w * bpp - 1;
388         }
389         if (win->flip_y)
390                 v_offset += win->src_h - 1;
391
392         /* Adjust offsets for planar yuv modes */
393         if (win->is_yuv_planar) {
394                 h_offset &= ~1;
395                 if (win->flip_x )
396                         h_offset |= 1;
397                 v_offset &= ~1;
398                 if (win->flip_y )
399                         v_offset |= 1;
400         }
401
402         /* Setup scaling. */
403         if (!win->transpose_xy) {
404                 h_init_dda = dc_scaling_init(win->src_x);
405                 v_init_dda = dc_scaling_init(win->src_y);
406                 h_incr_dda = dc_scaling_incr(win->src_w, win->dst_w, 4);
407                 v_incr_dda = dc_scaling_incr(win->src_h, win->dst_h, 15);
408         } else {
409                 h_init_dda =  dc_scaling_init(win->src_y);
410                 v_init_dda =  dc_scaling_init(win->src_x);
411                 h_incr_dda = dc_scaling_incr(win->src_h, win->dst_h, 4);
412                 v_incr_dda = dc_scaling_incr(win->src_w, win->dst_w, 15);
413         }
414 #ifdef DMR_DEBUG_WINDOW
415         printf("\n");
416         printf("  bpp: %d, size: h: %d v: %d, offset: h:%d v: %d\n",
417            bpp, h_size, v_size, h_offset, v_offset);
418         printf("  init_dda: h: %d v: %d, incr_dda: h: %d v: %d\n",
419            h_init_dda, v_init_dda, h_incr_dda, v_incr_dda);
420 #endif
421
422         LOCK(sc);
423
424         /* Select target window  */
425         val = WINDOW_A_SELECT << index;
426         WR4(sc, DC_CMD_DISPLAY_WINDOW_HEADER, val);
427
428         /* Sizes */
429         WR4(sc, DC_WIN_POSITION, WIN_POSITION(win->dst_x, win->dst_y));
430         WR4(sc, DC_WIN_SIZE, WIN_SIZE(win->dst_w, win->dst_h));
431         WR4(sc, DC_WIN_PRESCALED_SIZE, WIN_PRESCALED_SIZE(h_size, v_size));
432
433         /* DDA */
434         WR4(sc, DC_WIN_DDA_INCREMENT,
435             WIN_DDA_INCREMENT(h_incr_dda, v_incr_dda));
436         WR4(sc, DC_WIN_H_INITIAL_DDA, h_init_dda);
437         WR4(sc, DC_WIN_V_INITIAL_DDA, v_init_dda);
438
439         /* Color planes base addresses and strides */
440         WR4(sc, DC_WINBUF_START_ADDR, win->base[0]);
441         if (win->is_yuv_planar) {
442                 WR4(sc, DC_WINBUF_START_ADDR_U, win->base[1]);
443                 WR4(sc, DC_WINBUF_START_ADDR_V, win->base[2]);
444                 WR4(sc, DC_WIN_LINE_STRIDE,
445                      win->stride[1] << 16 | win->stride[0]);
446         } else {
447                 WR4(sc, DC_WIN_LINE_STRIDE, win->stride[0]);
448         }
449
450         /* Offsets for rotation and axis flip */
451         WR4(sc, DC_WINBUF_ADDR_H_OFFSET, h_offset);
452         WR4(sc, DC_WINBUF_ADDR_V_OFFSET, v_offset);
453
454         /* Color format */
455         WR4(sc, DC_WIN_COLOR_DEPTH, win->color_mode);
456         WR4(sc, DC_WIN_BYTE_SWAP, win->swap);
457
458         /* Tiling */
459         val = win->surface_kind;
460         if (win->surface_kind == SURFACE_KIND_BL_16B2)
461                 val |= SURFACE_KIND_BLOCK_HEIGHT(win->block_height);
462         WR4(sc, DC_WINBUF_SURFACE_KIND, val);
463
464         /* Color space coefs for YUV modes */
465         if (win->is_yuv) {
466                 WR4(sc, DC_WINC_CSC_YOF,   0x00f0);
467                 WR4(sc, DC_WINC_CSC_KYRGB, 0x012a);
468                 WR4(sc, DC_WINC_CSC_KUR,   0x0000);
469                 WR4(sc, DC_WINC_CSC_KVR,   0x0198);
470                 WR4(sc, DC_WINC_CSC_KUG,   0x039b);
471                 WR4(sc, DC_WINC_CSC_KVG,   0x032f);
472                 WR4(sc, DC_WINC_CSC_KUB,   0x0204);
473                 WR4(sc, DC_WINC_CSC_KVB,   0x0000);
474         }
475
476         val = WIN_ENABLE;
477         if (win->is_yuv)
478                 val |= CSC_ENABLE;
479         else if (win->bits_per_pixel < 24)
480                 val |= COLOR_EXPAND;
481         if (win->flip_y)
482                 val |= V_DIRECTION;
483         if (win->flip_x)
484                 val |= H_DIRECTION;
485         if (win->transpose_xy)
486                 val |= SCAN_COLUMN;
487         WR4(sc, DC_WINC_WIN_OPTIONS, val);
488
489 #ifdef DMR_DEBUG_WINDOW
490         /* Set underflow debug mode -> highlight missing pixels. */
491         WR4(sc, DC_WINBUF_UFLOW_CTRL, UFLOW_CTR_ENABLE);
492         WR4(sc, DC_WINBUF_UFLOW_DBG_PIXEL, 0xFFFF0000);
493 #endif
494
495         UNLOCK(sc);
496 }
497
498 /* -------------------------------------------------------------------
499  *
500  *    Plane functions.
501  *
502  */
503 static int
504 dc_plane_update(struct drm_plane *drm_plane, struct drm_crtc *drm_crtc,
505     struct drm_framebuffer *drm_fb,
506     int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h,
507     uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h)
508 {
509         struct tegra_plane *plane;
510         struct tegra_crtc *crtc;
511         struct tegra_fb *fb;
512         struct dc_softc *sc;
513         struct dc_window win;
514         int rv;
515
516         plane = container_of(drm_plane, struct tegra_plane, drm_plane);
517         fb = container_of(drm_fb, struct tegra_fb, drm_fb);
518         crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
519         sc = device_get_softc(crtc->dev);
520
521         memset(&win, 0, sizeof(win));
522         win.src_x = src_x >> 16;
523         win.src_y = src_y >> 16;
524         win.src_w = src_w >> 16;
525         win.src_h = src_h >> 16;
526         win.dst_x = crtc_x;
527         win.dst_y = crtc_y;
528         win.dst_w = crtc_w;
529         win.dst_h = crtc_h;
530
531         rv = dc_parse_drm_format(fb, &win);
532         if (rv != 0) {
533                 DRM_WARNING("unsupported pixel format %d\n",
534                     fb->drm_fb.pixel_format);
535                 return (rv);
536         }
537
538         dc_setup_window(sc, plane->index, &win);
539
540         WR4(sc, DC_CMD_STATE_CONTROL, WIN_A_UPDATE << plane->index);
541         WR4(sc, DC_CMD_STATE_CONTROL, WIN_A_ACT_REQ << plane->index);
542
543         return (0);
544 }
545
546 static int
547 dc_plane_disable(struct drm_plane *drm_plane)
548 {
549         struct tegra_plane *plane;
550         struct tegra_crtc *crtc;
551         struct dc_softc *sc;
552         uint32_t val, idx;
553
554         if (drm_plane->crtc == NULL)
555                 return (0);
556         plane = container_of(drm_plane, struct tegra_plane, drm_plane);
557         crtc = container_of(drm_plane->crtc, struct tegra_crtc, drm_crtc);
558
559         sc = device_get_softc(crtc->dev);
560         idx = plane->index;
561
562         LOCK(sc);
563
564         WR4(sc, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT << idx);
565
566         val = RD4(sc, DC_WINC_WIN_OPTIONS);
567         val &= ~WIN_ENABLE;
568         WR4(sc, DC_WINC_WIN_OPTIONS, val);
569
570         UNLOCK(sc);
571
572         WR4(sc, DC_CMD_STATE_CONTROL, WIN_A_UPDATE << idx);
573         WR4(sc, DC_CMD_STATE_CONTROL, WIN_A_ACT_REQ << idx);
574
575         return (0);
576 }
577
578 static void
579 dc_plane_destroy(struct drm_plane *plane)
580 {
581
582         dc_plane_disable(plane);
583         drm_plane_cleanup(plane);
584         free(plane, DRM_MEM_KMS);
585 }
586
587 static const struct drm_plane_funcs dc_plane_funcs = {
588         .update_plane = dc_plane_update,
589         .disable_plane = dc_plane_disable,
590         .destroy = dc_plane_destroy,
591 };
592
593 /* -------------------------------------------------------------------
594  *
595  *    CRTC helper functions.
596  *
597  */
598 static void
599 dc_crtc_dpms(struct drm_crtc *crtc, int mode)
600 {
601         /* Empty function */
602 }
603
604 static bool
605 dc_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode,
606     struct drm_display_mode *adjusted)
607 {
608
609         return (true);
610 }
611
612 static int
613 dc_set_base(struct dc_softc *sc, int x, int y, struct tegra_fb *fb)
614 {
615         struct dc_window win;
616         int rv;
617
618         memset(&win, 0, sizeof(win));
619         win.src_x = x;
620         win.src_y = y;
621         win.src_w = fb->drm_fb.width;
622         win.src_h = fb->drm_fb.height;
623         win.dst_x = x;
624         win.dst_y = y;
625         win.dst_w = fb->drm_fb.width;
626         win.dst_h = fb->drm_fb.height;
627
628         rv = dc_parse_drm_format(fb, &win);
629         if (rv != 0) {
630                 DRM_WARNING("unsupported pixel format %d\n",
631                     fb->drm_fb.pixel_format);
632                 return (rv);
633         }
634         dc_setup_window(sc, 0, &win);
635
636         return (0);
637 }
638
639 static int
640 dc_crtc_mode_set(struct drm_crtc *drm_crtc, struct drm_display_mode *mode,
641     struct drm_display_mode *adjusted, int x, int y,
642     struct drm_framebuffer *old_fb)
643 {
644         struct dc_softc *sc;
645         struct tegra_crtc *crtc;
646         struct tegra_fb *fb;
647         struct dc_window win;
648         uint32_t div, h_ref_to_sync, v_ref_to_sync;
649         int rv;
650
651         crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
652         sc = device_get_softc(crtc->dev);
653         fb = container_of(drm_crtc->fb, struct tegra_fb, drm_fb);
654
655         h_ref_to_sync = 1;
656         v_ref_to_sync = 1;
657         /* Setup timing */
658         rv = dc_setup_clk(sc, drm_crtc, mode, &div);
659         if (rv != 0) {
660                 device_printf(sc->dev, "Cannot set pixel clock\n");
661                 return (rv);
662         }
663
664         /* Timing */
665         WR4(sc, DC_DISP_DISP_TIMING_OPTIONS, 0);
666
667         WR4(sc, DC_DISP_REF_TO_SYNC,
668             (v_ref_to_sync << 16) |
669              h_ref_to_sync);
670
671         WR4(sc, DC_DISP_SYNC_WIDTH,
672             ((mode->vsync_end - mode->vsync_start) << 16) |
673             ((mode->hsync_end - mode->hsync_start) <<  0));
674
675         WR4(sc, DC_DISP_BACK_PORCH,
676             ((mode->vtotal - mode->vsync_end) << 16) |
677             ((mode->htotal - mode->hsync_end) <<  0));
678
679         WR4(sc, DC_DISP_FRONT_PORCH,
680             ((mode->vsync_start - mode->vdisplay) << 16) |
681             ((mode->hsync_start - mode->hdisplay) <<  0));
682
683         WR4(sc, DC_DISP_DISP_ACTIVE,
684             (mode->vdisplay << 16) | mode->hdisplay);
685
686         WR4(sc, DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT(DF1P1C));
687
688         WR4(sc,DC_DISP_DISP_CLOCK_CONTROL,
689             SHIFT_CLK_DIVIDER(div) | PIXEL_CLK_DIVIDER(PCD1));
690
691         memset(&win, 0, sizeof(win));
692         win.src_x = x;
693         win.src_y = y;
694         win.src_w = mode->hdisplay;
695         win.src_h = mode->vdisplay;
696         win.dst_x = x;
697         win.dst_y = y;
698         win.dst_w = mode->hdisplay;
699         win.dst_h = mode->vdisplay;
700
701         rv = dc_parse_drm_format(fb, &win);
702         if (rv != 0) {
703                 DRM_WARNING("unsupported pixel format %d\n",
704                     drm_crtc->fb->pixel_format);
705                 return (rv);
706         }
707
708         dc_setup_window(sc, 0, &win);
709
710         return (0);
711
712 }
713
714 static int
715 dc_crtc_mode_set_base(struct drm_crtc *drm_crtc, int x, int y,
716     struct drm_framebuffer *old_fb)
717 {
718         struct dc_softc *sc;
719         struct tegra_crtc *crtc;
720         struct tegra_fb *fb;
721         int rv;
722
723         crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
724         fb = container_of(drm_crtc->fb, struct tegra_fb, drm_fb);
725         sc = device_get_softc(crtc->dev);
726
727         rv = dc_set_base(sc, x, y, fb);
728
729         /* Commit */
730         WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE);
731         WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ);
732         return (rv);
733 }
734
735 static void
736 dc_crtc_prepare(struct drm_crtc *drm_crtc)
737 {
738
739         struct dc_softc *sc;
740         struct tegra_crtc *crtc;
741         uint32_t val;
742
743         crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
744         sc = device_get_softc(crtc->dev);
745
746         WR4(sc, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL, SYNCPT_CNTRL_NO_STALL);
747         /* XXX allocate syncpoint from host1x */
748         WR4(sc, DC_CMD_CONT_SYNCPT_VSYNC, SYNCPT_VSYNC_ENABLE |
749             (sc->tegra_crtc.nvidia_head == 0 ? SYNCPT_VBLANK0: SYNCPT_VBLANK1));
750
751         WR4(sc, DC_CMD_DISPLAY_POWER_CONTROL,
752             PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
753             PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
754
755         val = RD4(sc, DC_CMD_DISPLAY_COMMAND);
756         val |= DISPLAY_CTRL_MODE(CTRL_MODE_C_DISPLAY);
757         WR4(sc, DC_CMD_DISPLAY_COMMAND, val);
758
759         WR4(sc, DC_CMD_INT_MASK,
760             WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
761             WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT);
762
763         WR4(sc, DC_CMD_INT_ENABLE,
764             VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
765             WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT);
766 }
767
768 static void
769 dc_crtc_commit(struct drm_crtc *drm_crtc)
770 {
771         struct dc_softc *sc;
772         struct tegra_crtc *crtc;
773         uint32_t val;
774
775         crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
776         sc = device_get_softc(crtc->dev);
777
778         WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE);
779
780         val = RD4(sc, DC_CMD_INT_MASK);
781         val |= FRAME_END_INT;
782         WR4(sc, DC_CMD_INT_MASK, val);
783
784         val = RD4(sc, DC_CMD_INT_ENABLE);
785         val |= FRAME_END_INT;
786         WR4(sc, DC_CMD_INT_ENABLE, val);
787
788         WR4(sc, DC_CMD_STATE_CONTROL,  GENERAL_ACT_REQ | WIN_A_ACT_REQ);
789 }
790
791 static void
792 dc_crtc_load_lut(struct drm_crtc *crtc)
793 {
794
795         /* empty function */
796 }
797
798 static const struct drm_crtc_helper_funcs dc_crtc_helper_funcs = {
799         .dpms = dc_crtc_dpms,
800         .mode_fixup = dc_crtc_mode_fixup,
801         .mode_set = dc_crtc_mode_set,
802         .mode_set_base = dc_crtc_mode_set_base,
803         .prepare = dc_crtc_prepare,
804         .commit = dc_crtc_commit,
805         .load_lut = dc_crtc_load_lut,
806 };
807
808 static int
809 drm_crtc_index(struct drm_crtc *crtc)
810 {
811         int idx;
812         struct drm_crtc *tmp;
813
814         idx = 0;
815         list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) {
816                 if (tmp == crtc)
817                         return (idx);
818                 idx++;
819         }
820         panic("Cannot find CRTC");
821 }
822
823 /* -------------------------------------------------------------------
824  *
825  *   Exported functions (mainly vsync related).
826  *
827  * XXX revisit this -> convert to bus methods?
828  */
829 int
830 tegra_dc_get_pipe(struct drm_crtc *drm_crtc)
831 {
832         struct tegra_crtc *crtc;
833
834         crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
835         return (crtc->nvidia_head);
836 }
837
838 void
839 tegra_dc_enable_vblank(struct drm_crtc *drm_crtc)
840 {
841         struct dc_softc *sc;
842         struct tegra_crtc *crtc;
843         uint32_t val;
844
845         crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
846         sc = device_get_softc(crtc->dev);
847
848         LOCK(sc);
849         val = RD4(sc, DC_CMD_INT_MASK);
850         val |= VBLANK_INT;
851         WR4(sc, DC_CMD_INT_MASK, val);
852         UNLOCK(sc);
853 }
854
855 void
856 tegra_dc_disable_vblank(struct drm_crtc *drm_crtc)
857 {
858         struct dc_softc *sc;
859         struct tegra_crtc *crtc;
860         uint32_t val;
861
862         crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
863         sc = device_get_softc(crtc->dev);
864
865         LOCK(sc);
866         val = RD4(sc, DC_CMD_INT_MASK);
867         val &= ~VBLANK_INT;
868         WR4(sc, DC_CMD_INT_MASK, val);
869         UNLOCK(sc);
870 }
871
872 static void
873 dc_finish_page_flip(struct dc_softc *sc)
874 {
875         struct drm_crtc *drm_crtc;
876         struct drm_device *drm;
877         struct tegra_fb *fb;
878         struct tegra_bo *bo;
879         uint32_t base;
880         int idx;
881
882         drm_crtc = &sc->tegra_crtc.drm_crtc;
883         drm = drm_crtc->dev;
884         fb = container_of(drm_crtc->fb, struct tegra_fb, drm_fb);
885
886         mtx_lock(&drm->event_lock);
887
888         if (sc->event == NULL) {
889                 mtx_unlock(&drm->event_lock);
890                 return;
891         }
892
893         LOCK(sc);
894         /* Read active copy of WINBUF_START_ADDR */
895         WR4(sc, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT);
896         WR4(sc, DC_CMD_STATE_ACCESS, READ_MUX);
897         base = RD4(sc, DC_WINBUF_START_ADDR);
898         WR4(sc, DC_CMD_STATE_ACCESS, 0);
899         UNLOCK(sc);
900
901         /* Is already active */
902         bo = tegra_fb_get_plane(fb, 0);
903         if (base == (bo->pbase + fb->drm_fb.offsets[0])) {
904                 idx = drm_crtc_index(drm_crtc);
905                 drm_send_vblank_event(drm, idx, sc->event);
906                 drm_vblank_put(drm, idx);
907                 sc->event = NULL;
908         }
909
910         mtx_unlock(&drm->event_lock);
911 }
912
913 void
914 tegra_dc_cancel_page_flip(struct drm_crtc *drm_crtc, struct drm_file *file)
915 {
916         struct dc_softc *sc;
917         struct tegra_crtc *crtc;
918         struct drm_device *drm;
919
920         crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
921         sc = device_get_softc(crtc->dev);
922         drm = drm_crtc->dev;
923         mtx_lock(&drm->event_lock);
924
925         if ((sc->event != NULL) && (sc->event->base.file_priv == file)) {
926                 sc->event->base.destroy(&sc->event->base);
927                 drm_vblank_put(drm, drm_crtc_index(drm_crtc));
928                 sc->event = NULL;
929         }
930         mtx_unlock(&drm->event_lock);
931 }
932
933 /* -------------------------------------------------------------------
934  *
935  *    CRTC functions.
936  *
937  */
938 static int
939 dc_page_flip(struct drm_crtc *drm_crtc, struct drm_framebuffer *drm_fb,
940     struct drm_pending_vblank_event *event)
941 {
942         struct dc_softc *sc;
943         struct tegra_crtc *crtc;
944         struct tegra_fb *fb;
945         struct drm_device *drm;
946
947         crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
948         sc = device_get_softc(crtc->dev);
949         fb = container_of(drm_crtc->fb, struct tegra_fb, drm_fb);
950         drm = drm_crtc->dev;
951
952         if (sc->event != NULL)
953                 return (-EBUSY);
954
955         if (event != NULL) {
956                 event->pipe = sc->tegra_crtc.nvidia_head;
957                 sc->event = event;
958                 drm_vblank_get(drm, event->pipe);
959         }
960
961         dc_set_base(sc, drm_crtc->x, drm_crtc->y, fb);
962         drm_crtc->fb = drm_fb;
963
964         /* Commit */
965         WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE);
966
967         return (0);
968 }
969
970 static int
971 dc_cursor_set(struct drm_crtc *drm_crtc, struct drm_file *file,
972     uint32_t handle, uint32_t width, uint32_t height)
973 {
974
975         struct dc_softc *sc;
976         struct tegra_crtc *crtc;
977         struct drm_gem_object *gem;
978         struct tegra_bo *bo;
979         int i;
980         uint32_t val, *src, *dst;
981
982         crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
983         sc = device_get_softc(crtc->dev);
984
985         if (width != height)
986                 return (-EINVAL);
987
988         switch (width) {
989         case 32:
990                 val = CURSOR_SIZE(C32x32);
991                 break;
992         case 64:
993                 val = CURSOR_SIZE(C64x64);
994                 break;
995         case 128:
996                 val = CURSOR_SIZE(C128x128);
997                 break;
998         case 256:
999                 val = CURSOR_SIZE(C256x256);
1000                 break;
1001         default:
1002                 return (-EINVAL);
1003         }
1004
1005         bo = NULL;
1006         gem = NULL;
1007         if (handle != 0) {
1008                 gem = drm_gem_object_lookup(drm_crtc->dev, file, handle);
1009                 if (gem == NULL)
1010                         return (-ENOENT);
1011                 bo = container_of(gem, struct tegra_bo, gem_obj);
1012         }
1013
1014         if (sc->cursor_gem != NULL) {
1015                 drm_gem_object_unreference(sc->cursor_gem);
1016         }
1017         sc->cursor_gem = gem;
1018
1019         if (bo != NULL) {
1020                 /*
1021                  * Copy cursor into cache and convert it from ARGB to RGBA.
1022                  * XXXX - this is broken by design - client can write to BO at
1023                  * any time. We can dedicate other window for cursor or switch
1024                  * to sw cursor in worst case.
1025                  */
1026                 src = (uint32_t *)bo->vbase;
1027                 dst = (uint32_t *)crtc->cursor_vbase;
1028                 for (i = 0; i < width * height; i++)
1029                         dst[i] = (src[i] << 8) | (src[i] >> 24);
1030
1031                 val |= CURSOR_CLIP(CC_DISPLAY);
1032                 val |= CURSOR_START_ADDR(crtc->cursor_pbase);
1033                 WR4(sc, DC_DISP_CURSOR_START_ADDR, val);
1034
1035                 val = RD4(sc, DC_DISP_BLEND_CURSOR_CONTROL);
1036                 val &= ~CURSOR_DST_BLEND_FACTOR_SELECT(~0);
1037                 val &= ~CURSOR_SRC_BLEND_FACTOR_SELECT(~0);
1038                 val |= CURSOR_MODE_SELECT;
1039                 val |= CURSOR_DST_BLEND_FACTOR_SELECT(DST_NEG_K1_TIMES_SRC);
1040                 val |= CURSOR_SRC_BLEND_FACTOR_SELECT(SRC_BLEND_K1_TIMES_SRC);
1041                 val |= CURSOR_ALPHA(~0);
1042                 WR4(sc, DC_DISP_BLEND_CURSOR_CONTROL, val);
1043
1044                 val = RD4(sc, DC_DISP_DISP_WIN_OPTIONS);
1045                 val |= CURSOR_ENABLE;
1046                 WR4(sc, DC_DISP_DISP_WIN_OPTIONS, val);
1047         } else {
1048                 val = RD4(sc, DC_DISP_DISP_WIN_OPTIONS);
1049                 val &= ~CURSOR_ENABLE;
1050                 WR4(sc, DC_DISP_DISP_WIN_OPTIONS, val);
1051         }
1052
1053         /* XXX This fixes cursor underflow issues, but why ?  */
1054         WR4(sc, DC_DISP_CURSOR_UNDERFLOW_CTRL, CURSOR_UFLOW_CYA);
1055
1056         WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | CURSOR_UPDATE );
1057         WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | CURSOR_ACT_REQ);
1058         return (0);
1059 }
1060
1061 static int
1062 dc_cursor_move(struct drm_crtc *drm_crtc, int x, int y)
1063 {
1064         struct dc_softc *sc;
1065         struct tegra_crtc *crtc;
1066
1067         crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc);
1068         sc = device_get_softc(crtc->dev);
1069         WR4(sc, DC_DISP_CURSOR_POSITION, CURSOR_POSITION(x, y));
1070
1071         WR4(sc, DC_CMD_STATE_CONTROL, CURSOR_UPDATE);
1072         WR4(sc, DC_CMD_STATE_CONTROL, CURSOR_ACT_REQ);
1073
1074         return (0);
1075 }
1076
1077 static void
1078 dc_destroy(struct drm_crtc *crtc)
1079 {
1080
1081         drm_crtc_cleanup(crtc);
1082         memset(crtc, 0, sizeof(*crtc));
1083 }
1084
1085 static const struct drm_crtc_funcs dc_crtc_funcs = {
1086         .page_flip = dc_page_flip,
1087         .cursor_set = dc_cursor_set,
1088         .cursor_move = dc_cursor_move,
1089         .set_config = drm_crtc_helper_set_config,
1090         .destroy = dc_destroy,
1091 };
1092
1093 /* -------------------------------------------------------------------
1094  *
1095  *    Bus and infrastructure.
1096  *
1097  */
1098 static int
1099 dc_init_planes(struct dc_softc *sc, struct tegra_drm *drm)
1100 {
1101         int i, rv;
1102         struct tegra_plane *plane;
1103
1104         rv = 0;
1105         for (i = 0; i < DC_MAX_PLANES; i++) {
1106                 plane = malloc(sizeof(*plane), DRM_MEM_KMS, M_WAITOK | M_ZERO);
1107                 plane->index = i + 1;
1108                 rv = drm_plane_init(&drm->drm_dev, &plane->drm_plane,
1109                     1 << sc->tegra_crtc.nvidia_head, &dc_plane_funcs,
1110                     dc_plane_formats, nitems(dc_plane_formats), false);
1111                 if (rv != 0) {
1112                         free(plane, DRM_MEM_KMS);
1113                         return (rv);
1114                 }
1115         }
1116         return 0;
1117 }
1118
1119 static void
1120 dc_display_enable(device_t dev, bool enable)
1121 {
1122         struct dc_softc *sc;
1123         uint32_t val;
1124
1125         sc = device_get_softc(dev);
1126
1127         /* Set display mode */
1128         val = enable ? CTRL_MODE_C_DISPLAY: CTRL_MODE_STOP;
1129         WR4(sc, DC_CMD_DISPLAY_COMMAND, DISPLAY_CTRL_MODE(val));
1130
1131         /* and commit it*/
1132         WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_UPDATE);
1133         WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ);
1134 }
1135
1136 static void
1137 dc_hdmi_enable(device_t dev, bool enable)
1138 {
1139         struct dc_softc *sc;
1140         uint32_t val;
1141
1142         sc = device_get_softc(dev);
1143
1144         val = RD4(sc, DC_DISP_DISP_WIN_OPTIONS);
1145         if (enable)
1146                 val |= HDMI_ENABLE;
1147         else
1148                 val &= ~HDMI_ENABLE;
1149         WR4(sc, DC_DISP_DISP_WIN_OPTIONS, val);
1150
1151 }
1152
1153 static void
1154 dc_setup_timing(device_t dev, int h_pulse_start)
1155 {
1156         struct dc_softc *sc;
1157
1158         sc = device_get_softc(dev);
1159
1160         /* Setup display timing */
1161         WR4(sc, DC_DISP_DISP_TIMING_OPTIONS, VSYNC_H_POSITION(1));
1162         WR4(sc, DC_DISP_DISP_COLOR_CONTROL,
1163             DITHER_CONTROL(DITHER_DISABLE) | BASE_COLOR_SIZE(SIZE_BASE888));
1164
1165         WR4(sc, DC_DISP_DISP_SIGNAL_OPTIONS0, H_PULSE2_ENABLE);
1166         WR4(sc, DC_DISP_H_PULSE2_CONTROL,
1167             PULSE_CONTROL_QUAL(QUAL_VACTIVE) | PULSE_CONTROL_LAST(LAST_END_A));
1168
1169         WR4(sc, DC_DISP_H_PULSE2_POSITION_A,
1170             PULSE_START(h_pulse_start) | PULSE_END(h_pulse_start + 8));
1171 }
1172
1173 static void
1174 dc_intr(void *arg)
1175 {
1176         struct dc_softc *sc;
1177         uint32_t status;
1178
1179         sc = arg;
1180
1181         /* Confirm interrupt */
1182         status = RD4(sc, DC_CMD_INT_STATUS);
1183         WR4(sc, DC_CMD_INT_STATUS, status);
1184         if (status & VBLANK_INT) {
1185                 drm_handle_vblank(sc->tegra_crtc.drm_crtc.dev,
1186                     sc->tegra_crtc.nvidia_head);
1187                 dc_finish_page_flip(sc);
1188         }
1189 }
1190
1191 static int
1192 dc_init_client(device_t dev, device_t host1x, struct tegra_drm *drm)
1193 {
1194         struct dc_softc *sc;
1195         int rv;
1196
1197         sc = device_get_softc(dev);
1198
1199         if (drm->pitch_align < sc->pitch_align)
1200                 drm->pitch_align = sc->pitch_align;
1201
1202         drm_crtc_init(&drm->drm_dev, &sc->tegra_crtc.drm_crtc, &dc_crtc_funcs);
1203         drm_mode_crtc_set_gamma_size(&sc->tegra_crtc.drm_crtc, 256);
1204         drm_crtc_helper_add(&sc->tegra_crtc.drm_crtc, &dc_crtc_helper_funcs);
1205
1206         rv = dc_init_planes(sc, drm);
1207         if (rv!= 0){
1208                 device_printf(dev, "Cannot init planes\n");
1209                 return (rv);
1210         }
1211
1212         WR4(sc, DC_CMD_INT_TYPE,
1213             WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
1214             WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT);
1215
1216         WR4(sc, DC_CMD_INT_POLARITY,
1217             WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
1218             WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT);
1219
1220         WR4(sc, DC_CMD_INT_ENABLE, 0);
1221         WR4(sc, DC_CMD_INT_MASK, 0);
1222
1223         rv = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
1224             NULL, dc_intr, sc, &sc->irq_ih);
1225         if (rv != 0) {
1226                 device_printf(dev, "Cannot register interrupt handler\n");
1227                 return (rv);
1228         }
1229
1230         /* allocate memory for cursor cache */
1231         sc->tegra_crtc.cursor_vbase = kmem_alloc_contig(256 * 256 * 4,
1232             M_WAITOK | M_ZERO, 0, -1UL, PAGE_SIZE, 0,
1233             VM_MEMATTR_WRITE_COMBINING);
1234         sc->tegra_crtc.cursor_pbase = vtophys(sc->tegra_crtc.cursor_vbase);
1235         return (0);
1236 }
1237
1238 static int
1239 dc_exit_client(device_t dev, device_t host1x, struct tegra_drm *drm)
1240 {
1241         struct dc_softc *sc;
1242
1243         sc = device_get_softc(dev);
1244
1245         if (sc->irq_ih != NULL)
1246                 bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
1247         sc->irq_ih = NULL;
1248
1249         return (0);
1250 }
1251
1252 static int
1253 get_fdt_resources(struct dc_softc *sc, phandle_t node)
1254 {
1255         int rv;
1256
1257         rv = hwreset_get_by_ofw_name(sc->dev, 0, "dc", &sc->hwreset_dc);
1258         if (rv != 0) {
1259                 device_printf(sc->dev, "Cannot get 'dc' reset\n");
1260                 return (rv);
1261         }
1262         rv = clk_get_by_ofw_name(sc->dev, 0, "parent", &sc->clk_parent);
1263         if (rv != 0) {
1264                 device_printf(sc->dev, "Cannot get 'parent' clock\n");
1265                 return (rv);
1266         }
1267         rv = clk_get_by_ofw_name(sc->dev, 0, "dc", &sc->clk_dc);
1268         if (rv != 0) {
1269                 device_printf(sc->dev, "Cannot get 'dc' clock\n");
1270                 return (rv);
1271         }
1272
1273         rv = OF_getencprop(node, "nvidia,head", &sc->tegra_crtc.nvidia_head,
1274             sizeof(sc->tegra_crtc.nvidia_head));
1275         if (rv <= 0) {
1276                 device_printf(sc->dev,
1277                     "Cannot get 'nvidia,head' property\n");
1278                 return (rv);
1279         }
1280         return (0);
1281 }
1282
1283 static int
1284 enable_fdt_resources(struct dc_softc *sc)
1285 {
1286         int id, rv;
1287
1288         rv = clk_set_parent_by_clk(sc->clk_dc, sc->clk_parent);
1289         if (rv != 0) {
1290                 device_printf(sc->dev, "Cannot set parent for 'dc' clock\n");
1291                 return (rv);
1292         }
1293
1294         id = (sc->tegra_crtc.nvidia_head == 0) ?
1295             TEGRA_POWERGATE_DIS: TEGRA_POWERGATE_DISB;
1296         rv = tegra_powergate_sequence_power_up(id, sc->clk_dc, sc->hwreset_dc);
1297         if (rv != 0) {
1298                 device_printf(sc->dev, "Cannot enable 'DIS' powergate\n");
1299                 return (rv);
1300         }
1301
1302         return (0);
1303 }
1304
1305 static int
1306 dc_probe(device_t dev)
1307 {
1308
1309         if (!ofw_bus_status_okay(dev))
1310                 return (ENXIO);
1311
1312         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
1313                 return (ENXIO);
1314
1315         device_set_desc(dev, "Tegra Display Controller");
1316         return (BUS_PROBE_DEFAULT);
1317 }
1318
1319 static int
1320 dc_attach(device_t dev)
1321 {
1322         struct dc_softc *sc;
1323         phandle_t node;
1324         int rid, rv;
1325
1326         sc = device_get_softc(dev);
1327         sc->dev = dev;
1328         sc->tegra_crtc.dev = dev;
1329
1330         node = ofw_bus_get_node(sc->dev);
1331         LOCK_INIT(sc);
1332
1333         rid = 0;
1334         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
1335             RF_ACTIVE);
1336         if (sc->mem_res == NULL) {
1337                 device_printf(dev, "Cannot allocate memory resources\n");
1338                 goto fail;
1339         }
1340
1341         rid = 0;
1342         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
1343         if (sc->irq_res == NULL) {
1344                 device_printf(dev, "Cannot allocate IRQ resources\n");
1345                 goto fail;
1346         }
1347
1348         rv = get_fdt_resources(sc, node);
1349         if (rv != 0) {
1350                 device_printf(dev, "Cannot parse FDT resources\n");
1351                 goto fail;
1352         }
1353         rv = enable_fdt_resources(sc);
1354         if (rv != 0) {
1355                 device_printf(dev, "Cannot enable FDT resources\n");
1356                 goto fail;
1357         }
1358
1359         /*
1360          * Tegra124
1361          *  -  64 for RGB modes
1362          *  - 128 for YUV planar modes
1363          *  - 256 for block linear modes
1364          */
1365         sc->pitch_align = 256;
1366
1367         rv = TEGRA_DRM_REGISTER_CLIENT(device_get_parent(sc->dev), sc->dev);
1368         if (rv != 0) {
1369                 device_printf(dev, "Cannot register DRM device\n");
1370                 goto fail;
1371         }
1372
1373         return (bus_generic_attach(dev));
1374
1375 fail:
1376         TEGRA_DRM_DEREGISTER_CLIENT(device_get_parent(sc->dev), sc->dev);
1377         if (sc->irq_ih != NULL)
1378                 bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
1379         if (sc->clk_parent != NULL)
1380                 clk_release(sc->clk_parent);
1381         if (sc->clk_dc != NULL)
1382                 clk_release(sc->clk_dc);
1383         if (sc->hwreset_dc != NULL)
1384                 hwreset_release(sc->hwreset_dc);
1385         if (sc->irq_res != NULL)
1386                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
1387         if (sc->mem_res != NULL)
1388                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
1389         LOCK_DESTROY(sc);
1390
1391         return (ENXIO);
1392 }
1393
1394 static int
1395 dc_detach(device_t dev)
1396 {
1397         struct dc_softc *sc;
1398
1399         sc = device_get_softc(dev);
1400
1401         TEGRA_DRM_DEREGISTER_CLIENT(device_get_parent(sc->dev), sc->dev);
1402
1403         if (sc->irq_ih != NULL)
1404                 bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
1405         if (sc->clk_parent != NULL)
1406                 clk_release(sc->clk_parent);
1407         if (sc->clk_dc != NULL)
1408                 clk_release(sc->clk_dc);
1409         if (sc->hwreset_dc != NULL)
1410                 hwreset_release(sc->hwreset_dc);
1411         if (sc->irq_res != NULL)
1412                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
1413         if (sc->mem_res != NULL)
1414                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
1415         LOCK_DESTROY(sc);
1416
1417         return (bus_generic_detach(dev));
1418 }
1419
1420 static device_method_t tegra_dc_methods[] = {
1421         /* Device interface */
1422         DEVMETHOD(device_probe,                 dc_probe),
1423         DEVMETHOD(device_attach,                dc_attach),
1424         DEVMETHOD(device_detach,                dc_detach),
1425
1426         /* tegra drm interface */
1427         DEVMETHOD(tegra_drm_init_client,        dc_init_client),
1428         DEVMETHOD(tegra_drm_exit_client,        dc_exit_client),
1429
1430         /* tegra dc interface */
1431         DEVMETHOD(tegra_dc_display_enable,      dc_display_enable),
1432         DEVMETHOD(tegra_dc_hdmi_enable,         dc_hdmi_enable),
1433         DEVMETHOD(tegra_dc_setup_timing,        dc_setup_timing),
1434
1435         DEVMETHOD_END
1436 };
1437
1438 static devclass_t tegra_dc_devclass;
1439 DEFINE_CLASS_0(tegra_dc, tegra_dc_driver, tegra_dc_methods,
1440     sizeof(struct dc_softc));
1441 DRIVER_MODULE(tegra_dc, host1x, tegra_dc_driver, tegra_dc_devclass, NULL, NULL);