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