1 /*
2 * Copyright (C) 2019 Allwinnertech Co.Ltd
3 * Authors: zhengwanyu
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 */
11 #include <drm/drm_crtc_helper.h>
12 #include <drm/drm_fb_helper.h>
13 #include <drm/drm_fourcc.h>
14 #include <drm/drm_gem_framebuffer_helper.h>
15
16 #include "sunxi_drm_fb.h"
17 #include "sunxi_drm_gem.h"
18
19 /*void sunxi_fb_dump(struct drm_framebuffer *fb)
20 {
21 int i;
22 struct sunxi_drm_fb *sunxi_fb = to_sunxi_fb(fb);
23
24 DRM_INFO("Framebuffer info:\n");
25 DRM_INFO("FB ID:%u\n", fb->base.id);
26
27 if (sunxi_fb->flag == DRM_CREATE_FB)
28 DRM_INFO("DRM_CREATE_FB:\n");
29 else if (sunxi_fb->flag == FBDEV_CREATE_FB)
30 DRM_INFO("FBDEV_CREATE_FB:\n");
31 else
32 DRM_INFO("ERROR Flag!!!\n");
33
34 DRM_INFO("pitches(3~0): %u %u %u %u\n", fb->pitches[3], fb->pitches[2],
35 fb->pitches[1], fb->pitches[0]);
36 DRM_INFO("offsets(3~0): %u %u %u %u\n", fb->offsets[3], fb->offsets[2],
37 fb->offsets[1], fb->offsets[0]);
38 DRM_INFO("modifier(3~0): %llu %llu %llu %llu\n",
39 fb->modifier[3], fb->modifier[2],
40 fb->modifier[1], fb->modifier[0]);
41 DRM_INFO("width:%u height:%u\n", fb->width, fb->height);
42 DRM_INFO("depth:%u bpp:%d\n", fb->depth, fb->bits_per_pixel);
43 DRM_INFO("flags:%d\n", fb->flags);
44 DRM_INFO("Pixel_format:%c%c%c%c", (char)(fb->pixel_format & 0xff),
45 (char)((fb->pixel_format >> 8) & 0xff),
46 (char)((fb->pixel_format >> 16) & 0xff),
47 (char)((fb->pixel_format >> 24) & 0xff));
48 DRM_INFO("\n");
49
50 for (i = 0; i < 4; i++) {
51 if (!sunxi_fb->obj[i])
52 continue;
53 DRM_INFO("Pixel-Plane%d info:\n", i);
54 DRM_INFO("pitches:%u offsets:%u modifier:%llu\n",
55 fb->pitches[i], fb->offsets[i], fb->modifier[i]);
56 sunxi_gem_dump(&sunxi_fb->obj[i]->base);
57 DRM_INFO("\n");
58 }
59 }*/
60
61 /*ssize_t sunxi_drm_fb_show(char *buf, struct drm_framebuffer *fb)
62 {
63 ssize_t n = 0;
64 int i;
65 struct sunxi_drm_fb *sunxi_fb = to_sunxi_fb(fb);
66
67 if (sunxi_fb->flag == DRM_CREATE_FB)
68 n += sprintf(buf + n, "DRM_CREATE_FB:\n");
69 else if (sunxi_fb->flag == FBDEV_CREATE_FB)
70 n += sprintf(buf + n, "FBDEV_CREATE_FB:\n");
71 else
72 n += sprintf(buf + n, "ERROR Flag!!!\n");
73
74 n += sprintf(buf + n, "drm_mode_obj id:%d type:0x%x\n",
75 fb->base.id, fb->base.type);
76 n += sprintf(buf + n, "fb width:%u height:%u depth:%u bpp:%d "
77 "flags:%d pixel_format:%c%c%c%c\n",
78 fb->width, fb->height, fb->depth, fb->bits_per_pixel, fb->flags,
79 (char)(fb->format->format & 0xff),
80 (char)((fb->format->format >> 8) & 0xff),
81 (char)((fb->format->format >> 16) & 0xff),
82 (char)((fb->format->format >> 24) & 0xff));
83
84 for (i = 0; i < 4; i++) {
85 if (!sunxi_fb->obj[i])
86 continue;
87 n += sprintf(buf + n, "[fb(obj_id:%u) pixel component %d info]:\n",
88 fb->base.id, i);
89 n += sprintf(buf + n, "pitches:%u offsets:%u modifier:%llu\n",
90 fb->pitches[i], fb->offsets[i], fb->modifier[i]);
91 n += sunxi_drm_gem_show(buf + n, sunxi_fb->obj[i],
92 fb->offsets[i], fb->pitches[i]);
93 }
94
95 return n;
96 }*/
97
98
sunxi_drm_fb_destroy(struct drm_framebuffer * fb)99 void sunxi_drm_fb_destroy(struct drm_framebuffer *fb)
100 {
101 struct sunxi_drm_fb *sunxi_fb = to_sunxi_fb(fb);
102 int i;
103
104 for (i = 0; i < 4; i++) {
105 if (sunxi_fb->obj[i])
106 drm_gem_object_put(&sunxi_fb->obj[i]->base);
107 }
108
109 drm_framebuffer_cleanup(fb);
110 kfree(sunxi_fb);
111 }
112
sunxi_drm_fb_create_handle(struct drm_framebuffer * fb,struct drm_file * file_priv,unsigned int * handle)113 int sunxi_drm_fb_create_handle(struct drm_framebuffer *fb,
114 struct drm_file *file_priv, unsigned int *handle)
115 {
116 struct sunxi_drm_fb *sunxi_fb = to_sunxi_fb(fb);
117
118 return drm_gem_handle_create(file_priv,
119 &sunxi_fb->obj[0]->base, handle);
120 }
121
122 static struct drm_framebuffer_funcs sunxi_drm_fb_funcs = {
123 .destroy = sunxi_drm_fb_destroy,
124 .create_handle = sunxi_drm_fb_create_handle,
125 };
126
sunxi_drm_fb_get_funcs(void)127 struct drm_framebuffer_funcs *sunxi_drm_fb_get_funcs(void)
128 {
129 return &sunxi_drm_fb_funcs;
130 }
131
sunxi_drm_fb_alloc(struct drm_device * dev,const struct drm_mode_fb_cmd2 * mode_cmd,struct sunxi_drm_gem_object ** obj,unsigned int num_planes,int flag,const struct drm_framebuffer_funcs * funcs)132 struct sunxi_drm_fb *sunxi_drm_fb_alloc(struct drm_device *dev,
133 const struct drm_mode_fb_cmd2 *mode_cmd,
134 struct sunxi_drm_gem_object **obj,
135 unsigned int num_planes, int flag,
136 const struct drm_framebuffer_funcs *funcs)
137 {
138 struct sunxi_drm_fb *sunxi_fb;
139 int ret;
140 int i;
141
142 sunxi_fb = kzalloc(sizeof(*sunxi_fb), GFP_KERNEL);
143 if (!sunxi_fb)
144 return ERR_PTR(-ENOMEM);
145
146 drm_helper_mode_fill_fb_struct(dev, &sunxi_fb->fb, mode_cmd);
147
148 for (i = 0; i < num_planes; i++)
149 sunxi_fb->obj[i] = obj[i];
150
151 ret = drm_framebuffer_init(dev, &sunxi_fb->fb, funcs);
152 if (ret) {
153 DRM_ERROR("Failed to initialize framebuffer: %d\n", ret);
154 kfree(sunxi_fb);
155 return ERR_PTR(ret);
156 }
157
158 sunxi_fb->flag = flag;
159
160 return sunxi_fb;
161 }
162
163 /**
164 * sunxi_drm_fb_create_with_funcs() - helper function for the
165 * &drm_mode_config_funcs ->fb_create
166 * callback function
167 * @dev: DRM device
168 * @file_priv: drm file for the ioctl call
169 * @mode_cmd: metadata from the userspace fb creation request
170 * @funcs: vtable to be used for the new framebuffer object
171 *
172 * This can be used to set &drm_framebuffer_funcs for drivers that need the
173 * dirty() callback. Use sunxi_drm_fb_create() if you don't need to change
174 * &drm_framebuffer_funcs.
175 */
sunxi_drm_fb_create_with_funcs(struct drm_device * dev,struct drm_file * file_priv,const struct drm_mode_fb_cmd2 * mode_cmd,const struct drm_framebuffer_funcs * funcs)176 struct drm_framebuffer *sunxi_drm_fb_create_with_funcs(struct drm_device *dev,
177 struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd,
178 const struct drm_framebuffer_funcs *funcs)
179 {
180 struct sunxi_drm_fb *sunxi_fb;
181 struct sunxi_drm_gem_object *objs[4];
182 struct drm_gem_object *obj;
183 int ret;
184 unsigned int i;
185
186 const struct drm_format_info *info = drm_get_format_info(dev, mode_cmd);
187
188 for (i = 0; i < info->num_planes; i++) {
189 unsigned int width = mode_cmd->width / (i ? info->hsub : 1);
190 unsigned int height = mode_cmd->height / (i ? info->vsub : 1);
191 unsigned int min_size;
192
193 obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]);
194 if (!obj) {
195 DRM_ERROR("Failed to lookup GEM object, handle:0x%x\n",
196 mode_cmd->handles[i]);
197 ret = -ENXIO;
198 goto err_gem_object_unreference;
199 }
200
201 min_size = (height - 1) * mode_cmd->pitches[i]
202 + width * info->cpp[i];
203 + mode_cmd->offsets[i];
204
205 if (obj->size < min_size) {
206 DRM_ERROR("obj[%d] size so small, "
207 "obj->size:%d min_size:%d\n",
208 i, (int)obj->size, min_size);
209 drm_gem_object_put(obj);
210 ret = -EINVAL;
211 goto err_gem_object_unreference;
212 }
213 objs[i] = to_sunxi_drm_gem_obj(obj);
214 }
215
216 sunxi_fb = sunxi_drm_fb_alloc(dev, mode_cmd, objs, i,
217 DRM_CREATE_FB, funcs);
218 if (IS_ERR(sunxi_fb)) {
219 DRM_ERROR("Failed to alloc fb\n");
220 ret = PTR_ERR(sunxi_fb);
221 goto err_gem_object_unreference;
222 }
223
224 return &sunxi_fb->fb;
225
226 err_gem_object_unreference:
227 for (i--; i >= 0; i--)
228 drm_gem_object_put(&objs[i]->base);
229 return ERR_PTR(ret);
230 }
231
232 /**
233 * sunxi_drm_fb_create() - &drm_mode_config_funcs ->fb_create callback function
234 * @dev: DRM device
235 * @file_priv: drm file for the ioctl call
236 * @mode_cmd: metadata from the userspace fb creation request
237 *
238 * If your hardware has special alignment or pitch requirements these should be
239 * checked before calling this function. Use sunxi_drm_fb_create_with_funcs() if
240 * you need to set &drm_framebuffer_funcs ->dirty.
241 */
sunxi_drm_fb_create(struct drm_device * dev,struct drm_file * file_priv,const struct drm_mode_fb_cmd2 * mode_cmd)242 struct drm_framebuffer *sunxi_drm_fb_create(struct drm_device *dev,
243 struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd)
244 {
245 return sunxi_drm_fb_create_with_funcs(dev, file_priv, mode_cmd,
246 &sunxi_drm_fb_funcs);
247 }
248
249 /**
250 * sunxi_drm_fb_get_gem_obj() - Get SUNXI GEM object for framebuffer
251 * @fb: The framebuffer
252 * @plane: Which plane
253 *
254 * Return the SUNXI GEM object for given framebuffer.
255 *
256 * This function will usually be called from the CRTC callback functions.
257 */
sunxi_drm_fb_get_gem_obj(struct drm_framebuffer * fb,unsigned int plane)258 struct sunxi_drm_gem_object *sunxi_drm_fb_get_gem_obj(struct drm_framebuffer *fb,
259 unsigned int plane)
260 {
261 struct sunxi_drm_fb *sunxi_fb = to_sunxi_fb(fb);
262
263 if (plane >= 4)
264 return NULL;
265
266 return sunxi_fb->obj[plane];
267 }
268
269 /**
270 * sunxi_drm_fb_prepare_fb() - Prepare SUNXI framebuffer
271 * @plane: Which plane
272 * @state: Plane state attach fence to
273 *
274 * This should be put into prepare_fb hook of struct &drm_plane_helper_funcs .
275 *
276 * This function checks if the plane FB has an dma-buf attached, extracts
277 * the exclusive fence and attaches it to plane state for the atomic helper
278 * to wait on.
279 *
280 * There is no need for cleanup_fb for SUNXI based framebuffer drivers.
281 */
sunxi_drm_fb_prepare_fb(struct drm_plane * plane,struct drm_plane_state * state)282 int sunxi_drm_fb_prepare_fb(struct drm_plane *plane,
283 struct drm_plane_state *state)
284 {
285 /*struct dma_buf *dma_buf;
286 struct dma_fence *fence;
287
288 if ((plane->state->fb == state->fb) || !state->fb)
289 return 0;
290
291 dma_buf = sunxi_drm_fb_get_gem_obj(state->fb, 0)->base.dma_buf;
292 if (dma_buf)
293 drm_gem_fb_prepare_fb(plane, state);*/
294
295 return 0;
296 }
297