1 /**************************************************************************
5 Copyright 2017 Samsung Electronics co., Ltd. All Rights Reserved.
7 Contact: SooChan Lim <sc1.lim@samsung.com>
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sub license, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial portions
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
24 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 **************************************************************************/
35 #include <linux/media-bus-format.h>
38 #include "tdm_nexell.h"
40 typedef struct _tdm_nexell_pp_buffer {
44 struct list_head link;
45 } tdm_nexell_pp_buffer;
47 typedef struct _tdm_nexell_pp_data {
48 tdm_nexell_data *nexell_data;
52 struct list_head pending_buffer_list;
54 tdm_pp_done_handler done_func;
57 struct list_head link;
60 #define MAX_PLANE_NUM 3
69 typedef struct _tdm_nexell_scaler_context {
71 int src_fds[MAX_PLANE_NUM];
72 int src_stride[MAX_PLANE_NUM];
73 unsigned int src_width;
74 unsigned int src_height;
75 unsigned int src_code;
78 int dst_fds[MAX_PLANE_NUM];
79 int dst_stride[MAX_PLANE_NUM];
80 unsigned int dst_width;
81 unsigned int dst_height;
82 unsigned int dst_code;
85 } tdm_nexell_scaler_context;
87 static tbm_format pp_formats[] = {
91 #define NUM_PP_FORMAT (sizeof(pp_formats) / sizeof(pp_formats[0]))
92 #define IOC_NX_MAGIC 0x6e78 /* nx */
94 IOCTL_SCALER_SET_AND_RUN = _IO(IOC_NX_MAGIC, 1),
98 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
101 static int pp_list_init;
102 static struct list_head pp_list;
105 _tdm_drm_ioctl(int fd, unsigned long request, void *arg)
110 ret = ioctl(fd, request, arg);
111 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
117 _tdm_gem_to_dmafd(int drm_fd, int gem_fd)
120 struct drm_prime_handle arg = {0, };
123 ret = _tdm_drm_ioctl(drm_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &arg);
131 _tdm_nexell_pp_convert(tdm_nexell_pp_buffer *buffer, tdm_info_pp *info, int drm_fd, int scaler_fd)
133 tdm_nexell_scaler_context ctx;
134 unsigned int src_y_stride;
135 unsigned int src_c_stride;
136 unsigned int dst_y_stride;
137 unsigned int dst_c_stride;
138 tbm_bo bo_src = NULL;
139 tbm_bo bo_dst = NULL;
143 bo_src = tbm_surface_internal_get_bo(buffer->src, 0);
144 RETURN_VAL_IF_FAIL(bo_src != NULL, TDM_ERROR_OPERATION_FAILED);
145 handle_src = (__u32)tbm_bo_get_handle(bo_src, TBM_DEVICE_DEFAULT).u32;
146 ctx.src_fds[0] = _tdm_gem_to_dmafd(drm_fd, handle_src);
147 RETURN_VAL_IF_FAIL(ctx.src_fds[0] >= 0, TDM_ERROR_OPERATION_FAILED);
149 ctx.src_fds[1] = ctx.src_fds[0];
150 ctx.src_fds[2] = ctx.src_fds[0];
152 bo_dst = tbm_surface_internal_get_bo(buffer->dst, 0);
153 if (bo_dst == NULL) {
154 close(ctx.src_fds[0]);
155 return TDM_ERROR_OPERATION_FAILED;
157 handle_dst = (__u32)tbm_bo_get_handle(bo_dst, TBM_DEVICE_DEFAULT).u32;
158 ctx.dst_fds[0] = _tdm_gem_to_dmafd(drm_fd, handle_dst);
159 if (ctx.dst_fds[0] < 0) {
160 close(ctx.src_fds[0]);
161 return TDM_ERROR_OPERATION_FAILED;
164 ctx.dst_fds[1] = ctx.dst_fds[0];
165 ctx.dst_fds[2] = ctx.dst_fds[0];
167 src_y_stride = ALIGN(info->src_config.size.h, 32);
168 src_c_stride = ALIGN(src_y_stride >> 1, 16);
169 dst_y_stride = ALIGN(info->dst_config.size.h, 8);
170 dst_c_stride = ALIGN(dst_y_stride >> 1, 4);
172 ctx.src_plane_num = 1;
173 ctx.src_width = info->src_config.size.h;
174 ctx.src_height = info->src_config.size.v;
175 ctx.src_code = MEDIA_BUS_FMT_YUYV8_2X8;
176 ctx.src_stride[0] = src_y_stride;
177 ctx.src_stride[1] = src_c_stride;
178 ctx.src_stride[2] = src_c_stride;
180 ctx.dst_plane_num = 1;
181 ctx.dst_width = info->dst_config.size.h;
182 ctx.dst_height = info->dst_config.size.v;
183 ctx.dst_code = MEDIA_BUS_FMT_YUYV8_2X8;
184 ctx.dst_stride[0] = dst_y_stride;
185 ctx.dst_stride[1] = dst_c_stride;
186 ctx.dst_stride[2] = dst_c_stride;
188 ctx.crop.x = info->src_config.pos.x;
189 ctx.crop.y = info->src_config.pos.y;
190 ctx.crop.width = info->src_config.pos.w;
191 ctx.crop.height = info->src_config.pos.h;
193 TDM_DBG("pp %p(%d, %d). src(%dx%d, (%d,%d,%d) (%d,%d,%d)) dst(%dx%d, (%d,%d,%d) (%d,%d,%d)) crop(%dx%d, %dx%d)", info, drm_fd, scaler_fd,
194 ctx.src_width, ctx.src_height, ctx.src_stride[0], ctx.src_stride[1], ctx.src_stride[2], ctx.src_fds[0], ctx.src_fds[1], ctx.src_fds[2],
195 ctx.dst_width, ctx.dst_height, ctx.dst_stride[0], ctx.dst_stride[1], ctx.dst_stride[2], ctx.dst_fds[0], ctx.dst_fds[1], ctx.dst_fds[2],
196 ctx.crop.x, ctx.crop.y, ctx.crop.width, ctx.crop.height);
198 if (ioctl(scaler_fd, IOCTL_SCALER_SET_AND_RUN, &ctx) < 0) {
199 TDM_ERR("IOCTL_SCALER_SET_AND_RUN failed");
202 close(ctx.src_fds[0]);
203 close(ctx.dst_fds[0]);
205 return TDM_ERROR_NONE;
209 tdm_nexell_pp_get_capability(tdm_nexell_data *nexell_data, tdm_caps_pp *caps)
214 TDM_ERR("invalid params");
215 return TDM_ERROR_INVALID_PARAMETER;
218 if (nexell_data->scaler_fd < 0 ) {
219 TDM_ERR("no scaler_fd. not support pp.");
220 return TDM_ERROR_BAD_MODULE;
223 caps->capabilities = TDM_PP_CAPABILITY_SYNC | TDM_PP_CAPABILITY_SCANOUT | TDM_PP_CAPABILITY_NO_TRANSFORM_ROTATION;
225 caps->format_count = NUM_PP_FORMAT;
227 /* will be freed in frontend */
228 caps->formats = calloc(1, sizeof pp_formats);
229 if (!caps->formats) {
230 TDM_ERR("alloc failed");
231 return TDM_ERROR_OUT_OF_MEMORY;
233 for (i = 0; i < caps->format_count; i++)
234 caps->formats[i] = pp_formats[i];
238 caps->max_w = -1; /* not defined */
240 caps->preferred_align = 32;
242 return TDM_ERROR_NONE;
246 tdm_nexell_pp_create(tdm_nexell_data *nexell_data, tdm_error *error)
248 tdm_nexell_pp_data *pp_data = NULL;
250 if (nexell_data->scaler_fd < 0 ) {
251 TDM_ERR("no scaler_fd.");
253 *error = TDM_ERROR_BAD_MODULE;
257 pp_data = calloc(1, sizeof(tdm_nexell_pp_data));
259 TDM_ERR("alloc failed");
261 *error = TDM_ERROR_OUT_OF_MEMORY;
265 pp_data->nexell_data = nexell_data;
267 LIST_INITHEAD(&pp_data->pending_buffer_list);
271 LIST_INITHEAD(&pp_list);
273 LIST_ADDTAIL(&pp_data->link, &pp_list);
279 nexell_pp_destroy(tdm_pp *pp)
281 tdm_nexell_pp_data *pp_data = pp;
282 tdm_nexell_pp_buffer *b = NULL, *bb = NULL;
287 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
292 LIST_DEL(&pp_data->link);
298 nexell_pp_set_info(tdm_pp *pp, tdm_info_pp *info)
300 tdm_nexell_pp_data *pp_data = pp;
302 RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
303 RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
305 pp_data->info = *info;
307 return TDM_ERROR_NONE;
311 nexell_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
313 tdm_nexell_pp_data *pp_data = pp;
314 tdm_nexell_pp_buffer *buffer;
316 RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
317 RETURN_VAL_IF_FAIL(src, TDM_ERROR_INVALID_PARAMETER);
318 RETURN_VAL_IF_FAIL(dst, TDM_ERROR_INVALID_PARAMETER);
320 buffer = calloc(1, sizeof(tdm_nexell_pp_buffer));
322 TDM_ERR("alloc failed");
323 return TDM_ERROR_NONE;
326 LIST_ADDTAIL(&buffer->link, &pp_data->pending_buffer_list);
331 return TDM_ERROR_NONE;
335 nexell_pp_commit(tdm_pp *pp)
337 tdm_nexell_pp_data *pp_data = pp;
338 tdm_nexell_pp_buffer *b = NULL, *bb = NULL;
339 tdm_nexell_data *nexell_data;
342 RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
344 nexell_data = pp_data->nexell_data;
346 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
349 ret = _tdm_nexell_pp_convert(b, &pp_data->info, nexell_data->drm_fd, nexell_data->scaler_fd);
350 RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
352 if (pp_data->done_func)
353 pp_data->done_func(pp_data,
356 pp_data->done_user_data);
360 return TDM_ERROR_NONE;
364 nexell_pp_set_done_handler(tdm_pp *pp, tdm_pp_done_handler func, void *user_data)
366 tdm_nexell_pp_data *pp_data = pp;
368 RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
369 RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
371 pp_data->done_func = func;
372 pp_data->done_user_data = user_data;
374 return TDM_ERROR_NONE;