0001
0002
0003
0004
0005
0006
0007
0008
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
0033
0034
0035 if (is_drm_iommu_supported(drm_dev))
0036 return 0;
0037
0038 flags = exynos_gem->flags;
0039
0040
0041
0042
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
0172
0173
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 }