]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/blame - drivers/gpu/drm/exynos/exynos_drm_fb.c
UBUNTU: Ubuntu-5.3.0-29.31
[mirror_ubuntu-eoan-kernel.git] / drivers / gpu / drm / exynos / exynos_drm_fb.c
CommitLineData
2874c5fd 1// SPDX-License-Identifier: GPL-2.0-or-later
1c248b7d
ID
2/* exynos_drm_fb.c
3 *
4 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
5 * Authors:
6 * Inki Dae <inki.dae@samsung.com>
7 * Joonyoung Shim <jy0922.shim@samsung.com>
8 * Seung-Woo Kim <sw0312.kim@samsung.com>
1c248b7d
ID
9 */
10
d6562a29 11#include <drm/drm_atomic.h>
910874a8 12#include <drm/drm_atomic_helper.h>
fcd70cd3
DV
13#include <drm/drm_crtc.h>
14#include <drm/drm_fb_helper.h>
2bda34d7 15#include <drm/drm_fourcc.h>
b11954a6 16#include <drm/drm_gem_framebuffer_helper.h>
fcd70cd3 17#include <drm/drm_probe_helper.h>
2bda34d7 18#include <drm/exynos_drm.h>
1c248b7d 19
2bda34d7 20#include "exynos_drm_crtc.h"
7db3eba6 21#include "exynos_drm_drv.h"
1c248b7d 22#include "exynos_drm_fb.h"
25928a39 23#include "exynos_drm_fbdev.h"
1c248b7d 24
0519f9a1 25static int check_fb_gem_memory_type(struct drm_device *drm_dev,
813fd67b 26 struct exynos_drm_gem *exynos_gem)
0519f9a1
ID
27{
28 unsigned int flags;
29
30 /*
31 * if exynos drm driver supports iommu then framebuffer can use
32 * all the buffer types.
33 */
34 if (is_drm_iommu_supported(drm_dev))
35 return 0;
36
813fd67b 37 flags = exynos_gem->flags;
0519f9a1
ID
38
39 /*
6244bd65
SK
40 * Physically non-contiguous memory type for framebuffer is not
41 * supported without IOMMU.
0519f9a1
ID
42 */
43 if (IS_NONCONTIG_BUFFER(flags)) {
6f83d208
ID
44 DRM_DEV_ERROR(drm_dev->dev,
45 "Non-contiguous GEM memory is not supported.\n");
0519f9a1
ID
46 return -EINVAL;
47 }
48
49 return 0;
50}
51
800ba2b5 52static const struct drm_framebuffer_funcs exynos_drm_fb_funcs = {
b11954a6
DS
53 .destroy = drm_gem_fb_destroy,
54 .create_handle = drm_gem_fb_create_handle,
1c248b7d
ID
55};
56
e1533c08
JS
57struct drm_framebuffer *
58exynos_drm_framebuffer_init(struct drm_device *dev,
1eb83451 59 const struct drm_mode_fb_cmd2 *mode_cmd,
813fd67b 60 struct exynos_drm_gem **exynos_gem,
d56125af 61 int count)
1c248b7d 62{
ff059fcb 63 struct drm_framebuffer *fb;
d56125af 64 int i;
1c248b7d
ID
65 int ret;
66
ff059fcb
DS
67 fb = kzalloc(sizeof(*fb), GFP_KERNEL);
68 if (!fb)
1c248b7d 69 return ERR_PTR(-ENOMEM);
1c248b7d 70
d56125af 71 for (i = 0; i < count; i++) {
813fd67b 72 ret = check_fb_gem_memory_type(dev, exynos_gem[i]);
d56125af
JS
73 if (ret < 0)
74 goto err;
75
ff059fcb 76 fb->obj[i] = &exynos_gem[i]->base;
d56125af
JS
77 }
78
ff059fcb 79 drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);
94e30d93 80
ff059fcb 81 ret = drm_framebuffer_init(dev, fb, &exynos_drm_fb_funcs);
d56125af 82 if (ret < 0) {
6f83d208
ID
83 DRM_DEV_ERROR(dev->dev,
84 "failed to initialize framebuffer\n");
d56125af 85 goto err;
1c248b7d
ID
86 }
87
ff059fcb 88 return fb;
d56125af
JS
89
90err:
ff059fcb 91 kfree(fb);
d56125af 92 return ERR_PTR(ret);
1c248b7d
ID
93}
94
e1533c08
JS
95static struct drm_framebuffer *
96exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
1eb83451 97 const struct drm_mode_fb_cmd2 *mode_cmd)
1c248b7d 98{
1899bd57 99 const struct drm_format_info *info = drm_get_format_info(dev, mode_cmd);
813fd67b 100 struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER];
8d31758e
JS
101 struct drm_framebuffer *fb;
102 int i;
103 int ret;
229d3534 104
1899bd57
MS
105 for (i = 0; i < info->num_planes; i++) {
106 unsigned int height = (i == 0) ? mode_cmd->height :
107 DIV_ROUND_UP(mode_cmd->height, info->vsub);
108 unsigned long size = height * mode_cmd->pitches[i] +
109 mode_cmd->offsets[i];
110
e978de54
MS
111 exynos_gem[i] = exynos_drm_gem_get(file_priv,
112 mode_cmd->handles[i]);
113 if (!exynos_gem[i]) {
6f83d208
ID
114 DRM_DEV_ERROR(dev->dev,
115 "failed to lookup gem object\n");
979c0c7e 116 ret = -ENOENT;
dcbb85a1 117 goto err;
229d3534
SWK
118 }
119
1899bd57
MS
120 if (size > exynos_gem[i]->size) {
121 i++;
122 ret = -EINVAL;
123 goto err;
124 }
229d3534
SWK
125 }
126
813fd67b 127 fb = exynos_drm_framebuffer_init(dev, mode_cmd, exynos_gem, i);
8d31758e
JS
128 if (IS_ERR(fb)) {
129 ret = PTR_ERR(fb);
dcbb85a1 130 goto err;
f2c0095a
DV
131 }
132
8d31758e 133 return fb;
979c0c7e 134
dcbb85a1 135err:
8d31758e 136 while (i--)
e978de54 137 exynos_drm_gem_put(exynos_gem[i]);
979c0c7e 138
979c0c7e 139 return ERR_PTR(ret);
1c248b7d
ID
140}
141
0488f50e 142dma_addr_t exynos_drm_fb_dma_addr(struct drm_framebuffer *fb, int index)
1c248b7d 143{
7b30508f 144 struct exynos_drm_gem *exynos_gem;
1c248b7d 145
e0c7a510
CH
146 if (WARN_ON_ONCE(index >= MAX_FB_BUFFER))
147 return 0;
229d3534 148
7b30508f
DS
149 exynos_gem = to_exynos_gem(fb->obj[index]);
150 return exynos_gem->dma_addr + fb->offsets[index];
1c248b7d
ID
151}
152
41cbf0fd 153static struct drm_mode_config_helper_funcs exynos_drm_mode_config_helpers = {
81a099ac 154 .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
41cbf0fd
ID
155};
156
e6ecefaa 157static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
e1533c08 158 .fb_create = exynos_user_fb_create,
d2936153 159 .output_poll_changed = drm_fb_helper_output_poll_changed,
a7da5cfe 160 .atomic_check = drm_atomic_helper_check,
41cbf0fd 161 .atomic_commit = drm_atomic_helper_commit,
1c248b7d
ID
162};
163
164void exynos_drm_mode_config_init(struct drm_device *dev)
165{
166 dev->mode_config.min_width = 0;
167 dev->mode_config.min_height = 0;
168
169 /*
170 * set max width and height as default value(4096x4096).
171 * this value would be used to check framebuffer size limitation
172 * at drm_mode_addfb().
173 */
174 dev->mode_config.max_width = 4096;
175 dev->mode_config.max_height = 4096;
176
177 dev->mode_config.funcs = &exynos_drm_mode_config_funcs;
41cbf0fd 178 dev->mode_config.helper_private = &exynos_drm_mode_config_helpers;
f40031c2
TJ
179
180 dev->mode_config.allow_fb_modifiers = true;
a7da5cfe
PU
181
182 dev->mode_config.normalize_zpos = true;
1c248b7d 183}