xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/rockchip/rockchip_drm_direct_show.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2 /*
3  * Copyright (c) 2022 Rockchip Electronics Co., Ltd.
4  * Author: Sandy Huang <hjc@rock-chips.com>
5  */
6 #include <linux/dma-buf-cache.h>
7 #include <linux/fdtable.h>
8 #include <drm/drm_atomic_uapi.h>
9 
10 #include "../drm_internal.h"
11 #include "rockchip_drm_direct_show.h"
12 
13 static int drm_ds_debug;
14 #define DRM_DS_DBG(format, ...) do {	\
15 	if (drm_ds_debug)	\
16 		pr_info("DRM_DS: %s(%d): " format, __func__, __LINE__, ## __VA_ARGS__);	\
17 	} while (0)
18 
19 #define DRM_DS_ERR(format, ...) \
20 	pr_info("ERR: DRM_DS: %s(%d): " format, __func__, __LINE__, ## __VA_ARGS__)
21 
rockchip_drm_get_dev(void)22 struct drm_device *rockchip_drm_get_dev(void)
23 {
24 	int i;
25 	char *name = "rockchip";
26 
27 	for (i = 0; i < 64; i++) {
28 		struct drm_minor *minor;
29 
30 		minor = drm_minor_acquire(i + DRM_MINOR_PRIMARY);
31 		if (IS_ERR(minor))
32 			continue;
33 		if (!minor->dev || !minor->dev->driver ||
34 		    !minor->dev->driver->name)
35 			continue;
36 		if (!name)
37 			return minor->dev;
38 		if (!strcmp(name, minor->dev->driver->name))
39 			return minor->dev;
40 	}
41 
42 	return NULL;
43 }
44 
rockchip_drm_direct_show_alloc_fb(struct drm_device * drm,struct rockchip_drm_direct_show_buffer * buffer)45 static int rockchip_drm_direct_show_alloc_fb(struct drm_device *drm,
46 					     struct rockchip_drm_direct_show_buffer *buffer)
47 {
48 	struct drm_gem_object *obj;
49 	struct drm_gem_object *objs[ROCKCHIP_MAX_FB_BUFFER];
50 	struct drm_mode_fb_cmd2 mode_cmd = { 0 };
51 	struct drm_framebuffer *fb;
52 	const struct drm_format_info *format_info = drm_format_info(buffer->pixel_format);
53 
54 	mode_cmd.offsets[0] = 0;
55 	mode_cmd.width = buffer->width;
56 	mode_cmd.height = buffer->height;
57 	mode_cmd.pitches[0] = buffer->pitch[0];
58 	mode_cmd.pixel_format = buffer->pixel_format;
59 	obj = &buffer->rk_gem_obj->base;
60 	objs[0] = obj;
61 
62 	if (format_info->is_yuv) {
63 		mode_cmd.offsets[1] = buffer->width * buffer->height;
64 		mode_cmd.pitches[1] = mode_cmd.pitches[0];
65 		objs[1] = obj;
66 	}
67 
68 	fb = rockchip_fb_alloc(drm, &mode_cmd, objs, format_info->num_planes);
69 	if (IS_ERR_OR_NULL(fb))
70 		return -ENOMEM;
71 
72 	buffer->fb = fb;
73 
74 	return 0;
75 }
76 
rockchip_drm_direct_show_alloc_buffer(struct drm_device * drm,struct rockchip_drm_direct_show_buffer * buffer)77 int rockchip_drm_direct_show_alloc_buffer(struct drm_device *drm,
78 					  struct rockchip_drm_direct_show_buffer *buffer)
79 {
80 	u32 min_pitch;
81 	const struct drm_format_info *format_info;
82 	struct drm_mode_create_dumb args;
83 	struct rockchip_gem_object *rk_obj;
84 	struct drm_gem_object *obj;
85 	struct dma_buf *dmabuf;
86 	int dmabuf_fd;
87 
88 	args.width = buffer->width;
89 	args.height = buffer->height;
90 	format_info = drm_format_info(buffer->pixel_format);
91 	args.bpp = rockchip_drm_get_bpp(format_info);
92 	min_pitch = args.width * DIV_ROUND_UP(args.bpp, 8);
93 	args.pitch = ALIGN(min_pitch, 64);
94 	args.size = args.pitch * args.height;
95 	args.flags = buffer->flag;
96 
97 	if (format_info->is_yuv) {
98 		int bpp = 0;
99 
100 		bpp = format_info->cpp[1] * 8;
101 		min_pitch = args.width * DIV_ROUND_UP(bpp, 8);
102 		min_pitch = ALIGN(min_pitch, 64);
103 		args.size += min_pitch * args.height / format_info->hsub / format_info->vsub;
104 	}
105 	/* create a gem obj with kmap flag */
106 	rk_obj = rockchip_gem_create_object(drm, args.size, true, args.flags);
107 	if (IS_ERR(rk_obj)) {
108 		DRM_DS_ERR("create rk_obj failed\n");
109 		return -ENOMEM;
110 	}
111 	obj = &rk_obj->base;
112 
113 	buffer->bpp = args.bpp;
114 	buffer->pitch[0] = args.pitch;
115 	buffer->vir_addr[0] = rk_obj->kvaddr;
116 	buffer->phy_addr[0] = rk_obj->dma_handle;
117 	buffer->rk_gem_obj = rk_obj;
118 	if (format_info->is_yuv) {
119 		buffer->vir_addr[1] = buffer->vir_addr[0] + buffer->width * buffer->height;
120 		buffer->pitch[1] = buffer->pitch[0];
121 		buffer->phy_addr[1] = buffer->phy_addr[0] + buffer->width * buffer->height;
122 	}
123 
124 	/* to get drm fb */
125 	rockchip_drm_direct_show_alloc_fb(drm, buffer);
126 
127 	/* to get dma buffer fd */
128 	mutex_lock(&drm->object_name_lock);
129 	dmabuf = drm->driver->gem_prime_export(obj, 0);
130 	if (IS_ERR(dmabuf)) {
131 		mutex_unlock(&drm->object_name_lock);
132 		goto err_gem_free;
133 	}
134 	obj->dma_buf = dmabuf;
135 	get_dma_buf(obj->dma_buf);
136 	drm_gem_dmabuf_release(obj->dma_buf);
137 	mutex_unlock(&drm->object_name_lock);
138 
139 	dmabuf_fd = dma_buf_fd(dmabuf, 0);
140 	if (dmabuf_fd < 0) {
141 		DRM_DS_ERR("failed dma_buf_fd, ret %d\n", dmabuf_fd);
142 		goto err_free_dmabuf;
143 	}
144 	buffer->dmabuf_fd = dmabuf_fd;
145 
146 	DRM_DS_DBG("alloc buffer: 0x%p, dma buf fd:%d, args.pitch:%d\n", buffer->rk_gem_obj, dmabuf_fd, args.pitch);
147 
148 	return 0;
149 
150 err_free_dmabuf:
151 	dma_buf_put(dmabuf);
152 err_gem_free:
153 	drm_gem_object_put(&rk_obj->base);
154 
155 	return -ENOMEM;
156 }
157 
rockchip_drm_direct_show_free_buffer(struct drm_device * drm,struct rockchip_drm_direct_show_buffer * buffer)158 void rockchip_drm_direct_show_free_buffer(struct drm_device *drm,
159 					  struct rockchip_drm_direct_show_buffer *buffer)
160 {
161 	struct drm_gem_object *obj = &buffer->rk_gem_obj->base;
162 
163 	DRM_DS_DBG("free buffer: 0x%p\n", buffer->rk_gem_obj);
164 
165 	mutex_lock(&drm->object_name_lock);
166 	if (obj->dma_buf) {
167 		dma_buf_put(obj->dma_buf);
168 		obj->dma_buf = NULL;
169 	}
170 	mutex_unlock(&drm->object_name_lock);
171 
172 	drm_gem_object_put(obj);
173 }
174 
rockchip_drm_direct_show_get_plane(struct drm_device * drm,const char * name)175 struct drm_plane *rockchip_drm_direct_show_get_plane(struct drm_device *drm, const char *name)
176 {
177 	struct drm_plane *plane;
178 
179 	drm_for_each_plane(plane, drm) {
180 		if (!strncmp(plane->name, name, DRM_PROP_NAME_LEN))
181 			break;
182 	}
183 	if (!plane) {
184 		DRM_DS_ERR("failed to find plane:%s!\n", name);
185 		return NULL;
186 	}
187 
188 	DRM_DS_DBG("get plane[%s] success\n", plane->name);
189 
190 	return plane;
191 }
192 
rockchip_drm_direct_show_get_crtc(struct drm_device * drm,const char * name)193 struct drm_crtc *rockchip_drm_direct_show_get_crtc(struct drm_device *drm, const char *name)
194 {
195 	struct drm_crtc *crtc = NULL;
196 	bool crtc_active = false;
197 
198 	drm_for_each_crtc(crtc, drm) {
199 		if (name == NULL) {
200 			if (crtc->state && crtc->state->active) {
201 				crtc_active = true;
202 				break;
203 			}
204 		} else {
205 			if (crtc->state && crtc->state->active &&
206 			    !strncmp(crtc->name, name, DRM_PROP_NAME_LEN)) {
207 				crtc_active = true;
208 				break;
209 			}
210 		}
211 	}
212 
213 	if (crtc_active == false) {
214 		DRM_DS_ERR("failed to find active crtc\n");
215 		return NULL;
216 	}
217 	DRM_DS_DBG("get crtc[%s] success\n", crtc->name);
218 
219 	return crtc;
220 }
221 
222 static int
rockchip_drm_direct_show_set_property_value(struct drm_mode_object * obj,struct drm_property * property,uint64_t val)223 rockchip_drm_direct_show_set_property_value(struct drm_mode_object *obj,
224 					    struct drm_property *property,
225 					    uint64_t val)
226 {
227 	int i;
228 
229 	for (i = 0; i < obj->properties->count; i++) {
230 		if (obj->properties->properties[i] == property) {
231 			obj->properties->values[i] = val;
232 			return 0;
233 		}
234 	}
235 
236 	return -EINVAL;
237 }
238 
239 static struct drm_property *
rockchip_drm_direct_show_find_prop(struct drm_device * dev,struct drm_mode_object * obj,char * prop_name)240 rockchip_drm_direct_show_find_prop(struct drm_device *dev,
241 				   struct drm_mode_object *obj,
242 				   char *prop_name)
243 {
244 	int i = 0;
245 
246 	if (!obj->properties)
247 		return NULL;
248 
249 	for (i = 0; i < obj->properties->count; i++) {
250 		struct drm_property *prop = obj->properties->properties[i];
251 
252 		if (!strncmp(prop->name, prop_name, DRM_PROP_NAME_LEN))
253 			return prop;
254 	}
255 
256 	return NULL;
257 }
258 
rockchip_drm_direct_show_commit(struct drm_device * drm,struct rockchip_drm_direct_show_commit_info * commit_info)259 int rockchip_drm_direct_show_commit(struct drm_device *drm,
260 				    struct rockchip_drm_direct_show_commit_info *commit_info)
261 {
262 	int ret = 0;
263 	struct drm_plane *plane = commit_info->plane;
264 	struct drm_crtc *crtc = commit_info->crtc;
265 	struct drm_framebuffer *fb = commit_info->buffer->fb;
266 	struct drm_mode_config *conf = &drm->mode_config;
267 	struct drm_property *zpos_prop;
268 
269 	/*setplane overlay zpos top*/
270 	zpos_prop = rockchip_drm_direct_show_find_prop(drm, &plane->base, "zpos");
271 	if (!zpos_prop)
272 		DRM_DS_ERR("failed to find plane zpos prop, ret:%d\n", ret);
273 
274 	drm_modeset_lock_all(drm);
275 	/* set the max zpos value */
276 	if (commit_info->top_zpos && zpos_prop) {
277 		ret = rockchip_drm_direct_show_set_property_value(&plane->base,
278 								  zpos_prop,
279 								  zpos_prop->values[1]);
280 		if (ret)
281 			DRM_DS_ERR("failed to set plane zpos prop, ret:%d\n", ret);
282 		plane->state->zpos = zpos_prop->values[1];
283 	}
284 	ret = plane->funcs->update_plane(plane, crtc, fb,
285 					 commit_info->dst_x, commit_info->dst_y,
286 					 commit_info->dst_w, commit_info->dst_h,
287 					 commit_info->src_x << 16,
288 					 commit_info->src_y << 16,
289 					 commit_info->src_w << 16,
290 					 commit_info->src_h << 16,
291 					 conf->acquire_ctx);
292 	drm_modeset_unlock_all(drm);
293 
294 	if (ret)
295 		return ret;
296 
297 	DRM_DS_DBG("commit success: plane[%s], crtc[%s], src[%dx%d@%dx%d], dst[%dx%d@%dx%d]\n",
298 		   plane->name, crtc->name,
299 		   commit_info->src_w, commit_info->src_h,
300 		   commit_info->src_x, commit_info->src_y,
301 		   commit_info->dst_w, commit_info->dst_h,
302 		   commit_info->dst_x, commit_info->dst_y);
303 
304 	return ret;
305 }
306 
rockchip_drm_direct_show_disable_plane(struct drm_device * drm,struct drm_plane * plane)307 int rockchip_drm_direct_show_disable_plane(struct drm_device *drm, struct drm_plane *plane)
308 {
309 	int ret = 0;
310 	struct drm_mode_config *conf = &drm->mode_config;
311 
312 	DRM_DS_DBG("disable plane: %s\n", plane->name);
313 	drm_modeset_lock_all(drm);
314 	ret = plane->funcs->disable_plane(plane, conf->acquire_ctx);
315 	drm_modeset_unlock_all(drm);
316 
317 	return ret;
318 }
319