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_fb.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) 2016 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/kernel.h>
   34 #include <sys/malloc.h>
   35 
   36 #include <machine/bus.h>
   37 
   38 #include <dev/extres/clk/clk.h>
   39 #include <dev/drm2/drmP.h>
   40 #include <dev/drm2/drm_crtc_helper.h>
   41 #include <dev/drm2/drm_fb_helper.h>
   42 
   43 #include <arm/nvidia/drm2/tegra_drm.h>
   44 
   45 static void
   46 fb_destroy(struct drm_framebuffer *drm_fb)
   47 {
   48         struct tegra_fb *fb;
   49         struct tegra_bo *bo;
   50         unsigned int i;
   51 
   52         fb = container_of(drm_fb, struct tegra_fb, drm_fb);
   53         for (i = 0; i < fb->nplanes; i++) {
   54                 bo = fb->planes[i];
   55                 if (bo != NULL)
   56                         drm_gem_object_unreference_unlocked(&bo->gem_obj);
   57         }
   58 
   59         drm_framebuffer_cleanup(drm_fb);
   60         free(fb->planes, DRM_MEM_DRIVER);
   61 }
   62 
   63 static int
   64 fb_create_handle(struct drm_framebuffer *drm_fb, struct drm_file *file,
   65  unsigned int *handle)
   66 {
   67         struct tegra_fb *fb;
   68         int rv;
   69 
   70         fb = container_of(drm_fb, struct tegra_fb, drm_fb);
   71         rv = drm_gem_handle_create(file, &fb->planes[0]->gem_obj, handle);
   72         return (rv);
   73 }
   74 
   75 /* XXX Probably not needed */
   76 static int
   77 fb_dirty(struct drm_framebuffer *fb, struct drm_file *file_priv,
   78 unsigned flags, unsigned color, struct drm_clip_rect *clips, unsigned num_clips)
   79 {
   80 
   81         return (0);
   82 }
   83 
   84 static const struct drm_framebuffer_funcs fb_funcs = {
   85         .destroy = fb_destroy,
   86         .create_handle = fb_create_handle,
   87         .dirty = fb_dirty,
   88 };
   89 
   90 static int
   91 fb_alloc(struct drm_device *drm, struct drm_mode_fb_cmd2 *mode_cmd,
   92     struct tegra_bo **planes, int num_planes, struct tegra_fb **res_fb)
   93 {
   94         struct tegra_fb *fb;
   95         int i;
   96         int rv;
   97 
   98         fb = malloc(sizeof(*fb), DRM_MEM_DRIVER, M_WAITOK | M_ZERO);
   99         fb->planes = malloc(num_planes * sizeof(*fb->planes), DRM_MEM_DRIVER,
  100             M_WAITOK | M_ZERO);
  101         fb->nplanes = num_planes;
  102 
  103         drm_helper_mode_fill_fb_struct(&fb->drm_fb, mode_cmd);
  104         for (i = 0; i < fb->nplanes; i++)
  105                 fb->planes[i] = planes[i];
  106         rv = drm_framebuffer_init(drm, &fb->drm_fb, &fb_funcs);
  107         if (rv < 0) {
  108                 device_printf(drm->dev,
  109                     "Cannot initialize frame buffer %d\n", rv);
  110                 free(fb->planes, DRM_MEM_DRIVER);
  111                 return (rv);
  112         }
  113         *res_fb = fb;
  114         return (0);
  115 }
  116 
  117 static int
  118 tegra_fb_probe(struct drm_fb_helper *helper,
  119     struct drm_fb_helper_surface_size *sizes)
  120 {
  121         u_int bpp, size;
  122         struct tegra_drm *drm;
  123         struct tegra_fb *fb;
  124         struct fb_info *info;
  125         struct tegra_bo *bo;
  126         struct drm_mode_fb_cmd2 mode_cmd;
  127         struct drm_device *drm_dev;
  128         int rv;
  129 
  130         if (helper->fb != NULL)
  131                 return (0);
  132 
  133         DRM_DEBUG_KMS("surface: %d x %d (bpp: %d)\n", sizes->surface_width,
  134             sizes->surface_height, sizes->surface_bpp);
  135 
  136         drm_dev = helper->dev;
  137         fb = container_of(helper, struct tegra_fb, fb_helper);
  138         drm = container_of(drm_dev, struct tegra_drm, drm_dev);
  139         bpp = (sizes->surface_bpp + 7) / 8;
  140 
  141         /* Create mode_cmd */
  142         memset(&mode_cmd, 0, sizeof(mode_cmd));
  143         mode_cmd.width = sizes->surface_width;
  144         mode_cmd.height = sizes->surface_height;
  145         mode_cmd.pitches[0] = roundup(sizes->surface_width * bpp,
  146             drm->pitch_align);
  147         mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
  148             sizes->surface_depth);
  149         size = mode_cmd.pitches[0] * mode_cmd.height;
  150 
  151         DRM_LOCK(drm_dev);
  152         rv = tegra_bo_create(drm_dev, size, &bo);
  153         DRM_UNLOCK(drm_dev);
  154         if (rv != 0)
  155                 return (rv);
  156 
  157         info = framebuffer_alloc();
  158         if (info == NULL) {
  159                 device_printf(drm_dev->dev,
  160                     "Cannot allocate DRM framebuffer info.\n");
  161                 rv = -ENOMEM;
  162                 goto err_object;
  163         }
  164 
  165         rv = fb_alloc(drm_dev, &mode_cmd,  &bo, 1, &fb);
  166         if (rv != 0) {
  167                 device_printf(drm_dev->dev,
  168                      "Cannot allocate DRM framebuffer.\n");
  169                 goto err_fb;
  170         }
  171         helper->fb = &fb->drm_fb;
  172         helper->fbdev = info;
  173 
  174         /* Fill FB info */
  175         info->fb_vbase = bo->vbase;
  176         info->fb_pbase = bo->pbase;
  177         info->fb_size = size;
  178         info->fb_bpp = sizes->surface_bpp;
  179         drm_fb_helper_fill_fix(info, fb->drm_fb.pitches[0], fb->drm_fb.depth);
  180         drm_fb_helper_fill_var(info, helper, fb->drm_fb.width,
  181             fb->drm_fb.height);
  182 
  183         DRM_DEBUG_KMS("allocated %dx%d (s %dbits) fb size: %d, bo %p\n",
  184                       fb->drm_fb.width, fb->drm_fb.height, fb->drm_fb.depth,
  185                       size, bo);
  186         return (1);
  187 err_fb:
  188         drm_gem_object_unreference_unlocked(&bo->gem_obj);
  189         framebuffer_release(info);
  190 err_object:
  191         drm_gem_object_release(&bo->gem_obj);
  192         return (rv);
  193 }
  194 
  195 static struct drm_fb_helper_funcs fb_helper_funcs = {
  196         .fb_probe = tegra_fb_probe,
  197 };
  198 
  199 /*
  200  *      Exported functions
  201  */
  202 struct fb_info *
  203 tegra_drm_fb_getinfo(struct drm_device *drm_dev)
  204 {
  205         struct tegra_fb *fb;
  206         struct tegra_drm *drm;
  207 
  208         drm = container_of(drm_dev, struct tegra_drm, drm_dev);
  209         fb = drm->fb;
  210         if (fb == NULL)
  211                 return (NULL);
  212         return (fb->fb_helper.fbdev);
  213 }
  214 
  215 struct tegra_bo *
  216 tegra_fb_get_plane(struct tegra_fb *fb, int idx)
  217 {
  218 
  219         if (idx >= drm_format_num_planes(fb->drm_fb.pixel_format))
  220                 return (NULL);
  221         if (idx >= fb->nplanes)
  222                 return (NULL);
  223         return (fb->planes[idx]);
  224 }
  225 
  226 int
  227 tegra_drm_fb_init(struct drm_device *drm_dev)
  228 {
  229         struct tegra_fb *fb;
  230         struct tegra_drm *drm;
  231         int rv;
  232 
  233         drm = drm_dev->dev_private;
  234         drm = container_of(drm_dev, struct tegra_drm, drm_dev);
  235         fb = malloc(sizeof(*fb), DRM_MEM_DRIVER, M_WAITOK | M_ZERO);
  236         drm->fb = fb;
  237 
  238         fb->fb_helper.funcs = &fb_helper_funcs;
  239         rv = drm_fb_helper_init(drm_dev, &fb->fb_helper,
  240             drm_dev->mode_config.num_crtc, drm_dev->mode_config.num_connector);
  241         if (rv != 0) {
  242                 device_printf(drm_dev->dev,
  243                     "Cannot initialize frame buffer %d\n", rv);
  244                 return (rv);
  245         }
  246 
  247         rv = drm_fb_helper_single_add_all_connectors(&fb->fb_helper);
  248         if (rv != 0) {
  249                 device_printf(drm_dev->dev, "Cannot add all connectors: %d\n",
  250                     rv);
  251                 goto err_fini;
  252         }
  253 
  254         rv = drm_fb_helper_initial_config(&fb->fb_helper, 32);
  255         if (rv != 0) {
  256                 device_printf(drm_dev->dev,
  257                     "Cannot set initial config: %d\n", rv);
  258                 goto err_fini;
  259         }
  260         /* XXXX Setup initial mode for FB */
  261         /* drm_fb_helper_set_par(fb->fb_helper.fbdev); */
  262         return 0;
  263 
  264 err_fini:
  265         drm_fb_helper_fini(&fb->fb_helper);
  266         return (rv);
  267 }
  268 
  269 int
  270 tegra_drm_fb_create(struct drm_device *drm, struct drm_file *file,
  271     struct drm_mode_fb_cmd2 *cmd, struct drm_framebuffer **fb_res)
  272 {
  273         int hsub, vsub, i;
  274         int width, height, size, bpp;
  275         struct tegra_bo *planes[4];
  276         struct drm_gem_object *gem_obj;
  277         struct tegra_fb *fb;
  278         int rv, nplanes;
  279 
  280         hsub = drm_format_horz_chroma_subsampling(cmd->pixel_format);
  281         vsub = drm_format_vert_chroma_subsampling(cmd->pixel_format);
  282 
  283         nplanes = drm_format_num_planes(cmd->pixel_format);
  284         for (i = 0; i < nplanes; i++) {
  285                 width = cmd->width;
  286                 height = cmd->height;
  287                 if (i != 0) {
  288                         width /= hsub;
  289                         height /= vsub;
  290                 }
  291                 gem_obj = drm_gem_object_lookup(drm, file, cmd->handles[i]);
  292                 if (gem_obj == NULL) {
  293                         rv = -ENXIO;
  294                         goto fail;
  295                 }
  296 
  297                 bpp = drm_format_plane_cpp(cmd->pixel_format, i);
  298                 size = (height - 1) * cmd->pitches[i] +
  299                     width * bpp + cmd->offsets[i];
  300                 if (gem_obj->size < size) {
  301                         rv = -EINVAL;
  302                         goto fail;
  303                 }
  304                 planes[i] = container_of(gem_obj, struct tegra_bo, gem_obj);
  305         }
  306 
  307         rv = fb_alloc(drm, cmd, planes, nplanes, &fb);
  308         if (rv != 0)
  309                 goto fail;
  310 
  311         *fb_res = &fb->drm_fb;
  312         return (0);
  313 
  314 fail:
  315         while (i--)
  316                 drm_gem_object_unreference_unlocked(&planes[i]->gem_obj);
  317         return (rv);
  318 }
  319 
  320 void
  321 tegra_drm_fb_destroy(struct drm_device *drm_dev)
  322 {
  323         struct fb_info *info;
  324         struct tegra_fb *fb;
  325         struct tegra_drm *drm;
  326 
  327         drm = container_of(drm_dev, struct tegra_drm, drm_dev);
  328         fb = drm->fb;
  329         if (fb == NULL)
  330                 return;
  331         info = fb->fb_helper.fbdev;
  332         drm_framebuffer_remove(&fb->drm_fb);
  333         framebuffer_release(info);
  334         drm_fb_helper_fini(&fb->fb_helper);
  335         drm_framebuffer_cleanup(&fb->drm_fb);
  336         free(fb, DRM_MEM_DRIVER);
  337         drm->fb = NULL;
  338 }

Cache object: c11db66ffbc483ebfceaaaa6b2ba0464


[ 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.