Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* exynos_drm_fb.c
0003  *
0004  * Copyright (c) 2011 Samsung Electronics Co., Ltd.
0005  * Authors:
0006  *  Inki Dae <inki.dae@samsung.com>
0007  *  Joonyoung Shim <jy0922.shim@samsung.com>
0008  *  Seung-Woo Kim <sw0312.kim@samsung.com>
0009  */
0010 
0011 #include <drm/drm_atomic.h>
0012 #include <drm/drm_atomic_helper.h>
0013 #include <drm/drm_crtc.h>
0014 #include <drm/drm_fb_helper.h>
0015 #include <drm/drm_framebuffer.h>
0016 #include <drm/drm_fourcc.h>
0017 #include <drm/drm_gem_framebuffer_helper.h>
0018 #include <drm/drm_probe_helper.h>
0019 #include <drm/exynos_drm.h>
0020 
0021 #include "exynos_drm_crtc.h"
0022 #include "exynos_drm_drv.h"
0023 #include "exynos_drm_fb.h"
0024 #include "exynos_drm_fbdev.h"
0025 
0026 static int check_fb_gem_memory_type(struct drm_device *drm_dev,
0027                     struct exynos_drm_gem *exynos_gem)
0028 {
0029     unsigned int flags;
0030 
0031     /*
0032      * if exynos drm driver supports iommu then framebuffer can use
0033      * all the buffer types.
0034      */
0035     if (is_drm_iommu_supported(drm_dev))
0036         return 0;
0037 
0038     flags = exynos_gem->flags;
0039 
0040     /*
0041      * Physically non-contiguous memory type for framebuffer is not
0042      * supported without IOMMU.
0043      */
0044     if (IS_NONCONTIG_BUFFER(flags)) {
0045         DRM_DEV_ERROR(drm_dev->dev,
0046                   "Non-contiguous GEM memory is not supported.\n");
0047         return -EINVAL;
0048     }
0049 
0050     return 0;
0051 }
0052 
0053 static const struct drm_framebuffer_funcs exynos_drm_fb_funcs = {
0054     .destroy    = drm_gem_fb_destroy,
0055     .create_handle  = drm_gem_fb_create_handle,
0056 };
0057 
0058 struct drm_framebuffer *
0059 exynos_drm_framebuffer_init(struct drm_device *dev,
0060                 const struct drm_mode_fb_cmd2 *mode_cmd,
0061                 struct exynos_drm_gem **exynos_gem,
0062                 int count)
0063 {
0064     struct drm_framebuffer *fb;
0065     int i;
0066     int ret;
0067 
0068     fb = kzalloc(sizeof(*fb), GFP_KERNEL);
0069     if (!fb)
0070         return ERR_PTR(-ENOMEM);
0071 
0072     for (i = 0; i < count; i++) {
0073         ret = check_fb_gem_memory_type(dev, exynos_gem[i]);
0074         if (ret < 0)
0075             goto err;
0076 
0077         fb->obj[i] = &exynos_gem[i]->base;
0078     }
0079 
0080     drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);
0081 
0082     ret = drm_framebuffer_init(dev, fb, &exynos_drm_fb_funcs);
0083     if (ret < 0) {
0084         DRM_DEV_ERROR(dev->dev,
0085                   "failed to initialize framebuffer\n");
0086         goto err;
0087     }
0088 
0089     return fb;
0090 
0091 err:
0092     kfree(fb);
0093     return ERR_PTR(ret);
0094 }
0095 
0096 static struct drm_framebuffer *
0097 exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
0098               const struct drm_mode_fb_cmd2 *mode_cmd)
0099 {
0100     const struct drm_format_info *info = drm_get_format_info(dev, mode_cmd);
0101     struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER];
0102     struct drm_framebuffer *fb;
0103     int i;
0104     int ret;
0105 
0106     for (i = 0; i < info->num_planes; i++) {
0107         unsigned int height = (i == 0) ? mode_cmd->height :
0108                      DIV_ROUND_UP(mode_cmd->height, info->vsub);
0109         unsigned long size = height * mode_cmd->pitches[i] +
0110                      mode_cmd->offsets[i];
0111 
0112         exynos_gem[i] = exynos_drm_gem_get(file_priv,
0113                            mode_cmd->handles[i]);
0114         if (!exynos_gem[i]) {
0115             DRM_DEV_ERROR(dev->dev,
0116                       "failed to lookup gem object\n");
0117             ret = -ENOENT;
0118             goto err;
0119         }
0120 
0121         if (size > exynos_gem[i]->size) {
0122             i++;
0123             ret = -EINVAL;
0124             goto err;
0125         }
0126     }
0127 
0128     fb = exynos_drm_framebuffer_init(dev, mode_cmd, exynos_gem, i);
0129     if (IS_ERR(fb)) {
0130         ret = PTR_ERR(fb);
0131         goto err;
0132     }
0133 
0134     return fb;
0135 
0136 err:
0137     while (i--)
0138         exynos_drm_gem_put(exynos_gem[i]);
0139 
0140     return ERR_PTR(ret);
0141 }
0142 
0143 dma_addr_t exynos_drm_fb_dma_addr(struct drm_framebuffer *fb, int index)
0144 {
0145     struct exynos_drm_gem *exynos_gem;
0146 
0147     if (WARN_ON_ONCE(index >= MAX_FB_BUFFER))
0148         return 0;
0149 
0150     exynos_gem = to_exynos_gem(fb->obj[index]);
0151     return exynos_gem->dma_addr + fb->offsets[index];
0152 }
0153 
0154 static struct drm_mode_config_helper_funcs exynos_drm_mode_config_helpers = {
0155     .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
0156 };
0157 
0158 static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
0159     .fb_create = exynos_user_fb_create,
0160     .output_poll_changed = drm_fb_helper_output_poll_changed,
0161     .atomic_check = drm_atomic_helper_check,
0162     .atomic_commit = drm_atomic_helper_commit,
0163 };
0164 
0165 void exynos_drm_mode_config_init(struct drm_device *dev)
0166 {
0167     dev->mode_config.min_width = 0;
0168     dev->mode_config.min_height = 0;
0169 
0170     /*
0171      * set max width and height as default value(4096x4096).
0172      * this value would be used to check framebuffer size limitation
0173      * at drm_mode_addfb().
0174      */
0175     dev->mode_config.max_width = 4096;
0176     dev->mode_config.max_height = 4096;
0177 
0178     dev->mode_config.funcs = &exynos_drm_mode_config_funcs;
0179     dev->mode_config.helper_private = &exynos_drm_mode_config_helpers;
0180 
0181     dev->mode_config.normalize_zpos = true;
0182 }