The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arm/nvidia/drm2/tegra_dc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 =
 1235             vtophys((uintptr_t)sc->tegra_crtc.cursor_vbase);
 1236         return (0);
 1237 }
 1238 
 1239 static int
 1240 dc_exit_client(device_t dev, device_t host1x, struct tegra_drm *drm)
 1241 {
 1242         struct dc_softc *sc;
 1243 
 1244         sc = device_get_softc(dev);
 1245 
 1246         if (sc->irq_ih != NULL)
 1247                 bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
 1248         sc->irq_ih = NULL;
 1249 
 1250         return (0);
 1251 }
 1252 
 1253 static int
 1254 get_fdt_resources(struct dc_softc *sc, phandle_t node)
 1255 {
 1256         int rv;
 1257 
 1258         rv = hwreset_get_by_ofw_name(sc->dev, 0, "dc", &sc->hwreset_dc);
 1259         if (rv != 0) {
 1260                 device_printf(sc->dev, "Cannot get 'dc' reset\n");
 1261                 return (rv);
 1262         }
 1263         rv = clk_get_by_ofw_name(sc->dev, 0, "parent", &sc->clk_parent);
 1264         if (rv != 0) {
 1265                 device_printf(sc->dev, "Cannot get 'parent' clock\n");
 1266                 return (rv);
 1267         }
 1268         rv = clk_get_by_ofw_name(sc->dev, 0, "dc", &sc->clk_dc);
 1269         if (rv != 0) {
 1270                 device_printf(sc->dev, "Cannot get 'dc' clock\n");
 1271                 return (rv);
 1272         }
 1273 
 1274         rv = OF_getencprop(node, "nvidia,head", &sc->tegra_crtc.nvidia_head,
 1275             sizeof(sc->tegra_crtc.nvidia_head));
 1276         if (rv <= 0) {
 1277                 device_printf(sc->dev,
 1278                     "Cannot get 'nvidia,head' property\n");
 1279                 return (rv);
 1280         }
 1281         return (0);
 1282 }
 1283 
 1284 static int
 1285 enable_fdt_resources(struct dc_softc *sc)
 1286 {
 1287         int id, rv;
 1288 
 1289         rv = clk_set_parent_by_clk(sc->clk_dc, sc->clk_parent);
 1290         if (rv != 0) {
 1291                 device_printf(sc->dev, "Cannot set parent for 'dc' clock\n");
 1292                 return (rv);
 1293         }
 1294 
 1295         id = (sc->tegra_crtc.nvidia_head == 0) ?
 1296             TEGRA_POWERGATE_DIS: TEGRA_POWERGATE_DISB;
 1297         rv = tegra_powergate_sequence_power_up(id, sc->clk_dc, sc->hwreset_dc);
 1298         if (rv != 0) {
 1299                 device_printf(sc->dev, "Cannot enable 'DIS' powergate\n");
 1300                 return (rv);
 1301         }
 1302 
 1303         return (0);
 1304 }
 1305 
 1306 static int
 1307 dc_probe(device_t dev)
 1308 {
 1309 
 1310         if (!ofw_bus_status_okay(dev))
 1311                 return (ENXIO);
 1312 
 1313         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
 1314                 return (ENXIO);
 1315 
 1316         device_set_desc(dev, "Tegra Display Controller");
 1317         return (BUS_PROBE_DEFAULT);
 1318 }
 1319 
 1320 static int
 1321 dc_attach(device_t dev)
 1322 {
 1323         struct dc_softc *sc;
 1324         phandle_t node;
 1325         int rid, rv;
 1326 
 1327         sc = device_get_softc(dev);
 1328         sc->dev = dev;
 1329         sc->tegra_crtc.dev = dev;
 1330 
 1331         node = ofw_bus_get_node(sc->dev);
 1332         LOCK_INIT(sc);
 1333 
 1334         rid = 0;
 1335         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
 1336             RF_ACTIVE);
 1337         if (sc->mem_res == NULL) {
 1338                 device_printf(dev, "Cannot allocate memory resources\n");
 1339                 goto fail;
 1340         }
 1341 
 1342         rid = 0;
 1343         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
 1344         if (sc->irq_res == NULL) {
 1345                 device_printf(dev, "Cannot allocate IRQ resources\n");
 1346                 goto fail;
 1347         }
 1348 
 1349         rv = get_fdt_resources(sc, node);
 1350         if (rv != 0) {
 1351                 device_printf(dev, "Cannot parse FDT resources\n");
 1352                 goto fail;
 1353         }
 1354         rv = enable_fdt_resources(sc);
 1355         if (rv != 0) {
 1356                 device_printf(dev, "Cannot enable FDT resources\n");
 1357                 goto fail;
 1358         }
 1359 
 1360         /*
 1361          * Tegra124
 1362          *  -  64 for RGB modes
 1363          *  - 128 for YUV planar modes
 1364          *  - 256 for block linear modes
 1365          */
 1366         sc->pitch_align = 256;
 1367 
 1368         rv = TEGRA_DRM_REGISTER_CLIENT(device_get_parent(sc->dev), sc->dev);
 1369         if (rv != 0) {
 1370                 device_printf(dev, "Cannot register DRM device\n");
 1371                 goto fail;
 1372         }
 1373 
 1374         return (bus_generic_attach(dev));
 1375 
 1376 fail:
 1377         TEGRA_DRM_DEREGISTER_CLIENT(device_get_parent(sc->dev), sc->dev);
 1378         if (sc->irq_ih != NULL)
 1379                 bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
 1380         if (sc->clk_parent != NULL)
 1381                 clk_release(sc->clk_parent);
 1382         if (sc->clk_dc != NULL)
 1383                 clk_release(sc->clk_dc);
 1384         if (sc->hwreset_dc != NULL)
 1385                 hwreset_release(sc->hwreset_dc);
 1386         if (sc->irq_res != NULL)
 1387                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
 1388         if (sc->mem_res != NULL)
 1389                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
 1390         LOCK_DESTROY(sc);
 1391 
 1392         return (ENXIO);
 1393 }
 1394 
 1395 static int
 1396 dc_detach(device_t dev)
 1397 {
 1398         struct dc_softc *sc;
 1399 
 1400         sc = device_get_softc(dev);
 1401 
 1402         TEGRA_DRM_DEREGISTER_CLIENT(device_get_parent(sc->dev), sc->dev);
 1403 
 1404         if (sc->irq_ih != NULL)
 1405                 bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
 1406         if (sc->clk_parent != NULL)
 1407                 clk_release(sc->clk_parent);
 1408         if (sc->clk_dc != NULL)
 1409                 clk_release(sc->clk_dc);
 1410         if (sc->hwreset_dc != NULL)
 1411                 hwreset_release(sc->hwreset_dc);
 1412         if (sc->irq_res != NULL)
 1413                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
 1414         if (sc->mem_res != NULL)
 1415                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
 1416         LOCK_DESTROY(sc);
 1417 
 1418         return (bus_generic_detach(dev));
 1419 }
 1420 
 1421 static device_method_t tegra_dc_methods[] = {
 1422         /* Device interface */
 1423         DEVMETHOD(device_probe,                 dc_probe),
 1424         DEVMETHOD(device_attach,                dc_attach),
 1425         DEVMETHOD(device_detach,                dc_detach),
 1426 
 1427         /* tegra drm interface */
 1428         DEVMETHOD(tegra_drm_init_client,        dc_init_client),
 1429         DEVMETHOD(tegra_drm_exit_client,        dc_exit_client),
 1430 
 1431         /* tegra dc interface */
 1432         DEVMETHOD(tegra_dc_display_enable,      dc_display_enable),
 1433         DEVMETHOD(tegra_dc_hdmi_enable,         dc_hdmi_enable),
 1434         DEVMETHOD(tegra_dc_setup_timing,        dc_setup_timing),
 1435 
 1436         DEVMETHOD_END
 1437 };
 1438 
 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, NULL, NULL);

Cache object: 3e26a9c7d0e33671aa559e50882f7fd0


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.