• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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