Commit | Line | Data |
---|---|---|
70007c4e JC |
1 | /* |
2 | * Copyright (C) 2008 The Android Open Source Project | |
3 | * Copyright@ Samsung Electronics Co. LTD | |
4 | * | |
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | * you may not use this file except in compliance with the License. | |
7 | * You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
16 | */ | |
17 | ||
18 | /*! | |
19 | * \file exynos_gscaler.c | |
20 | * \brief header file for Gscaler HAL | |
21 | * \author ShinWon Lee (shinwon.lee@samsung.com) | |
22 | * \date 2012/01/09 | |
23 | * | |
24 | * <b>Revision History: </b> | |
25 | * - 2012.01.09 : ShinWon Lee(shinwon.lee@samsung.com) \n | |
26 | * Create | |
27 | * | |
28 | * - 2012.02.07 : ShinWon Lee(shinwon.lee@samsung.com) \n | |
29 | * Change file name to exynos_gscaler.h | |
30 | * | |
31 | * - 2012.02.09 : Sangwoo, Parkk(sw5771.park@samsung.com) \n | |
32 | * Use Multiple Gscaler by Multiple Process | |
33 | * | |
34 | * - 2012.02.20 : Sangwoo, Park(sw5771.park@samsung.com) \n | |
35 | * Add exynos_gsc_set_rotation() API | |
36 | * | |
37 | * - 2012.02.20 : ShinWon Lee(shinwon.lee@samsung.com) \n | |
38 | * Add size constrain | |
39 | * | |
40 | */ | |
41 | ||
42 | //#define LOG_NDEBUG 0 | |
43 | #include "exynos_gsc_utils.h" | |
44 | ||
45 | static unsigned int m_gsc_get_plane_count( | |
46 | int v4l_pixel_format) | |
47 | { | |
48 | int plane_count = 0; | |
49 | ||
50 | switch (v4l_pixel_format) { | |
51 | case V4L2_PIX_FMT_RGB32: | |
52 | case V4L2_PIX_FMT_BGR32: | |
53 | case V4L2_PIX_FMT_RGB24: | |
54 | case V4L2_PIX_FMT_RGB565: | |
55 | case V4L2_PIX_FMT_RGB555X: | |
56 | case V4L2_PIX_FMT_RGB444: | |
57 | case V4L2_PIX_FMT_YUYV: | |
58 | case V4L2_PIX_FMT_UYVY: | |
23dac69c SK |
59 | case V4L2_PIX_FMT_NV16: |
60 | case V4L2_PIX_FMT_NV61: | |
70007c4e JC |
61 | plane_count = 1; |
62 | break; | |
63 | case V4L2_PIX_FMT_NV12M: | |
64 | case V4L2_PIX_FMT_NV12MT_16X16: | |
2607aa30 | 65 | case V4L2_PIX_FMT_NV12: |
70007c4e | 66 | case V4L2_PIX_FMT_NV21: |
66e91991 | 67 | case V4L2_PIX_FMT_NV21M: |
70007c4e JC |
68 | plane_count = 2; |
69 | break; | |
70 | case V4L2_PIX_FMT_YVU420M: | |
71 | case V4L2_PIX_FMT_YUV422P: | |
4006f615 | 72 | case V4L2_PIX_FMT_YUV420M: |
70007c4e JC |
73 | plane_count = 3; |
74 | break; | |
75 | default: | |
6134b8bb | 76 | ALOGE("%s::unmatched v4l_pixel_format color_space(0x%x)\n", |
70007c4e JC |
77 | __func__, v4l_pixel_format); |
78 | plane_count = -1; | |
79 | break; | |
80 | } | |
81 | ||
82 | return plane_count; | |
83 | } | |
84 | ||
85 | static unsigned int m_gsc_get_plane_size( | |
86 | unsigned int *plane_size, | |
87 | unsigned int width, | |
88 | unsigned int height, | |
89 | int v4l_pixel_format) | |
90 | { | |
91 | switch (v4l_pixel_format) { | |
92 | /* 1 plane */ | |
93 | case V4L2_PIX_FMT_RGB32: | |
94 | case V4L2_PIX_FMT_BGR32: | |
95 | plane_size[0] = width * height * 4; | |
96 | plane_size[1] = 0; | |
97 | plane_size[2] = 0; | |
98 | break; | |
99 | case V4L2_PIX_FMT_RGB24: | |
100 | plane_size[0] = width * height * 3; | |
101 | plane_size[1] = 0; | |
102 | plane_size[2] = 0; | |
103 | break; | |
104 | case V4L2_PIX_FMT_RGB565: | |
105 | case V4L2_PIX_FMT_RGB555X: | |
106 | case V4L2_PIX_FMT_RGB444: | |
107 | case V4L2_PIX_FMT_YUYV: | |
108 | case V4L2_PIX_FMT_UYVY: | |
109 | plane_size[0] = width * height * 2; | |
110 | plane_size[1] = 0; | |
111 | plane_size[2] = 0; | |
112 | break; | |
113 | /* 2 planes */ | |
114 | case V4L2_PIX_FMT_NV12M: | |
2607aa30 | 115 | case V4L2_PIX_FMT_NV12: |
70007c4e | 116 | case V4L2_PIX_FMT_NV21: |
66e91991 | 117 | case V4L2_PIX_FMT_NV21M: |
e6a0625b JC |
118 | plane_size[0] = width * height; |
119 | plane_size[1] = width * (height / 2); | |
120 | plane_size[2] = 0; | |
121 | break; | |
70007c4e JC |
122 | case V4L2_PIX_FMT_NV16: |
123 | case V4L2_PIX_FMT_NV61: | |
35b3cc21 JS |
124 | plane_size[0] = width * height * 2; |
125 | plane_size[1] = 0; | |
70007c4e JC |
126 | plane_size[2] = 0; |
127 | break; | |
128 | case V4L2_PIX_FMT_NV12MT_16X16: | |
129 | plane_size[0] = ALIGN(width, 16) * ALIGN(height, 16); | |
130 | plane_size[1] = ALIGN(width, 16) * ALIGN(height / 2, 8); | |
131 | plane_size[2] = 0; | |
132 | break; | |
133 | /* 3 planes */ | |
134 | case V4L2_PIX_FMT_YVU420M: | |
135 | case V4L2_PIX_FMT_YUV422P: | |
136 | plane_size[0] = width * height; | |
137 | plane_size[1] = (width / 2) * (height / 2); | |
138 | plane_size[2] = (width / 2) * (height / 2); | |
139 | break; | |
140 | default: | |
6134b8bb | 141 | ALOGE("%s::unmatched v4l_pixel_format color_space(0x%x)\n", |
70007c4e JC |
142 | __func__, v4l_pixel_format); |
143 | return -1; | |
144 | break; | |
145 | } | |
146 | ||
147 | return 0; | |
148 | } | |
149 | ||
150 | static int m_exynos_gsc_multiple_of_n( | |
151 | int number, int N) | |
152 | { | |
153 | int result = number; | |
154 | switch (N) { | |
155 | case 1: | |
156 | case 2: | |
157 | case 4: | |
158 | case 8: | |
159 | case 16: | |
160 | case 32: | |
161 | case 64: | |
162 | case 128: | |
163 | case 256: | |
164 | result = (number - (number & (N-1))); | |
165 | break; | |
166 | default: | |
167 | result = number - (number % N); | |
168 | break; | |
169 | } | |
170 | return result; | |
171 | } | |
172 | ||
173 | static bool m_exynos_gsc_check_src_size( | |
174 | unsigned int *w, unsigned int *h, | |
175 | unsigned int *crop_x, unsigned int *crop_y, | |
176 | unsigned int *crop_w, unsigned int *crop_h, | |
177 | int v4l2_colorformat) | |
178 | { | |
179 | if (*w < GSC_MIN_W_SIZE || *h < GSC_MIN_H_SIZE) { | |
6134b8bb | 180 | ALOGE("%s::too small size (w : %d < %d) (h : %d < %d)", |
70007c4e JC |
181 | __func__, GSC_MIN_W_SIZE, *w, GSC_MIN_H_SIZE, *h); |
182 | return false; | |
183 | } | |
184 | ||
185 | if (*crop_w < GSC_MIN_W_SIZE || *crop_h < GSC_MIN_H_SIZE) { | |
6134b8bb | 186 | ALOGE("%s::too small size (w : %d < %d) (h : %d < %d)", |
70007c4e JC |
187 | __func__, GSC_MIN_W_SIZE,* crop_w, GSC_MIN_H_SIZE, *crop_h); |
188 | return false; | |
189 | } | |
190 | ||
191 | switch (v4l2_colorformat) { | |
192 | // YUV420 | |
193 | case V4L2_PIX_FMT_YUV420M: | |
194 | case V4L2_PIX_FMT_YVU420M: | |
195 | case V4L2_PIX_FMT_NV12M: | |
196 | case V4L2_PIX_FMT_NV12MT: | |
197 | case V4L2_PIX_FMT_NV21: | |
198 | case V4L2_PIX_FMT_NV21M: | |
199 | *w = (*w + 15) & ~15; | |
200 | *h = (*h + 15) & ~15; | |
201 | //*w = m_exynos_gsc_multiple_of_n(*w, 16); | |
202 | //*h = m_exynos_gsc_multiple_of_n(*h, 16); | |
203 | *crop_w = m_exynos_gsc_multiple_of_n(*crop_w, 4); | |
204 | *crop_h = m_exynos_gsc_multiple_of_n(*crop_h, 4); | |
205 | break; | |
206 | // YUV422 | |
207 | case V4L2_PIX_FMT_YUYV: | |
208 | case V4L2_PIX_FMT_YUV422P: | |
209 | case V4L2_PIX_FMT_UYVY: | |
210 | case V4L2_PIX_FMT_NV16: | |
211 | case V4L2_PIX_FMT_YVYU: | |
212 | case V4L2_PIX_FMT_VYUY: | |
213 | *h = (*h + 7) & ~7; | |
214 | //*h = m_exynos_gsc_multiple_of_n(*h, 8); | |
215 | *crop_w = m_exynos_gsc_multiple_of_n(*crop_w, 4); | |
216 | *crop_h = m_exynos_gsc_multiple_of_n(*crop_h, 2); | |
217 | break; | |
218 | // RGB | |
219 | case V4L2_PIX_FMT_RGB32: | |
220 | case V4L2_PIX_FMT_RGB24: | |
221 | case V4L2_PIX_FMT_RGB565: | |
222 | case V4L2_PIX_FMT_BGR32: | |
223 | case V4L2_PIX_FMT_RGB555X: | |
224 | case V4L2_PIX_FMT_RGB444: | |
225 | default: | |
226 | *h = (*h + 7) & ~7; | |
227 | //*h = m_exynos_gsc_multiple_of_n(*h, 8); | |
228 | *crop_w = m_exynos_gsc_multiple_of_n(*crop_w, 2); | |
229 | *crop_h = m_exynos_gsc_multiple_of_n(*crop_h, 2); | |
230 | break; | |
231 | } | |
232 | ||
233 | return true; | |
234 | } | |
235 | ||
236 | static bool m_exynos_gsc_check_dst_size( | |
237 | unsigned int *w, unsigned int *h, | |
238 | unsigned int *crop_x, unsigned int *crop_y, | |
239 | unsigned int *crop_w, unsigned int *crop_h, | |
240 | int v4l2_colorformat, | |
241 | int rotation) | |
242 | { | |
243 | unsigned int *new_w; | |
244 | unsigned int *new_h; | |
245 | unsigned int *new_crop_w; | |
246 | unsigned int *new_crop_h; | |
247 | ||
70007c4e JC |
248 | new_w = w; |
249 | new_h = h; | |
250 | new_crop_w = crop_w; | |
251 | new_crop_h = crop_h; | |
70007c4e JC |
252 | |
253 | if (*w < GSC_MIN_W_SIZE || *h < GSC_MIN_H_SIZE) { | |
6134b8bb | 254 | ALOGE("%s::too small size (w : %d < %d) (h : %d < %d)", |
70007c4e JC |
255 | __func__, GSC_MIN_W_SIZE, *w, GSC_MIN_H_SIZE, *h); |
256 | return false; | |
257 | } | |
258 | ||
259 | if (*crop_w < GSC_MIN_W_SIZE || *crop_h < GSC_MIN_H_SIZE) { | |
6134b8bb | 260 | ALOGE("%s::too small size (w : %d < %d) (h : %d < %d)", |
70007c4e JC |
261 | __func__, GSC_MIN_W_SIZE,* crop_w, GSC_MIN_H_SIZE, *crop_h); |
262 | return false; | |
263 | } | |
264 | ||
265 | switch (v4l2_colorformat) { | |
266 | // YUV420 | |
267 | case V4L2_PIX_FMT_NV12M: | |
268 | case V4L2_PIX_FMT_NV12MT: | |
269 | case V4L2_PIX_FMT_NV21: | |
66e91991 | 270 | case V4L2_PIX_FMT_NV21M: |
70007c4e JC |
271 | case V4L2_PIX_FMT_YUV420M: |
272 | case V4L2_PIX_FMT_YVU420M: | |
273 | *new_w = m_exynos_gsc_multiple_of_n(*new_w, 2); | |
274 | *new_h = m_exynos_gsc_multiple_of_n(*new_h, 2); | |
275 | break; | |
276 | // YUV422 | |
277 | case V4L2_PIX_FMT_YUYV: | |
278 | case V4L2_PIX_FMT_YUV422P: | |
279 | case V4L2_PIX_FMT_UYVY: | |
280 | case V4L2_PIX_FMT_NV16: | |
281 | case V4L2_PIX_FMT_YVYU: | |
282 | case V4L2_PIX_FMT_VYUY: | |
283 | *new_w = m_exynos_gsc_multiple_of_n(*new_w, 2); | |
284 | break; | |
285 | // RGB | |
286 | case V4L2_PIX_FMT_RGB32: | |
287 | case V4L2_PIX_FMT_RGB24: | |
288 | case V4L2_PIX_FMT_RGB565: | |
289 | case V4L2_PIX_FMT_BGR32: | |
290 | case V4L2_PIX_FMT_RGB555X: | |
291 | case V4L2_PIX_FMT_RGB444: | |
292 | default: | |
293 | break; | |
294 | } | |
295 | ||
296 | return true; | |
297 | } | |
298 | ||
299 | static int m_exynos_gsc_output_create( | |
300 | struct GSC_HANDLE *gsc_handle, | |
301 | int dev_num, | |
302 | int out_mode) | |
303 | { | |
e6a0625b | 304 | struct media_device *media0; |
70007c4e JC |
305 | struct media_entity *gsc_sd_entity; |
306 | struct media_entity *gsc_vd_entity; | |
307 | struct media_entity *sink_sd_entity; | |
308 | struct media_link *links; | |
309 | char node[32]; | |
310 | char devname[32]; | |
311 | unsigned int cap; | |
312 | int i; | |
313 | int fd = 0; | |
e6a0625b JC |
314 | |
315 | Exynos_gsc_In(); | |
316 | ||
70007c4e JC |
317 | if ((out_mode != GSC_OUT_FIMD) && |
318 | (out_mode != GSC_OUT_TV)) | |
319 | return -1; | |
320 | ||
321 | gsc_handle->out_mode = out_mode; | |
322 | /* GSCX => FIMD_WINX : arbitrary linking is not allowed */ | |
323 | if ((out_mode == GSC_OUT_FIMD) && | |
52cf3b06 | 324 | (dev_num > 2)) |
70007c4e JC |
325 | return -1; |
326 | ||
327 | /* media0 */ | |
328 | sprintf(node, "%s%d", PFX_NODE_MEDIADEV, 0); | |
329 | media0 = exynos_media_open(node); | |
330 | if (media0 == NULL) { | |
6134b8bb | 331 | ALOGE("%s::exynos_media_open failed (node=%s)", __func__, node); |
70007c4e JC |
332 | return false; |
333 | } | |
334 | ||
335 | /* Get the sink subdev entity by name and make the node of sink subdev*/ | |
336 | if (out_mode == GSC_OUT_FIMD) | |
337 | sprintf(devname, PFX_FIMD_ENTITY, dev_num); | |
338 | else | |
339 | sprintf(devname, PFX_MXR_ENTITY, 0); | |
340 | ||
e6a0625b | 341 | sink_sd_entity = exynos_media_get_entity_by_name(media0, devname, strlen(devname)); |
70007c4e JC |
342 | sink_sd_entity->fd = exynos_subdev_open_devname(devname, O_RDWR); |
343 | if ( sink_sd_entity->fd < 0) { | |
6134b8bb | 344 | ALOGE("%s:: failed to open sink subdev node", __func__); |
70007c4e JC |
345 | goto gsc_output_err; |
346 | } | |
347 | ||
348 | /* get GSC video dev & sub dev entity by name*/ | |
349 | sprintf(devname, PFX_GSC_VIDEODEV_ENTITY, dev_num); | |
350 | gsc_vd_entity= exynos_media_get_entity_by_name(media0, devname, strlen(devname)); | |
351 | ||
352 | sprintf(devname, PFX_GSC_SUBDEV_ENTITY, dev_num); | |
353 | gsc_sd_entity= exynos_media_get_entity_by_name(media0, devname, strlen(devname)); | |
354 | ||
355 | /* gsc sub-dev open */ | |
356 | sprintf(devname, PFX_GSC_SUBDEV_ENTITY, dev_num); | |
357 | gsc_sd_entity->fd = exynos_subdev_open_devname(devname, O_RDWR); | |
358 | ||
359 | /* setup link : GSC : video device --> sub device */ | |
360 | for (i = 0; i < (int) gsc_vd_entity->num_links; i++) { | |
361 | links = &gsc_vd_entity->links[i]; | |
362 | ||
363 | if (links == NULL || | |
364 | links->source->entity != gsc_vd_entity || | |
365 | links->sink->entity != gsc_sd_entity) { | |
366 | continue; | |
367 | } else if (exynos_media_setup_link(media0, links->source, links->sink, MEDIA_LNK_FL_ENABLED) < 0) { | |
6134b8bb | 368 | ALOGE("%s::exynos_media_setup_link [src.entity=%d->sink.entity=%d] failed", |
70007c4e JC |
369 | __func__, links->source->entity->info.id, links->sink->entity->info.id); |
370 | return -1; | |
371 | } | |
372 | } | |
373 | ||
374 | /* setup link : GSC: sub device --> sink device */ | |
375 | for (i = 0; i < (int) gsc_sd_entity->num_links; i++) { | |
376 | links = &gsc_sd_entity->links[i]; | |
377 | ||
378 | if (links == NULL || links->source->entity != gsc_sd_entity || | |
379 | links->sink->entity != sink_sd_entity) { | |
380 | continue; | |
381 | } else if (exynos_media_setup_link(media0, links->source, links->sink, MEDIA_LNK_FL_ENABLED) < 0) { | |
6134b8bb | 382 | ALOGE("%s::exynos_media_setup_link [src.entity=%d->sink.entity=%d] failed", |
70007c4e JC |
383 | __func__, links->source->entity->info.id, links->sink->entity->info.id); |
384 | return -1; | |
385 | } | |
386 | } | |
387 | ||
388 | /* gsc video-dev open */ | |
389 | sprintf(devname, PFX_GSC_VIDEODEV_ENTITY, dev_num); | |
390 | gsc_vd_entity->fd = exynos_v4l2_open_devname(devname, O_RDWR); | |
391 | cap = V4L2_CAP_STREAMING | | |
392 | V4L2_CAP_VIDEO_OUTPUT_MPLANE; | |
393 | ||
394 | if (exynos_v4l2_querycap(gsc_vd_entity->fd, cap) == false) { | |
6134b8bb | 395 | ALOGE("%s::exynos_v4l2_querycap() fail", __func__); |
70007c4e JC |
396 | goto gsc_output_err; |
397 | } | |
398 | gsc_handle->gsc_sd_entity = gsc_sd_entity; | |
399 | gsc_handle->gsc_vd_entity = gsc_vd_entity; | |
400 | gsc_handle->sink_sd_entity = sink_sd_entity; | |
e6a0625b JC |
401 | gsc_handle->media0 = media0; |
402 | ||
403 | Exynos_gsc_Out(); | |
404 | ||
70007c4e JC |
405 | return 0; |
406 | ||
407 | gsc_output_err: | |
408 | /* to do */ | |
409 | return -1; | |
410 | ||
411 | } | |
412 | ||
e6a0625b | 413 | static int m_exynos_gsc_m2m_create( |
70007c4e JC |
414 | int dev) |
415 | { | |
416 | int fd = 0; | |
417 | int video_node_num; | |
418 | unsigned int cap; | |
419 | char node[32]; | |
420 | ||
e6a0625b JC |
421 | Exynos_gsc_In(); |
422 | ||
70007c4e JC |
423 | switch(dev) { |
424 | case 0: | |
425 | video_node_num = NODE_NUM_GSC_0; | |
426 | break; | |
427 | case 1: | |
428 | video_node_num = NODE_NUM_GSC_1; | |
429 | break; | |
430 | case 2: | |
431 | video_node_num = NODE_NUM_GSC_2; | |
432 | break; | |
433 | case 3: | |
434 | video_node_num = NODE_NUM_GSC_3; | |
435 | break; | |
436 | default: | |
6134b8bb | 437 | ALOGE("%s::unexpected dev(%d) fail", __func__, dev); |
70007c4e JC |
438 | return -1; |
439 | break; | |
440 | } | |
441 | ||
442 | sprintf(node, "%s%d", PFX_NODE_GSC, video_node_num); | |
443 | fd = exynos_v4l2_open(node, O_RDWR); | |
444 | if (fd < 0) { | |
6134b8bb | 445 | ALOGE("%s::exynos_v4l2_open(%s) fail", __func__, node); |
70007c4e JC |
446 | return -1; |
447 | } | |
448 | ||
449 | cap = V4L2_CAP_STREAMING | | |
450 | V4L2_CAP_VIDEO_OUTPUT_MPLANE | | |
451 | V4L2_CAP_VIDEO_CAPTURE_MPLANE; | |
452 | ||
453 | if (exynos_v4l2_querycap(fd, cap) == false) { | |
6134b8bb | 454 | ALOGE("%s::exynos_v4l2_querycap() fail", __func__); |
70007c4e JC |
455 | if (0 < fd) |
456 | close(fd); | |
457 | fd = 0; | |
458 | return -1; | |
459 | } | |
e6a0625b JC |
460 | |
461 | Exynos_gsc_Out(); | |
462 | ||
70007c4e JC |
463 | return fd; |
464 | } | |
465 | ||
466 | ||
e6a0625b | 467 | static bool m_exynos_gsc_out_destroy(struct GSC_HANDLE *gsc_handle) |
70007c4e JC |
468 | { |
469 | struct media_link * links; | |
470 | int i; | |
471 | ||
e6a0625b JC |
472 | Exynos_gsc_In(); |
473 | ||
70007c4e | 474 | if (gsc_handle == NULL) { |
6134b8bb | 475 | ALOGE("%s::gsc_handle is NULL", __func__); |
70007c4e JC |
476 | return false; |
477 | } | |
478 | ||
479 | if (gsc_handle->src.stream_on == true) { | |
480 | if (exynos_gsc_out_stop((void *)gsc_handle) < 0) | |
6134b8bb | 481 | ALOGE("%s::exynos_gsc_out_stop() fail", __func__); |
70007c4e JC |
482 | |
483 | gsc_handle->src.stream_on = false; | |
484 | } | |
485 | ||
e6a0625b | 486 | /* unlink : gscaler-out --> fimd */ |
70007c4e JC |
487 | for (i = 0; i < (int) gsc_handle->gsc_sd_entity->num_links; i++) { |
488 | links = &gsc_handle->gsc_sd_entity->links[i]; | |
489 | ||
490 | if (links == NULL || links->source->entity != gsc_handle->gsc_sd_entity || | |
491 | links->sink->entity != gsc_handle->sink_sd_entity) { | |
492 | continue; | |
493 | } else if (exynos_media_setup_link(gsc_handle->media0, links->source, | |
494 | links->sink, 0) < 0) { | |
6134b8bb | 495 | ALOGE("%s::exynos_media_setup_unlink [src.entity=%d->sink.entity=%d] failed", |
70007c4e JC |
496 | __func__, links->source->entity->info.id, links->sink->entity->info.id); |
497 | } | |
498 | } | |
499 | ||
500 | close(gsc_handle->gsc_vd_entity->fd); | |
501 | close(gsc_handle->gsc_sd_entity->fd); | |
502 | gsc_handle->gsc_vd_entity->fd = -1; | |
503 | gsc_handle->gsc_vd_entity->fd = -1; | |
504 | ||
e6a0625b JC |
505 | Exynos_gsc_Out(); |
506 | ||
70007c4e JC |
507 | return true; |
508 | ||
509 | } | |
510 | ||
511 | static bool m_exynos_gsc_destroy( | |
512 | struct GSC_HANDLE *gsc_handle) | |
513 | { | |
e6a0625b JC |
514 | Exynos_gsc_In(); |
515 | ||
70007c4e JC |
516 | if (gsc_handle->src.stream_on == true) { |
517 | if (exynos_v4l2_streamoff(gsc_handle->gsc_fd, gsc_handle->src.buf_type) < 0) | |
6134b8bb | 518 | ALOGE("%s::exynos_v4l2_streamoff() fail", __func__); |
70007c4e JC |
519 | |
520 | gsc_handle->src.stream_on = false; | |
521 | } | |
522 | ||
523 | if (gsc_handle->dst.stream_on == true) { | |
524 | if (exynos_v4l2_streamoff(gsc_handle->gsc_fd, gsc_handle->dst.buf_type) < 0) | |
6134b8bb | 525 | ALOGE("%s::exynos_v4l2_streamoff() fail", __func__); |
70007c4e JC |
526 | |
527 | gsc_handle->dst.stream_on = false; | |
528 | } | |
529 | ||
530 | if (0 < gsc_handle->gsc_fd) | |
531 | close(gsc_handle->gsc_fd); | |
532 | gsc_handle->gsc_fd = 0; | |
533 | ||
e6a0625b JC |
534 | Exynos_gsc_Out(); |
535 | ||
70007c4e JC |
536 | return true; |
537 | } | |
538 | ||
539 | bool m_exynos_gsc_find_and_trylock_and_create( | |
540 | struct GSC_HANDLE *gsc_handle) | |
541 | { | |
542 | int i = 0; | |
543 | bool flag_find_new_gsc = false; | |
544 | unsigned int total_sleep_time = 0; | |
545 | ||
e6a0625b JC |
546 | Exynos_gsc_In(); |
547 | ||
70007c4e JC |
548 | do { |
549 | for (i = 0; i < NUM_OF_GSC_HW; i++) { | |
550 | // HACK : HWComposer, HDMI uses gscaler with their own code. | |
551 | // So, This obj_mutex cannot defense their open() | |
e6a0625b | 552 | if (i == 0 || i == 3) |
70007c4e | 553 | continue; |
70007c4e JC |
554 | |
555 | if (exynos_mutex_trylock(gsc_handle->obj_mutex[i]) == true) { | |
556 | ||
557 | // destroy old one. | |
558 | m_exynos_gsc_destroy(gsc_handle); | |
559 | ||
560 | // create new one. | |
e6a0625b | 561 | gsc_handle->gsc_fd = m_exynos_gsc_m2m_create(i); |
70007c4e JC |
562 | if (gsc_handle->gsc_fd < 0) { |
563 | gsc_handle->gsc_fd = 0; | |
564 | exynos_mutex_unlock(gsc_handle->obj_mutex[i]); | |
565 | continue; | |
566 | } | |
567 | ||
568 | if (gsc_handle->cur_obj_mutex) | |
569 | exynos_mutex_unlock(gsc_handle->cur_obj_mutex); | |
570 | ||
571 | gsc_handle->cur_obj_mutex = gsc_handle->obj_mutex[i]; | |
572 | ||
573 | flag_find_new_gsc = true; | |
574 | break; | |
575 | } | |
576 | } | |
577 | ||
578 | // waiting for another process doesn't use gscaler. | |
579 | // we need to make decision how to do. | |
580 | if (flag_find_new_gsc == false) { | |
581 | usleep(GSC_WAITING_TIME_FOR_TRYLOCK); | |
582 | total_sleep_time += GSC_WAITING_TIME_FOR_TRYLOCK; | |
6134b8bb | 583 | ALOGV("%s::waiting for anthere process doens't use gscaler", __func__); |
70007c4e JC |
584 | } |
585 | ||
586 | } while( flag_find_new_gsc == false | |
587 | && total_sleep_time < MAX_GSC_WAITING_TIME_FOR_TRYLOCK); | |
588 | ||
589 | if (flag_find_new_gsc == false) | |
6134b8bb | 590 | ALOGE("%s::we don't have no available gsc.. fail", __func__); |
70007c4e | 591 | |
e6a0625b JC |
592 | Exynos_gsc_Out(); |
593 | ||
70007c4e JC |
594 | return flag_find_new_gsc; |
595 | } | |
596 | ||
597 | static bool m_exynos_gsc_set_format( | |
598 | int fd, | |
599 | struct gsc_info *info, | |
600 | bool force) | |
601 | { | |
e6a0625b JC |
602 | Exynos_gsc_In(); |
603 | ||
70007c4e JC |
604 | struct v4l2_requestbuffers req_buf; |
605 | int plane_count; | |
606 | ||
607 | plane_count = m_gsc_get_plane_count(info->v4l2_colorformat); | |
608 | if (plane_count < 0) { | |
6134b8bb | 609 | ALOGE("%s::not supported v4l2_colorformat", __func__); |
70007c4e JC |
610 | return false; |
611 | } | |
612 | ||
613 | if (force == false) { | |
614 | // format | |
615 | info->format.type = info->buf_type; | |
616 | if (exynos_v4l2_g_fmt(fd, &info->format) < 0) { | |
6134b8bb | 617 | ALOGE("%s::exynos_v4l2_g_fmt() fail type=%d", __func__, info->buf_type); |
70007c4e JC |
618 | return false; |
619 | } | |
620 | ||
621 | if (info->width != info->format.fmt.pix_mp.width || | |
622 | info->height != info->format.fmt.pix_mp.height || | |
623 | info->v4l2_colorformat != info->format.fmt.pix_mp.pixelformat) { | |
6134b8bb | 624 | ALOGV("%s::info is different..)", __func__); |
70007c4e JC |
625 | goto set_hw; |
626 | } | |
627 | ||
628 | // crop | |
629 | info->crop.type = info->buf_type; | |
630 | if (exynos_v4l2_g_crop(fd, &info->crop) < 0) { | |
6134b8bb | 631 | ALOGE("%s::exynos_v4l2_g_crop() fail", __func__); |
70007c4e JC |
632 | return false; |
633 | } | |
634 | ||
635 | if (info->crop_left != info->crop.c.left || | |
636 | info->crop_top != info->crop.c.top || | |
637 | info->crop_width != info->crop.c.width || | |
638 | info->crop_height != info->crop.c.height) { | |
6134b8bb | 639 | ALOGV("%s::crop is different..", __func__); |
70007c4e JC |
640 | goto set_hw; |
641 | } | |
642 | ||
643 | // rotation value; | |
644 | int value = 0; | |
645 | ||
646 | if (exynos_v4l2_g_ctrl(fd, V4L2_CID_ROTATE, &value) < 0) { | |
6134b8bb | 647 | ALOGE("%s::exynos_v4l2_g_ctrl(V4L2_CID_ROTATE) fail", __func__); |
70007c4e JC |
648 | return false; |
649 | } | |
650 | ||
651 | if (info->rotation != value) { | |
6134b8bb | 652 | ALOGV("%s::rotation is different..", __func__); |
70007c4e JC |
653 | goto set_hw; |
654 | } | |
655 | ||
656 | if (exynos_v4l2_g_ctrl(fd, V4L2_CID_VFLIP, &value) < 0) { | |
6134b8bb | 657 | ALOGE("%s::exynos_v4l2_g_ctrl(V4L2_CID_ROTATE) fail", __func__); |
70007c4e JC |
658 | return false; |
659 | } | |
660 | ||
661 | if (info->flip_horizontal != value) { | |
6134b8bb | 662 | ALOGV("%s::flip_horizontal is different..", __func__); |
70007c4e JC |
663 | goto set_hw; |
664 | } | |
665 | ||
666 | if (exynos_v4l2_g_ctrl(fd, V4L2_CID_HFLIP, &value) < 0) { | |
6134b8bb | 667 | ALOGE("%s::exynos_v4l2_g_ctrl(V4L2_CID_ROTATE) fail", __func__); |
70007c4e JC |
668 | return false; |
669 | } | |
670 | ||
671 | if (info->flip_vertical != value) { | |
6134b8bb | 672 | ALOGV("%s::flip_vertical is different..", __func__); |
70007c4e JC |
673 | goto set_hw; |
674 | } | |
675 | ||
676 | // skip s_fmt | |
6134b8bb | 677 | ALOGV("%s::fmt, crop is same with old-one, so skip s_fmt crop..", __func__); |
70007c4e JC |
678 | } |
679 | ||
680 | set_hw: | |
681 | ||
682 | if (info->stream_on == true) { | |
683 | if (exynos_v4l2_streamoff(fd, info->buf_type) < 0) { | |
6134b8bb | 684 | ALOGE("%s::exynos_v4l2_streamoff() fail", __func__); |
70007c4e JC |
685 | return false; |
686 | } | |
687 | info->stream_on = false; | |
688 | } | |
689 | ||
690 | if (exynos_v4l2_s_ctrl(fd, V4L2_CID_ROTATE, info->rotation) < 0) { | |
6134b8bb | 691 | ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_ROTATE) fail", __func__); |
70007c4e JC |
692 | return false; |
693 | } | |
694 | ||
695 | if (exynos_v4l2_s_ctrl(fd, V4L2_CID_VFLIP, info->flip_horizontal) < 0) { | |
6134b8bb | 696 | ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_VFLIP) fail", __func__); |
70007c4e JC |
697 | return false; |
698 | } | |
699 | ||
700 | if (exynos_v4l2_s_ctrl(fd, V4L2_CID_HFLIP, info->flip_vertical) < 0) { | |
6134b8bb | 701 | ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_HFLIP) fail", __func__); |
70007c4e JC |
702 | return false; |
703 | } | |
e6a0625b | 704 | info->format.type = info->buf_type; |
70007c4e JC |
705 | info->format.fmt.pix_mp.width = info->width; |
706 | info->format.fmt.pix_mp.height = info->height; | |
707 | info->format.fmt.pix_mp.pixelformat = info->v4l2_colorformat; | |
708 | info->format.fmt.pix_mp.field = V4L2_FIELD_ANY; | |
709 | info->format.fmt.pix_mp.num_planes = plane_count; | |
710 | ||
711 | if (exynos_v4l2_s_fmt(fd, &info->format) < 0) { | |
6134b8bb | 712 | ALOGE("%s::exynos_v4l2_s_fmt() fail", __func__); |
70007c4e JC |
713 | return false; |
714 | } | |
715 | ||
716 | info->crop.type = info->buf_type; | |
717 | info->crop.c.left = info->crop_left; | |
718 | info->crop.c.top = info->crop_top; | |
719 | info->crop.c.width = info->crop_width; | |
720 | info->crop.c.height = info->crop_height; | |
721 | ||
722 | if (exynos_v4l2_s_crop(fd, &info->crop) < 0) { | |
6134b8bb | 723 | ALOGE("%s::exynos_v4l2_s_crop() fail", __func__); |
70007c4e JC |
724 | return false; |
725 | } | |
726 | ||
727 | if (exynos_v4l2_s_ctrl(fd, V4L2_CID_CACHEABLE, info->cacheable) < 0) { | |
6134b8bb | 728 | ALOGE("%s::exynos_v4l2_s_ctrl() fail", __func__); |
70007c4e JC |
729 | return false; |
730 | } | |
731 | ||
732 | req_buf.count = 1; | |
733 | req_buf.type = info->buf_type; | |
776bd695 | 734 | req_buf.memory = V4L2_MEMORY_DMABUF; |
70007c4e | 735 | if (exynos_v4l2_reqbufs(fd, &req_buf) < 0) { |
6134b8bb | 736 | ALOGE("%s::exynos_v4l2_reqbufs() fail", __func__); |
70007c4e JC |
737 | return false; |
738 | } | |
739 | ||
e6a0625b JC |
740 | Exynos_gsc_Out(); |
741 | ||
70007c4e JC |
742 | return true; |
743 | } | |
744 | ||
745 | static bool m_exynos_gsc_set_addr( | |
746 | int fd, | |
747 | struct gsc_info *info) | |
748 | { | |
749 | unsigned int i; | |
750 | unsigned int plane_size[NUM_OF_GSC_PLANES]; | |
751 | ||
752 | m_gsc_get_plane_size(plane_size, | |
753 | info->width, | |
754 | info->height, | |
755 | info->v4l2_colorformat); | |
756 | ||
757 | info->buffer.index = 0; | |
758 | info->buffer.type = info->buf_type; | |
776bd695 | 759 | info->buffer.memory = V4L2_MEMORY_DMABUF; |
70007c4e JC |
760 | info->buffer.m.planes = info->planes; |
761 | info->buffer.length = info->format.fmt.pix_mp.num_planes; | |
762 | ||
763 | for (i = 0; i < info->format.fmt.pix_mp.num_planes; i++) { | |
776bd695 | 764 | info->buffer.m.planes[i].m.fd = (int)info->addr[i]; |
70007c4e JC |
765 | info->buffer.m.planes[i].length = plane_size[i]; |
766 | info->buffer.m.planes[i].bytesused = 0; | |
767 | } | |
768 | ||
769 | if (exynos_v4l2_qbuf(fd, &info->buffer) < 0) { | |
6134b8bb | 770 | ALOGE("%s::exynos_v4l2_qbuf() fail", __func__); |
70007c4e JC |
771 | return false; |
772 | } | |
773 | ||
774 | return true; | |
775 | } | |
776 | ||
777 | void *exynos_gsc_create( | |
778 | void) | |
779 | { | |
780 | int i = 0; | |
781 | int op_id = 0; | |
782 | char mutex_name[32]; | |
783 | ||
e6a0625b JC |
784 | Exynos_gsc_In(); |
785 | ||
70007c4e JC |
786 | struct GSC_HANDLE *gsc_handle = (struct GSC_HANDLE *)malloc(sizeof(struct GSC_HANDLE)); |
787 | if (gsc_handle == NULL) { | |
6134b8bb | 788 | ALOGE("%s::malloc(struct GSC_HANDLE) fail", __func__); |
70007c4e JC |
789 | goto err; |
790 | } | |
791 | ||
792 | gsc_handle->gsc_fd = 0; | |
793 | memset(&gsc_handle->src, 0, sizeof(struct gsc_info)); | |
794 | memset(&gsc_handle->dst, 0, sizeof(struct gsc_info)); | |
795 | ||
796 | gsc_handle->src.buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | |
797 | gsc_handle->dst.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | |
798 | ||
799 | gsc_handle->op_mutex = NULL; | |
800 | for (i = 0; i < NUM_OF_GSC_HW; i++) | |
801 | gsc_handle->obj_mutex[i] = NULL; | |
802 | ||
803 | gsc_handle->cur_obj_mutex = NULL; | |
804 | gsc_handle->flag_local_path = false; | |
805 | gsc_handle->flag_exclusive_open = false; | |
806 | ||
807 | srand(time(NULL)); | |
808 | op_id = rand() % 1000000; // just make random id | |
809 | sprintf(mutex_name, "%sOp%d", LOG_TAG, op_id); | |
810 | gsc_handle->op_mutex = exynos_mutex_create(EXYNOS_MUTEX_TYPE_PRIVATE, mutex_name); | |
811 | if (gsc_handle->op_mutex == NULL) { | |
6134b8bb | 812 | ALOGE("%s::exynos_mutex_create(%s) fail", __func__, mutex_name); |
70007c4e JC |
813 | goto err; |
814 | } | |
815 | ||
816 | exynos_mutex_lock(gsc_handle->op_mutex); | |
817 | ||
818 | // check if it is available | |
819 | for (i = 0; i < NUM_OF_GSC_HW; i++) { | |
820 | sprintf(mutex_name, "%sObject%d", LOG_TAG, i); | |
821 | ||
822 | gsc_handle->obj_mutex[i] = exynos_mutex_create(EXYNOS_MUTEX_TYPE_SHARED, mutex_name); | |
823 | if (gsc_handle->obj_mutex[i] == NULL) { | |
6134b8bb | 824 | ALOGE("%s::exynos_mutex_create(%s) fail", __func__, mutex_name); |
70007c4e JC |
825 | goto err; |
826 | } | |
827 | } | |
828 | ||
829 | if (m_exynos_gsc_find_and_trylock_and_create(gsc_handle) == false) { | |
6134b8bb | 830 | ALOGE("%s::m_exynos_gsc_find_and_trylock_and_create() fail", __func__); |
70007c4e JC |
831 | goto err; |
832 | } | |
833 | ||
834 | exynos_mutex_unlock(gsc_handle->cur_obj_mutex); | |
835 | exynos_mutex_unlock(gsc_handle->op_mutex); | |
836 | ||
837 | return (void *)gsc_handle; | |
838 | ||
839 | err: | |
840 | if (gsc_handle) { | |
841 | m_exynos_gsc_destroy(gsc_handle); | |
842 | ||
843 | if (gsc_handle->cur_obj_mutex) | |
844 | exynos_mutex_unlock(gsc_handle->cur_obj_mutex); | |
845 | ||
846 | for (i = 0; i < NUM_OF_GSC_HW; i++) { | |
847 | if ((gsc_handle->obj_mutex[i] != NULL) && | |
e6a0625b | 848 | (exynos_mutex_get_created_status(gsc_handle->obj_mutex[i]) == true)) { |
70007c4e | 849 | if (exynos_mutex_destroy(gsc_handle->obj_mutex[i]) == false) |
6134b8bb | 850 | ALOGE("%s::exynos_mutex_destroy() fail", __func__); |
70007c4e JC |
851 | } |
852 | } | |
853 | ||
854 | if (gsc_handle->op_mutex) | |
855 | exynos_mutex_unlock(gsc_handle->op_mutex); | |
856 | ||
857 | if (exynos_mutex_destroy(gsc_handle->op_mutex) == false) | |
6134b8bb | 858 | ALOGE("%s::exynos_mutex_destroy(op_mutex) fail", __func__); |
70007c4e JC |
859 | |
860 | free(gsc_handle); | |
861 | } | |
862 | ||
e6a0625b JC |
863 | Exynos_gsc_Out(); |
864 | ||
70007c4e JC |
865 | return NULL; |
866 | } | |
867 | ||
868 | void *exynos_gsc_reserve(int dev_num) | |
869 | { | |
870 | char mutex_name[32]; | |
871 | unsigned int total_sleep_time = 0; | |
872 | bool gsc_flag = false; | |
873 | ||
874 | if ((dev_num < 0) || (dev_num >= NUM_OF_GSC_HW)) { | |
6134b8bb | 875 | ALOGE("%s::fail:: dev_num is not valid(%d) ", __func__, dev_num); |
70007c4e JC |
876 | return NULL; |
877 | } | |
878 | ||
879 | struct GSC_HANDLE *gsc_handle = (struct GSC_HANDLE *)malloc(sizeof(struct GSC_HANDLE)); | |
880 | if (gsc_handle == NULL) { | |
6134b8bb | 881 | ALOGE("%s::malloc(struct GSC_HANDLE) fail", __func__); |
70007c4e JC |
882 | goto err; |
883 | } | |
884 | ||
885 | gsc_handle->gsc_fd = -1; | |
886 | gsc_handle->op_mutex = NULL; | |
887 | gsc_handle->cur_obj_mutex = NULL; | |
888 | ||
889 | sprintf(mutex_name, "%sObject%d", LOG_TAG, dev_num); | |
890 | gsc_handle->cur_obj_mutex = exynos_mutex_create(EXYNOS_MUTEX_TYPE_SHARED, mutex_name); | |
891 | if (gsc_handle->cur_obj_mutex == NULL) { | |
6134b8bb | 892 | ALOGE("%s::exynos_mutex_create(%s) fail", __func__, mutex_name); |
70007c4e JC |
893 | goto err; |
894 | } | |
895 | ||
896 | do { | |
897 | if (exynos_mutex_trylock(gsc_handle->cur_obj_mutex) == true) { | |
898 | gsc_flag = true; | |
899 | break; | |
900 | } | |
901 | usleep(GSC_WAITING_TIME_FOR_TRYLOCK); | |
902 | total_sleep_time += GSC_WAITING_TIME_FOR_TRYLOCK; | |
6134b8bb | 903 | ALOGV("%s::waiting for another process to release the requested gscaler", __func__); |
70007c4e JC |
904 | } while(total_sleep_time < MAX_GSC_WAITING_TIME_FOR_TRYLOCK); |
905 | ||
906 | if (gsc_flag == true) | |
907 | return (void *)gsc_handle; | |
908 | ||
909 | err: | |
910 | if (gsc_handle) { | |
911 | free(gsc_handle); | |
912 | } | |
913 | ||
914 | return NULL; | |
915 | } | |
916 | ||
917 | void exynos_gsc_release(void *handle) | |
918 | { | |
919 | struct GSC_HANDLE *gsc_handle = (struct GSC_HANDLE *)handle; | |
920 | ||
921 | if (handle == NULL) { | |
6134b8bb | 922 | ALOGE("%s::handle == NULL() fail", __func__); |
70007c4e JC |
923 | return; |
924 | } | |
925 | ||
926 | exynos_mutex_unlock(gsc_handle->cur_obj_mutex); | |
927 | exynos_mutex_destroy(gsc_handle->cur_obj_mutex); | |
928 | free(gsc_handle); | |
929 | return; | |
930 | } | |
931 | ||
932 | void *exynos_gsc_create_exclusive( | |
933 | int dev_num, | |
934 | int mode, | |
935 | int out_mode) | |
936 | { | |
937 | int i = 0; | |
938 | int op_id = 0; | |
939 | char mutex_name[32]; | |
940 | unsigned int total_sleep_time = 0; | |
941 | bool gsc_flag = false; | |
942 | int ret = 0; | |
e6a0625b JC |
943 | |
944 | Exynos_gsc_In(); | |
945 | ||
70007c4e | 946 | if ((dev_num < 0) || (dev_num >= NUM_OF_GSC_HW)) { |
6134b8bb | 947 | ALOGE("%s::fail:: dev_num is not valid(%d) ", __func__, dev_num); |
70007c4e JC |
948 | return NULL; |
949 | } | |
950 | ||
951 | if ((mode < 0) || (mode >= NUM_OF_GSC_HW)) { | |
6134b8bb | 952 | ALOGE("%s::fail:: mode is not valid(%d) ", __func__, mode); |
70007c4e JC |
953 | return NULL; |
954 | } | |
955 | ||
956 | struct GSC_HANDLE *gsc_handle = (struct GSC_HANDLE *)malloc(sizeof(struct GSC_HANDLE)); | |
957 | if (gsc_handle == NULL) { | |
6134b8bb | 958 | ALOGE("%s::malloc(struct GSC_HANDLE) fail", __func__); |
70007c4e JC |
959 | goto err; |
960 | } | |
70007c4e | 961 | memset(gsc_handle, 0, sizeof(struct GSC_HANDLE)); |
e6a0625b | 962 | gsc_handle->gsc_fd = -1; |
70007c4e JC |
963 | gsc_handle->gsc_mode = mode; |
964 | ||
965 | gsc_handle->src.buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | |
966 | gsc_handle->dst.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | |
967 | ||
968 | gsc_handle->op_mutex = NULL; | |
969 | for (i = 0; i < NUM_OF_GSC_HW; i++) | |
970 | gsc_handle->obj_mutex[i] = NULL; | |
971 | ||
972 | gsc_handle->cur_obj_mutex = NULL; | |
973 | gsc_handle->flag_local_path = false; | |
974 | gsc_handle->flag_exclusive_open = true; | |
975 | ||
976 | srand(time(NULL)); | |
977 | op_id = rand() % 1000000; // just make random id | |
978 | sprintf(mutex_name, "%sOp%d", LOG_TAG, op_id); | |
979 | gsc_handle->op_mutex = exynos_mutex_create(EXYNOS_MUTEX_TYPE_PRIVATE, mutex_name); | |
980 | if (gsc_handle->op_mutex == NULL) { | |
6134b8bb | 981 | ALOGE("%s::exynos_mutex_create(%s) fail", __func__, mutex_name); |
70007c4e JC |
982 | goto err; |
983 | } | |
984 | ||
985 | exynos_mutex_lock(gsc_handle->op_mutex); | |
986 | ||
987 | sprintf(mutex_name, "%sObject%d", LOG_TAG, dev_num); | |
988 | gsc_handle->cur_obj_mutex = exynos_mutex_create(EXYNOS_MUTEX_TYPE_SHARED, mutex_name); | |
989 | if (gsc_handle->cur_obj_mutex == NULL) { | |
6134b8bb | 990 | ALOGE("%s::exynos_mutex_create(%s) fail", __func__, mutex_name); |
70007c4e JC |
991 | goto err; |
992 | } | |
993 | ||
994 | do { | |
995 | if (exynos_mutex_trylock(gsc_handle->cur_obj_mutex) == true) { | |
996 | if (mode == GSC_M2M_MODE) { | |
e6a0625b JC |
997 | gsc_handle->gsc_fd = m_exynos_gsc_m2m_create(dev_num); |
998 | if (gsc_handle->gsc_fd < 0) { | |
999 | ALOGE("%s::m_exynos_gsc_m2m_create(%i) fail", __func__, dev_num); | |
1000 | goto err; | |
1001 | } | |
70007c4e JC |
1002 | } else if (mode == GSC_OUTPUT_MODE) { |
1003 | ret = m_exynos_gsc_output_create(gsc_handle, dev_num, out_mode); | |
1004 | if (ret < 0) { | |
6134b8bb | 1005 | ALOGE("%s::m_exynos_gsc_output_create(%i) fail", __func__, dev_num); |
70007c4e JC |
1006 | goto err; |
1007 | } | |
1008 | } | |
1009 | /*else | |
1010 | gsc_handle->gsc_fd = m_exynos_gsc_capture_create(dev_num);*/ | |
e6a0625b | 1011 | |
70007c4e JC |
1012 | gsc_flag = true; |
1013 | break; | |
1014 | } | |
1015 | usleep(GSC_WAITING_TIME_FOR_TRYLOCK); | |
1016 | total_sleep_time += GSC_WAITING_TIME_FOR_TRYLOCK; | |
6134b8bb | 1017 | ALOGV("%s::waiting for anthere process doens't use gscaler", __func__); |
70007c4e JC |
1018 | } while(total_sleep_time < MAX_GSC_WAITING_TIME_FOR_TRYLOCK); |
1019 | ||
1020 | exynos_mutex_unlock(gsc_handle->op_mutex); | |
e6a0625b JC |
1021 | if (gsc_flag == true) { |
1022 | Exynos_gsc_Out(); | |
1023 | return (void *)gsc_handle; | |
1024 | } | |
70007c4e JC |
1025 | |
1026 | err: | |
1027 | if (gsc_handle) { | |
1028 | m_exynos_gsc_destroy(gsc_handle); | |
1029 | ||
1030 | if (gsc_handle->cur_obj_mutex) | |
1031 | exynos_mutex_unlock(gsc_handle->cur_obj_mutex); | |
1032 | ||
1033 | for (i = 0; i < NUM_OF_GSC_HW; i++) { | |
1034 | if ((gsc_handle->obj_mutex[i] != NULL) && | |
e6a0625b | 1035 | (exynos_mutex_get_created_status(gsc_handle->obj_mutex[i]) == true)) { |
70007c4e | 1036 | if (exynos_mutex_destroy(gsc_handle->obj_mutex[i]) == false) |
6134b8bb | 1037 | ALOGE("%s::exynos_mutex_destroy() fail", __func__); |
70007c4e JC |
1038 | } |
1039 | } | |
1040 | ||
1041 | if (gsc_handle->op_mutex) | |
1042 | exynos_mutex_unlock(gsc_handle->op_mutex); | |
1043 | ||
1044 | if (exynos_mutex_destroy(gsc_handle->op_mutex) == false) | |
6134b8bb | 1045 | ALOGE("%s::exynos_mutex_destroy(op_mutex) fail", __func__); |
70007c4e JC |
1046 | |
1047 | free(gsc_handle); | |
1048 | } | |
1049 | ||
e6a0625b JC |
1050 | Exynos_gsc_Out(); |
1051 | ||
70007c4e JC |
1052 | return NULL; |
1053 | } | |
1054 | ||
1055 | void exynos_gsc_destroy( | |
1056 | void *handle) | |
1057 | { | |
1058 | int i = 0; | |
1059 | struct GSC_HANDLE *gsc_handle = (struct GSC_HANDLE *)handle; | |
1060 | ||
e6a0625b JC |
1061 | Exynos_gsc_In(); |
1062 | ||
70007c4e | 1063 | if (handle == NULL) { |
6134b8bb | 1064 | ALOGE("%s::handle == NULL() fail", __func__); |
70007c4e JC |
1065 | return; |
1066 | } | |
1067 | ||
1068 | exynos_mutex_lock(gsc_handle->op_mutex); | |
1069 | ||
1070 | if (gsc_handle->flag_exclusive_open == false) | |
1071 | exynos_mutex_lock(gsc_handle->cur_obj_mutex); | |
1072 | ||
1073 | if (gsc_handle->gsc_mode == GSC_OUTPUT_MODE) | |
e6a0625b JC |
1074 | m_exynos_gsc_out_destroy(gsc_handle); |
1075 | else | |
1076 | m_exynos_gsc_destroy(gsc_handle); | |
70007c4e JC |
1077 | |
1078 | exynos_mutex_unlock(gsc_handle->cur_obj_mutex); | |
1079 | ||
1080 | for (i = 0; i < NUM_OF_GSC_HW; i++) { | |
1081 | if ((gsc_handle->obj_mutex[i] != NULL) && | |
e6a0625b | 1082 | (exynos_mutex_get_created_status(gsc_handle->obj_mutex[i]) == true)) { |
70007c4e | 1083 | if (exynos_mutex_destroy(gsc_handle->obj_mutex[i]) == false) |
6134b8bb | 1084 | ALOGE("%s::exynos_mutex_destroy(obj_mutex) fail", __func__); |
70007c4e JC |
1085 | } |
1086 | } | |
1087 | ||
1088 | exynos_mutex_unlock(gsc_handle->op_mutex); | |
1089 | ||
1090 | if (exynos_mutex_destroy(gsc_handle->op_mutex) == false) | |
6134b8bb | 1091 | ALOGE("%s::exynos_mutex_destroy(op_mutex) fail", __func__); |
70007c4e JC |
1092 | |
1093 | if (gsc_handle) | |
1094 | free(gsc_handle); | |
e6a0625b JC |
1095 | |
1096 | Exynos_gsc_Out(); | |
1097 | ||
70007c4e JC |
1098 | } |
1099 | ||
1100 | int exynos_gsc_set_src_format( | |
1101 | void *handle, | |
1102 | unsigned int width, | |
1103 | unsigned int height, | |
1104 | unsigned int crop_left, | |
1105 | unsigned int crop_top, | |
1106 | unsigned int crop_width, | |
1107 | unsigned int crop_height, | |
1108 | unsigned int v4l2_colorformat, | |
e6a0625b JC |
1109 | unsigned int cacheable, |
1110 | unsigned int mode_drm) | |
70007c4e | 1111 | { |
e6a0625b JC |
1112 | Exynos_gsc_In(); |
1113 | ||
70007c4e JC |
1114 | struct GSC_HANDLE *gsc_handle; |
1115 | gsc_handle = (struct GSC_HANDLE *)handle; | |
1116 | ||
1117 | if (handle == NULL) { | |
6134b8bb | 1118 | ALOGE("%s::handle == NULL() fail", __func__); |
70007c4e JC |
1119 | return -1; |
1120 | } | |
1121 | ||
1122 | exynos_mutex_lock(gsc_handle->op_mutex); | |
1123 | ||
1124 | gsc_handle->src.width = width; | |
1125 | gsc_handle->src.height = height; | |
1126 | gsc_handle->src.crop_left = crop_left; | |
1127 | gsc_handle->src.crop_top = crop_top; | |
1128 | gsc_handle->src.crop_width = crop_width; | |
1129 | gsc_handle->src.crop_height = crop_height; | |
1130 | gsc_handle->src.v4l2_colorformat = v4l2_colorformat; | |
1131 | gsc_handle->src.cacheable = cacheable; | |
e6a0625b | 1132 | gsc_handle->src.mode_drm = mode_drm; |
70007c4e JC |
1133 | |
1134 | if (gsc_handle->flag_exclusive_open == true) { | |
1135 | if (m_exynos_gsc_set_format(gsc_handle->gsc_fd, &gsc_handle->src, false) == false) { | |
6134b8bb | 1136 | ALOGE("%s::m_exynos_gsc_set_format(src) fail", __func__); |
70007c4e JC |
1137 | } |
1138 | } | |
1139 | ||
1140 | exynos_mutex_unlock(gsc_handle->op_mutex); | |
1141 | ||
e6a0625b JC |
1142 | Exynos_gsc_Out(); |
1143 | ||
70007c4e JC |
1144 | return 0; |
1145 | } | |
1146 | ||
1147 | int exynos_gsc_set_dst_format( | |
1148 | void *handle, | |
1149 | unsigned int width, | |
1150 | unsigned int height, | |
1151 | unsigned int crop_left, | |
1152 | unsigned int crop_top, | |
1153 | unsigned int crop_width, | |
1154 | unsigned int crop_height, | |
1155 | unsigned int v4l2_colorformat, | |
e6a0625b JC |
1156 | unsigned int cacheable, |
1157 | unsigned int mode_drm) | |
70007c4e | 1158 | { |
e6a0625b JC |
1159 | Exynos_gsc_In(); |
1160 | ||
70007c4e JC |
1161 | struct GSC_HANDLE *gsc_handle; |
1162 | gsc_handle = (struct GSC_HANDLE *)handle; | |
1163 | ||
1164 | if (handle == NULL) { | |
6134b8bb | 1165 | ALOGE("%s::handle == NULL() fail", __func__); |
70007c4e JC |
1166 | return -1; |
1167 | } | |
1168 | ||
1169 | exynos_mutex_lock(gsc_handle->op_mutex); | |
1170 | ||
1171 | gsc_handle->dst.width = width; | |
1172 | gsc_handle->dst.height = height; | |
1173 | gsc_handle->dst.crop_left = crop_left; | |
1174 | gsc_handle->dst.crop_top = crop_top; | |
1175 | gsc_handle->dst.crop_width = crop_width; | |
1176 | gsc_handle->dst.crop_height = crop_height; | |
1177 | gsc_handle->dst.v4l2_colorformat = v4l2_colorformat; | |
1178 | gsc_handle->dst.cacheable = cacheable; | |
e6a0625b | 1179 | gsc_handle->dst.mode_drm = mode_drm; |
70007c4e JC |
1180 | |
1181 | if (gsc_handle->flag_exclusive_open == true) { | |
1182 | if (m_exynos_gsc_set_format(gsc_handle->gsc_fd, &gsc_handle->dst, false) == false) { | |
6134b8bb | 1183 | ALOGE("%s::m_exynos_gsc_set_format(dst) fail", __func__); |
70007c4e JC |
1184 | } |
1185 | } | |
1186 | ||
1187 | exynos_mutex_unlock(gsc_handle->op_mutex); | |
1188 | ||
e6a0625b JC |
1189 | Exynos_gsc_Out(); |
1190 | return 0; | |
1191 | } | |
1192 | ||
1193 | static int exynos_gsc_ctrl_sysmmu( | |
1194 | int fd, | |
1195 | int flag) | |
1196 | { | |
1197 | int sys_mmu_flag = flag ^ 1; | |
1198 | ||
1199 | #if 0 //it will be enabled later | |
1200 | if (exynos_v4l2_s_ctrl(fd, V4L2_CID_USE_SYSMMU, sys_mmu_flag) < 0) { | |
1201 | ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_USE_SYSMMU) fail", __func__); | |
1202 | return -1; | |
1203 | } | |
1204 | #endif | |
70007c4e JC |
1205 | return 0; |
1206 | } | |
1207 | ||
1208 | int exynos_gsc_set_rotation( | |
1209 | void *handle, | |
1210 | int rotation, | |
1211 | int flip_horizontal, | |
1212 | int flip_vertical) | |
1213 | { | |
1214 | int ret = -1; | |
1215 | struct GSC_HANDLE *gsc_handle; | |
1216 | gsc_handle = (struct GSC_HANDLE *)handle; | |
1217 | ||
1218 | if (handle == NULL) { | |
6134b8bb | 1219 | ALOGE("%s::handle == NULL() fail", __func__); |
70007c4e JC |
1220 | return ret; |
1221 | } | |
1222 | ||
1223 | exynos_mutex_lock(gsc_handle->op_mutex); | |
1224 | ||
1225 | int new_rotation = rotation % 360; | |
1226 | ||
1227 | if (new_rotation % 90 != 0) { | |
6134b8bb | 1228 | ALOGE("%s::rotation(%d) cannot be acceptable fail", __func__, rotation); |
70007c4e JC |
1229 | goto done; |
1230 | } | |
1231 | ||
1232 | if(new_rotation < 0) | |
1233 | new_rotation = -new_rotation; | |
1234 | ||
1235 | gsc_handle->dst.rotation = new_rotation; | |
1236 | gsc_handle->dst.flip_horizontal = flip_horizontal; | |
1237 | gsc_handle->dst.flip_vertical = flip_vertical; | |
1238 | ||
1239 | ret = 0; | |
1240 | done: | |
1241 | exynos_mutex_unlock(gsc_handle->op_mutex); | |
1242 | ||
1243 | return ret; | |
1244 | } | |
1245 | ||
1246 | int exynos_gsc_set_src_addr( | |
1247 | void *handle, | |
1248 | void *addr[3]) | |
1249 | { | |
1250 | struct GSC_HANDLE *gsc_handle; | |
1251 | gsc_handle = (struct GSC_HANDLE *)handle; | |
1252 | ||
e6a0625b JC |
1253 | Exynos_gsc_In(); |
1254 | ||
70007c4e | 1255 | if (handle == NULL) { |
6134b8bb | 1256 | ALOGE("%s::handle == NULL() fail", __func__); |
70007c4e JC |
1257 | return -1; |
1258 | } | |
1259 | ||
1260 | exynos_mutex_lock(gsc_handle->op_mutex); | |
1261 | ||
1262 | gsc_handle->src.addr[0] = addr[0]; | |
1263 | gsc_handle->src.addr[1] = addr[1]; | |
1264 | gsc_handle->src.addr[2] = addr[2]; | |
1265 | ||
1266 | if (gsc_handle->flag_exclusive_open == true) { | |
1267 | if (m_exynos_gsc_set_addr(gsc_handle->gsc_fd, &gsc_handle->src) == false) { | |
6134b8bb | 1268 | ALOGE("%s::m_exynos_gsc_set_addr(src) fail", __func__); |
70007c4e JC |
1269 | } |
1270 | } | |
1271 | ||
1272 | exynos_mutex_unlock(gsc_handle->op_mutex); | |
1273 | ||
e6a0625b JC |
1274 | Exynos_gsc_Out(); |
1275 | ||
70007c4e JC |
1276 | return 0; |
1277 | } | |
1278 | ||
1279 | int exynos_gsc_set_dst_addr( | |
1280 | void *handle, | |
1281 | void *addr[3]) | |
1282 | { | |
1283 | struct GSC_HANDLE *gsc_handle; | |
1284 | gsc_handle = (struct GSC_HANDLE *)handle; | |
994ebe9b | 1285 | int ret = 0; |
70007c4e | 1286 | |
e6a0625b JC |
1287 | Exynos_gsc_In(); |
1288 | ||
70007c4e | 1289 | if (handle == NULL) { |
6134b8bb | 1290 | ALOGE("%s::handle == NULL() fail", __func__); |
70007c4e JC |
1291 | return -1; |
1292 | } | |
1293 | ||
1294 | exynos_mutex_lock(gsc_handle->op_mutex); | |
1295 | ||
1296 | gsc_handle->dst.addr[0] = addr[0]; | |
1297 | gsc_handle->dst.addr[1] = addr[1]; | |
1298 | gsc_handle->dst.addr[2] = addr[2]; | |
1299 | ||
1300 | if (gsc_handle->flag_exclusive_open == true) { | |
1301 | if (m_exynos_gsc_set_addr(gsc_handle->gsc_fd, &gsc_handle->dst) == false) { | |
6134b8bb | 1302 | ALOGE("%s::m_exynos_gsc_set_addr(dst) fail", __func__); |
994ebe9b | 1303 | ret = -1; |
70007c4e JC |
1304 | } |
1305 | } | |
1306 | ||
1307 | exynos_mutex_unlock(gsc_handle->op_mutex); | |
1308 | ||
e6a0625b JC |
1309 | Exynos_gsc_Out(); |
1310 | ||
994ebe9b | 1311 | return ret; |
70007c4e JC |
1312 | } |
1313 | ||
1314 | static void rotateValueHAL2GSC(unsigned int transform, | |
1315 | unsigned int *rotate, | |
1316 | unsigned int *hflip, | |
1317 | unsigned int *vflip) | |
1318 | { | |
1319 | int rotate_flag = transform & 0x7; | |
1320 | *rotate = 0; | |
1321 | *hflip = 0; | |
1322 | *vflip = 0; | |
1323 | ||
1324 | switch (rotate_flag) { | |
1325 | case HAL_TRANSFORM_ROT_90: | |
1326 | *rotate = 90; | |
1327 | break; | |
1328 | case HAL_TRANSFORM_ROT_180: | |
1329 | *rotate = 180; | |
1330 | break; | |
1331 | case HAL_TRANSFORM_ROT_270: | |
1332 | *rotate = 270; | |
1333 | break; | |
1334 | case HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90: | |
1335 | *rotate = 90; | |
1336 | *vflip = 1; /* set vflip to compensate the rot & flip order. */ | |
1337 | break; | |
1338 | case HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90: | |
1339 | *rotate = 90; | |
1340 | *hflip = 1; /* set hflip to compensate the rot & flip order. */ | |
1341 | break; | |
1342 | case HAL_TRANSFORM_FLIP_H: | |
1343 | *hflip = 1; | |
1344 | break; | |
1345 | case HAL_TRANSFORM_FLIP_V: | |
1346 | *vflip = 1; | |
1347 | break; | |
1348 | default: | |
1349 | break; | |
1350 | } | |
70007c4e JC |
1351 | } |
1352 | ||
1353 | static bool get_plane_size(int V4L2_PIX, | |
1354 | unsigned int * size, | |
1355 | unsigned int frame_size, | |
e6a0625b | 1356 | int src_planes) |
70007c4e | 1357 | { |
e6a0625b | 1358 | unsigned int frame_ratio = 1; |
70007c4e JC |
1359 | int src_bpp = get_yuv_bpp(V4L2_PIX); |
1360 | ||
1361 | src_planes = (src_planes == -1) ? 1 : src_planes; | |
1362 | frame_ratio = 8 * (src_planes -1) / (src_bpp - 8); | |
1363 | ||
1364 | switch (src_planes) { | |
1365 | case 1: | |
1366 | switch (V4L2_PIX) { | |
1367 | case V4L2_PIX_FMT_BGR32: | |
1368 | case V4L2_PIX_FMT_RGB32: | |
1369 | size[0] = frame_size << 2; | |
1370 | break; | |
1371 | case V4L2_PIX_FMT_RGB565X: | |
1372 | case V4L2_PIX_FMT_NV16: | |
1373 | case V4L2_PIX_FMT_NV61: | |
1374 | case V4L2_PIX_FMT_YUYV: | |
1375 | case V4L2_PIX_FMT_UYVY: | |
1376 | case V4L2_PIX_FMT_VYUY: | |
1377 | case V4L2_PIX_FMT_YVYU: | |
1378 | size[0] = frame_size << 1; | |
1379 | break; | |
1380 | case V4L2_PIX_FMT_YUV420: | |
1381 | case V4L2_PIX_FMT_NV12: | |
1382 | case V4L2_PIX_FMT_NV21: | |
66e91991 | 1383 | case V4L2_PIX_FMT_NV21M: |
70007c4e JC |
1384 | size[0] = (frame_size * 3) >> 1; |
1385 | break; | |
1386 | default: | |
6134b8bb | 1387 | ALOGE("%s::invalid color type", __func__); |
70007c4e JC |
1388 | return false; |
1389 | break; | |
1390 | } | |
1391 | size[1] = 0; | |
1392 | size[2] = 0; | |
1393 | break; | |
1394 | case 2: | |
1395 | size[0] = frame_size; | |
1396 | size[1] = frame_size / frame_ratio; | |
1397 | size[2] = 0; | |
1398 | break; | |
1399 | case 3: | |
1400 | size[0] = frame_size; | |
1401 | size[1] = frame_size / frame_ratio; | |
1402 | size[2] = frame_size / frame_ratio; | |
1403 | break; | |
1404 | default: | |
6134b8bb | 1405 | ALOGE("%s::invalid color foarmt", __func__); |
70007c4e JC |
1406 | return false; |
1407 | break; | |
1408 | } | |
1409 | ||
1410 | return true; | |
1411 | } | |
1412 | ||
e6a0625b JC |
1413 | int exynos_gsc_m2m_config(void *handle, |
1414 | exynos_gsc_img *src_img, | |
1415 | exynos_gsc_img *dst_img) | |
1416 | { | |
1417 | struct GSC_HANDLE *gsc_handle; | |
1418 | int32_t src_color_space; | |
1419 | int32_t dst_color_space; | |
1420 | int ret; | |
1421 | unsigned int rotate; | |
1422 | unsigned int hflip; | |
1423 | unsigned int vflip; | |
1424 | ||
1425 | Exynos_gsc_In(); | |
1426 | ||
1427 | gsc_handle = (struct GSC_HANDLE *)handle; | |
1428 | if (gsc_handle == NULL) { | |
1429 | ALOGE("%s::gsc_handle == NULL() fail", __func__); | |
1430 | return -1; | |
1431 | } | |
1432 | ||
1433 | src_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(src_img->format); | |
1434 | dst_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(dst_img->format); | |
1435 | rotateValueHAL2GSC(dst_img->rot, &rotate, &hflip, &vflip); | |
1436 | exynos_gsc_set_rotation(gsc_handle, rotate, hflip, vflip); | |
1437 | ||
1438 | ret = exynos_gsc_set_src_format(gsc_handle, src_img->fw, src_img->fh, | |
1439 | src_img->x, src_img->y, src_img->w, src_img->h, | |
1440 | src_color_space, src_img->cacheable, src_img->drmMode); | |
1441 | if (ret < 0) { | |
1442 | ALOGE("%s: fail: exynos_gsc_set_src_format [fw %d fh %d x %d y %d w %d h %d f %x rot %d]", | |
1443 | __func__, src_img->fw, src_img->fh, src_img->x, src_img->y, src_img->w, src_img->h, | |
1444 | src_color_space, src_img->rot); | |
1445 | return -1; | |
1446 | } | |
1447 | ||
1448 | ret = exynos_gsc_set_dst_format(gsc_handle, dst_img->fw, dst_img->fh, | |
1449 | dst_img->x, dst_img->y, dst_img->w, dst_img->h, | |
1450 | dst_color_space, dst_img->cacheable, src_img->drmMode); | |
1451 | if (ret < 0) { | |
1452 | ALOGE("%s: fail: exynos_gsc_set_dst_format [fw %d fh %d x %d y %d w %d h %d f %x rot %d]", | |
1453 | __func__, dst_img->fw, dst_img->fh, dst_img->x, dst_img->y, dst_img->w, dst_img->h, | |
1454 | src_color_space, dst_img->rot); | |
1455 | return -1; | |
1456 | } | |
1457 | ||
1458 | Exynos_gsc_Out(); | |
1459 | ||
1460 | return 0; | |
1461 | } | |
1462 | ||
70007c4e | 1463 | int exynos_gsc_out_config(void *handle, |
e6a0625b JC |
1464 | exynos_gsc_img *src_img, |
1465 | exynos_gsc_img *dst_img) | |
70007c4e JC |
1466 | { |
1467 | struct GSC_HANDLE *gsc_handle; | |
1468 | struct v4l2_format fmt; | |
1469 | struct v4l2_crop crop; | |
1470 | struct v4l2_requestbuffers reqbuf; | |
1471 | struct v4l2_subdev_format sd_fmt; | |
1472 | struct v4l2_subdev_crop sd_crop; | |
1473 | int i; | |
1474 | unsigned int rotate; | |
1475 | unsigned int hflip; | |
1476 | unsigned int vflip; | |
1477 | unsigned int plane_size[NUM_OF_GSC_PLANES]; | |
cd63257f | 1478 | bool rgb; |
70007c4e JC |
1479 | |
1480 | struct v4l2_rect dst_rect; | |
1481 | int32_t src_color_space; | |
1482 | int32_t dst_color_space; | |
1483 | int32_t src_planes; | |
e6a0625b | 1484 | |
70007c4e JC |
1485 | gsc_handle = (struct GSC_HANDLE *)handle; |
1486 | if (gsc_handle == NULL) { | |
6134b8bb | 1487 | ALOGE("%s::gsc_handle == NULL() fail", __func__); |
70007c4e JC |
1488 | return -1; |
1489 | } | |
1490 | ||
e6a0625b JC |
1491 | Exynos_gsc_In(); |
1492 | ||
70007c4e | 1493 | if (gsc_handle->src.stream_on != false) { |
6134b8bb | 1494 | ALOGE("Error: Src is already streamed on !!!!"); |
70007c4e JC |
1495 | return -1; |
1496 | } | |
1497 | ||
e6a0625b JC |
1498 | memcpy(&gsc_handle->src_img, src_img, sizeof(exynos_gsc_img)); |
1499 | memcpy(&gsc_handle->dst_img, dst_img, sizeof(exynos_gsc_img)); | |
70007c4e JC |
1500 | src_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(src_img->format); |
1501 | dst_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(dst_img->format); | |
1502 | src_planes = get_yuv_planes(src_color_space); | |
ba718a43 BG |
1503 | src_planes = (src_planes == -1) ? 1 : src_planes; |
1504 | rgb = get_yuv_planes(dst_color_space) == -1; | |
70007c4e JC |
1505 | rotateValueHAL2GSC(dst_img->rot, &rotate, &hflip, &vflip); |
1506 | ||
1507 | if (m_exynos_gsc_check_src_size(&gsc_handle->src_img.fw, &gsc_handle->src_img.fh, | |
1508 | &gsc_handle->src_img.x, &gsc_handle->src_img.y, | |
1509 | &gsc_handle->src_img.w, &gsc_handle->src_img.h, | |
1510 | src_color_space) == false) { | |
6134b8bb | 1511 | ALOGE("%s::m_exynos_gsc_check_src_size() fail", __func__); |
70007c4e JC |
1512 | return -1; |
1513 | } | |
1514 | ||
1515 | if (m_exynos_gsc_check_dst_size(&gsc_handle->dst_img.fw, &gsc_handle->dst_img.fh, | |
1516 | &gsc_handle->dst_img.x, &gsc_handle->dst_img.y, | |
1517 | &gsc_handle->dst_img.w, &gsc_handle->dst_img.h, | |
1518 | dst_color_space, | |
1519 | rotate) == false) { | |
6134b8bb | 1520 | ALOGE("%s::m_exynos_gsc_check_dst_size() fail", __func__); |
70007c4e JC |
1521 | return -1; |
1522 | } | |
1523 | ||
1524 | /*set: src v4l2_buffer*/ | |
1525 | gsc_handle->src.src_buf_idx = 0; | |
1526 | gsc_handle->src.qbuf_cnt = 0; | |
70007c4e JC |
1527 | /* set format: src pad of GSC sub-dev*/ |
1528 | sd_fmt.pad = GSCALER_SUBDEV_PAD_SOURCE; | |
1529 | sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; | |
1530 | sd_fmt.format.width = gsc_handle->dst_img.fw; | |
1531 | sd_fmt.format.height = gsc_handle->dst_img.fh; | |
cd63257f GH |
1532 | sd_fmt.format.code = rgb ? V4L2_MBUS_FMT_XRGB8888_4X8_LE : |
1533 | V4L2_MBUS_FMT_YUV8_1X24; | |
70007c4e | 1534 | if (exynos_subdev_s_fmt(gsc_handle->gsc_sd_entity->fd, &sd_fmt) < 0) { |
6134b8bb | 1535 | ALOGE("%s::GSC subdev set format failed", __func__); |
70007c4e JC |
1536 | return -1; |
1537 | } | |
1538 | ||
1539 | /* set crop: src crop of GSC sub-dev*/ | |
1540 | sd_crop.pad = GSCALER_SUBDEV_PAD_SOURCE; | |
1541 | sd_crop.which = V4L2_SUBDEV_FORMAT_ACTIVE; | |
1542 | sd_crop.rect.left = gsc_handle->dst_img.x; | |
1543 | sd_crop.rect.top = gsc_handle->dst_img.y; | |
1544 | sd_crop.rect.width = gsc_handle->dst_img.w; | |
1545 | sd_crop.rect.height = gsc_handle->dst_img.h; | |
1546 | if (exynos_subdev_s_crop(gsc_handle->gsc_sd_entity->fd, &sd_crop) < 0) { | |
6134b8bb | 1547 | ALOGE("%s::GSC subdev set crop failed", __func__); |
70007c4e JC |
1548 | return -1; |
1549 | } | |
1550 | ||
1551 | /* sink pad is connected to GSC out */ | |
1552 | /* set format: sink sub-dev */ | |
1553 | if (gsc_handle->out_mode == GSC_OUT_FIMD) | |
1554 | sd_fmt.pad = FIMD_SUBDEV_PAD_SINK; | |
1555 | else | |
1556 | sd_fmt.pad = MIXER_V_SUBDEV_PAD_SINK; | |
e6a0625b | 1557 | |
70007c4e | 1558 | sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; |
e6a0625b JC |
1559 | sd_fmt.format.width = gsc_handle->dst_img.w; |
1560 | sd_fmt.format.height = gsc_handle->dst_img.h; | |
cd63257f GH |
1561 | sd_fmt.format.code = rgb ? V4L2_MBUS_FMT_XRGB8888_4X8_LE : |
1562 | V4L2_MBUS_FMT_YUV8_1X24; | |
70007c4e | 1563 | if (exynos_subdev_s_fmt(gsc_handle->sink_sd_entity->fd, &sd_fmt) < 0) { |
6134b8bb | 1564 | ALOGE("%s::sink:set format failed (PAD=%d)", __func__, sd_fmt.pad); |
70007c4e JC |
1565 | return -1; |
1566 | } | |
1567 | ||
1568 | /* set crop: sink sub-dev */ | |
1569 | if (gsc_handle->out_mode == GSC_OUT_FIMD) | |
1570 | sd_crop.pad = FIMD_SUBDEV_PAD_SINK; | |
1571 | else | |
1572 | sd_crop.pad = MIXER_V_SUBDEV_PAD_SINK; | |
1573 | ||
1574 | sd_crop.which = V4L2_SUBDEV_FORMAT_ACTIVE; | |
1575 | sd_crop.rect.left = gsc_handle->dst_img.x; | |
1576 | sd_crop.rect.top = gsc_handle->dst_img.y; | |
1577 | sd_crop.rect.width = gsc_handle->dst_img.w; | |
1578 | sd_crop.rect.height = gsc_handle->dst_img.h; | |
1579 | if (exynos_subdev_s_crop(gsc_handle->sink_sd_entity->fd, &sd_crop) < 0) { | |
6134b8bb | 1580 | ALOGE("%s::sink: subdev set crop failed(PAD=%d)", __func__, sd_crop.pad); |
70007c4e JC |
1581 | return -1; |
1582 | } | |
1583 | ||
1584 | /*set GSC ctrls */ | |
e6a0625b | 1585 | if (exynos_v4l2_s_ctrl(gsc_handle->gsc_vd_entity->fd, V4L2_CID_ROTATE, rotate) < 0) { |
6134b8bb | 1586 | ALOGE("%s:: exynos_v4l2_s_ctrl (V4L2_CID_ROTATE: %d) failed", __func__, rotate); |
70007c4e JC |
1587 | return -1; |
1588 | } | |
1589 | ||
e6a0625b | 1590 | if (exynos_v4l2_s_ctrl(gsc_handle->gsc_vd_entity->fd, V4L2_CID_HFLIP, hflip) < 0) { |
6134b8bb | 1591 | ALOGE("%s:: exynos_v4l2_s_ctrl (V4L2_CID_HFLIP: %d) failed", __func__, hflip); |
70007c4e JC |
1592 | return -1; |
1593 | } | |
1594 | ||
e6a0625b | 1595 | if (exynos_v4l2_s_ctrl(gsc_handle->gsc_vd_entity->fd, V4L2_CID_VFLIP, vflip) < 0) { |
6134b8bb | 1596 | ALOGE("%s:: exynos_v4l2_s_ctrl (V4L2_CID_VFLIP: %d) failed", __func__, vflip); |
70007c4e JC |
1597 | return -1; |
1598 | } | |
1599 | ||
e6a0625b | 1600 | if (exynos_v4l2_s_ctrl(gsc_handle->gsc_vd_entity->fd, V4L2_CID_CACHEABLE, 1) < 0) { |
6134b8bb | 1601 | ALOGE("%s:: exynos_v4l2_s_ctrl (V4L2_CID_CACHEABLE: 1) failed", __func__); |
70007c4e JC |
1602 | return -1; |
1603 | } | |
1604 | ||
1605 | /* set src format :GSC video dev*/ | |
1606 | fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | |
1607 | fmt.fmt.pix_mp.width = gsc_handle->src_img.fw; | |
1608 | fmt.fmt.pix_mp.height = gsc_handle->src_img.fh; | |
1609 | fmt.fmt.pix_mp.pixelformat = src_color_space; | |
1610 | fmt.fmt.pix_mp.field = V4L2_FIELD_NONE; | |
1611 | fmt.fmt.pix_mp.num_planes = src_planes; | |
e6a0625b | 1612 | |
70007c4e | 1613 | if (exynos_v4l2_s_fmt(gsc_handle->gsc_vd_entity->fd, &fmt) < 0) { |
6134b8bb | 1614 | ALOGE("%s::videodev set format failed", __func__); |
70007c4e JC |
1615 | return -1; |
1616 | } | |
1617 | ||
1618 | /* set src crop info :GSC video dev*/ | |
1619 | crop.type = fmt.type; | |
1620 | crop.c.left = gsc_handle->src_img.x; | |
1621 | crop.c.top = gsc_handle->src_img.y; | |
1622 | crop.c.width = gsc_handle->src_img.w; | |
1623 | crop.c.height = gsc_handle->src_img.h; | |
1624 | ||
1625 | if (exynos_v4l2_s_crop(gsc_handle->gsc_vd_entity->fd, &crop) < 0) { | |
6134b8bb | 1626 | ALOGE("%s::videodev set crop failed", __func__); |
70007c4e JC |
1627 | return -1; |
1628 | } | |
e6a0625b | 1629 | |
70007c4e | 1630 | reqbuf.type = fmt.type; |
776bd695 | 1631 | reqbuf.memory = V4L2_MEMORY_DMABUF; |
70007c4e JC |
1632 | reqbuf.count = MAX_BUFFERS_GSCALER_OUT; |
1633 | ||
1634 | if (exynos_v4l2_reqbufs(gsc_handle->gsc_vd_entity->fd, &reqbuf) < 0) { | |
6134b8bb | 1635 | ALOGE("%s::request buffers failed", __func__); |
70007c4e JC |
1636 | return -1; |
1637 | } | |
e6a0625b JC |
1638 | |
1639 | Exynos_gsc_Out(); | |
1640 | ||
70007c4e JC |
1641 | return 0; |
1642 | } | |
1643 | ||
1644 | int exynos_gsc_out_run(void *handle, | |
1645 | unsigned int yAddr, | |
1646 | unsigned int uAddr, | |
1647 | unsigned int vAddr) | |
1648 | { | |
1649 | struct GSC_HANDLE *gsc_handle; | |
1650 | struct v4l2_plane planes[NUM_OF_GSC_PLANES]; | |
1651 | struct v4l2_buffer buf; | |
1652 | int32_t src_color_space; | |
1653 | int32_t src_planes; | |
1654 | int i; | |
1655 | unsigned int plane_size[NUM_OF_GSC_PLANES]; | |
70007c4e JC |
1656 | |
1657 | gsc_handle = (struct GSC_HANDLE *)handle; | |
1658 | if (handle == NULL) { | |
6134b8bb | 1659 | ALOGE("%s::handle == NULL() fail", __func__); |
70007c4e JC |
1660 | return -1; |
1661 | } | |
1662 | ||
1663 | memset(&buf, 0, sizeof(struct v4l2_buffer)); | |
1664 | for (i = 0; i < NUM_OF_GSC_PLANES; i++) | |
1665 | memset(&planes[i], 0, sizeof(struct v4l2_plane)); | |
1666 | ||
1667 | src_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(gsc_handle->src_img.format); | |
1668 | src_planes = get_yuv_planes(src_color_space); | |
1669 | src_planes = (src_planes == -1) ? 1 : src_planes; | |
1670 | ||
1671 | buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | |
776bd695 | 1672 | buf.memory = V4L2_MEMORY_DMABUF; |
70007c4e JC |
1673 | buf.length = src_planes; |
1674 | buf.index = gsc_handle->src.src_buf_idx; | |
1675 | buf.m.planes = planes; | |
1676 | ||
1677 | gsc_handle->src.addr[0] = (void *)yAddr; | |
1678 | gsc_handle->src.addr[1] = (void *)uAddr; | |
1679 | gsc_handle->src.addr[2] = (void *)vAddr; | |
1680 | ||
1681 | if (get_plane_size(src_color_space, plane_size, | |
1682 | gsc_handle->src_img.fw * gsc_handle->src_img.fh, src_planes) != true) { | |
6134b8bb | 1683 | ALOGE("%s:get_plane_size:fail", __func__); |
70007c4e JC |
1684 | return -1; |
1685 | } | |
1686 | ||
1687 | for (i = 0; i < buf.length; i++) { | |
776bd695 | 1688 | buf.m.planes[i].m.fd = (int)gsc_handle->src.addr[i]; |
70007c4e JC |
1689 | buf.m.planes[i].length = plane_size[i]; |
1690 | buf.m.planes[i].bytesused = plane_size[i]; | |
70007c4e JC |
1691 | } |
1692 | ||
1693 | /* Queue the buf */ | |
1694 | if (exynos_v4l2_qbuf(gsc_handle->gsc_vd_entity->fd, &buf) < 0) { | |
6134b8bb | 1695 | ALOGE("%s::queue buffer failed (index=%d)(mSrcBufNum=%d)", __func__, |
70007c4e JC |
1696 | gsc_handle->src.src_buf_idx, MAX_BUFFERS_GSCALER_OUT); |
1697 | return -1; | |
1698 | } | |
1699 | gsc_handle->src.src_buf_idx++; | |
1700 | gsc_handle->src.qbuf_cnt++; | |
1701 | ||
1702 | if (gsc_handle->src.stream_on == false) { | |
e6a0625b JC |
1703 | /* stream on after queing the second buffer |
1704 | to do: below logic should be changed to handle the single frame videos */ | |
1705 | #ifndef GSC_OUT_DELAYED_STREAMON | |
1706 | if (gsc_handle->src.src_buf_idx == (MAX_BUFFERS_GSCALER_OUT - 2)) { | |
1707 | #else | |
70007c4e | 1708 | if (gsc_handle->src.src_buf_idx == (MAX_BUFFERS_GSCALER_OUT - 1)) { |
e6a0625b | 1709 | #endif |
70007c4e | 1710 | if (exynos_v4l2_streamon(gsc_handle->gsc_vd_entity->fd, buf.type) < 0) { |
6134b8bb | 1711 | ALOGE("%s::stream on failed", __func__); |
70007c4e JC |
1712 | return -1; |
1713 | } | |
1714 | gsc_handle->src.stream_on = true; | |
1715 | } | |
1716 | gsc_handle->src.src_buf_idx = gsc_handle->src.src_buf_idx % MAX_BUFFERS_GSCALER_OUT; | |
e6a0625b | 1717 | #ifndef GSC_OUT_DMA_BLOCKING |
70007c4e | 1718 | return 0; |
e6a0625b | 1719 | #endif |
70007c4e | 1720 | } |
e6a0625b JC |
1721 | |
1722 | if (gsc_handle->src.qbuf_cnt < MAX_BUFFERS_GSCALER_OUT) | |
1723 | return 0; | |
1724 | ||
70007c4e | 1725 | gsc_handle->src.src_buf_idx = gsc_handle->src.src_buf_idx % MAX_BUFFERS_GSCALER_OUT; |
70007c4e JC |
1726 | for (i = 0; i < MAX_BUFFERS_GSCALER_OUT; i++) |
1727 | memset(&planes[i], 0, sizeof(struct v4l2_plane)); | |
1728 | ||
1729 | buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | |
776bd695 | 1730 | buf.memory = V4L2_MEMORY_DMABUF; |
70007c4e JC |
1731 | buf.length = src_planes; |
1732 | buf.m.planes = planes; | |
1733 | ||
1734 | /* DeQueue a buf */ | |
1735 | if (exynos_v4l2_dqbuf(gsc_handle->gsc_vd_entity->fd, &buf) < 0) { | |
6134b8bb | 1736 | ALOGE("%s::dequeue buffer failed (index=%d)(mSrcBufNum=%d)", __func__, |
70007c4e JC |
1737 | gsc_handle->src.src_buf_idx, MAX_BUFFERS_GSCALER_OUT); |
1738 | return -1; | |
1739 | } | |
e6a0625b | 1740 | return 0; |
70007c4e JC |
1741 | } |
1742 | ||
1743 | int exynos_gsc_out_stop(void *handle) | |
1744 | { | |
1745 | struct GSC_HANDLE *gsc_handle; | |
1746 | struct v4l2_requestbuffers reqbuf; | |
1747 | struct v4l2_buffer buf; | |
1748 | struct v4l2_plane planes[NUM_OF_GSC_PLANES]; | |
1749 | int i; | |
1750 | ||
e6a0625b JC |
1751 | Exynos_gsc_In(); |
1752 | ||
70007c4e | 1753 | gsc_handle = (struct GSC_HANDLE *)handle; |
70007c4e | 1754 | if (handle == NULL) { |
6134b8bb | 1755 | ALOGE("%s::handle == NULL() fail", __func__); |
70007c4e JC |
1756 | return -1; |
1757 | } | |
e6a0625b | 1758 | |
70007c4e JC |
1759 | if (gsc_handle->src.stream_on == false) { |
1760 | /* to handle special scenario.*/ | |
70007c4e | 1761 | gsc_handle->src.src_buf_idx = 0; |
e6a0625b | 1762 | gsc_handle->src.qbuf_cnt = 0; |
6134b8bb | 1763 | ALOGD("%s::GSC is already stopped", __func__); |
e6a0625b | 1764 | goto SKIP_STREAMOFF; |
70007c4e JC |
1765 | } |
1766 | gsc_handle->src.src_buf_idx = 0; | |
1767 | gsc_handle->src.qbuf_cnt = 0; | |
e6a0625b | 1768 | gsc_handle->src.stream_on = false; |
70007c4e JC |
1769 | |
1770 | if (exynos_v4l2_streamoff(gsc_handle->gsc_vd_entity->fd, | |
1771 | V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) < 0) { | |
6134b8bb | 1772 | ALOGE("%s::stream off failed", __func__); |
70007c4e JC |
1773 | return -1; |
1774 | } | |
e6a0625b | 1775 | SKIP_STREAMOFF: |
70007c4e JC |
1776 | /* Clear Buffer */ |
1777 | /*todo: support for other buffer type & memory */ | |
1778 | reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | |
776bd695 | 1779 | reqbuf.memory = V4L2_MEMORY_DMABUF; |
70007c4e JC |
1780 | reqbuf.count = 0; |
1781 | ||
1782 | if (exynos_v4l2_reqbufs(gsc_handle->gsc_vd_entity->fd, &reqbuf) < 0) { | |
6134b8bb | 1783 | ALOGE("%s::request buffers failed", __func__); |
70007c4e JC |
1784 | return -1; |
1785 | } | |
e6a0625b JC |
1786 | |
1787 | Exynos_gsc_Out(); | |
1788 | ||
70007c4e JC |
1789 | return 0; |
1790 | } | |
1791 | ||
7b062be7 | 1792 | static int exynos_gsc_m2m_run_core(void *handle) |
70007c4e JC |
1793 | { |
1794 | struct GSC_HANDLE *gsc_handle; | |
7b062be7 | 1795 | |
70007c4e JC |
1796 | gsc_handle = (struct GSC_HANDLE *)handle; |
1797 | ||
e6a0625b JC |
1798 | Exynos_gsc_In(); |
1799 | ||
70007c4e | 1800 | if (handle == NULL) { |
6134b8bb | 1801 | ALOGE("%s::handle == NULL() fail", __func__); |
70007c4e JC |
1802 | return -1; |
1803 | } | |
1804 | ||
70007c4e JC |
1805 | bool flag_new_gsc = false; |
1806 | ||
70007c4e JC |
1807 | if (gsc_handle->flag_exclusive_open == false) { |
1808 | if (exynos_mutex_trylock(gsc_handle->cur_obj_mutex) == false) { | |
1809 | if (m_exynos_gsc_find_and_trylock_and_create(gsc_handle) == false) { | |
6134b8bb | 1810 | ALOGE("%s::m_exynos_gsc_find_and_trylock_and_create() fail", __func__); |
70007c4e JC |
1811 | goto done; |
1812 | } | |
1813 | flag_new_gsc = true; | |
1814 | } | |
1815 | ||
1816 | if (m_exynos_gsc_check_src_size(&gsc_handle->src.width, &gsc_handle->src.height, | |
1817 | &gsc_handle->src.crop_left, &gsc_handle->src.crop_top, | |
1818 | &gsc_handle->src.crop_width, &gsc_handle->src.crop_height, | |
1819 | gsc_handle->src.v4l2_colorformat) == false) { | |
6134b8bb | 1820 | ALOGE("%s::m_exynos_gsc_check_src_size() fail", __func__); |
70007c4e JC |
1821 | goto done; |
1822 | } | |
1823 | ||
1824 | if (m_exynos_gsc_check_dst_size(&gsc_handle->dst.width, &gsc_handle->dst.height, | |
1825 | &gsc_handle->dst.crop_left, &gsc_handle->dst.crop_top, | |
1826 | &gsc_handle->dst.crop_width, &gsc_handle->dst.crop_height, | |
1827 | gsc_handle->dst.v4l2_colorformat, | |
1828 | gsc_handle->dst.rotation) == false) { | |
6134b8bb | 1829 | ALOGE("%s::m_exynos_gsc_check_dst_size() fail", __func__); |
70007c4e JC |
1830 | goto done; |
1831 | } | |
1832 | ||
1833 | if (m_exynos_gsc_set_format(gsc_handle->gsc_fd, &gsc_handle->src, flag_new_gsc) == false) { | |
6134b8bb | 1834 | ALOGE("%s::m_exynos_gsc_set_format(src) fail", __func__); |
70007c4e JC |
1835 | goto done; |
1836 | } | |
1837 | ||
1838 | if (m_exynos_gsc_set_format(gsc_handle->gsc_fd, &gsc_handle->dst, flag_new_gsc) == false) { | |
6134b8bb | 1839 | ALOGE("%s::m_exynos_gsc_set_format(dst) fail", __func__); |
70007c4e JC |
1840 | goto done; |
1841 | } | |
1842 | ||
1843 | if (m_exynos_gsc_set_addr(gsc_handle->gsc_fd, &gsc_handle->src) == false) { | |
6134b8bb | 1844 | ALOGE("%s::m_exynos_gsc_set_addr(src) fail", __func__); |
70007c4e JC |
1845 | goto done; |
1846 | } | |
1847 | ||
1848 | if (m_exynos_gsc_set_addr(gsc_handle->gsc_fd, &gsc_handle->dst) == false) { | |
6134b8bb | 1849 | ALOGE("%s::m_exynos_gsc_set_addr(dst) fail", __func__); |
70007c4e JC |
1850 | goto done; |
1851 | } | |
1852 | } | |
1853 | ||
1854 | if (gsc_handle->src.stream_on == false) { | |
1855 | if (exynos_v4l2_streamon(gsc_handle->gsc_fd, gsc_handle->src.buf_type) < 0) { | |
6134b8bb | 1856 | ALOGE("%s::exynos_v4l2_streamon(src) fail", __func__); |
70007c4e JC |
1857 | goto done; |
1858 | } | |
1859 | gsc_handle->src.stream_on = true; | |
1860 | } | |
1861 | ||
1862 | if (gsc_handle->dst.stream_on == false) { | |
1863 | if (exynos_v4l2_streamon(gsc_handle->gsc_fd, gsc_handle->dst.buf_type) < 0) { | |
6134b8bb | 1864 | ALOGE("%s::exynos_v4l2_streamon(dst) fail", __func__); |
70007c4e JC |
1865 | goto done; |
1866 | } | |
1867 | gsc_handle->dst.stream_on = true; | |
1868 | } | |
1869 | ||
7b062be7 YS |
1870 | Exynos_gsc_Out(); |
1871 | ||
1872 | return 0; | |
1873 | ||
1874 | done: | |
1875 | return -1; | |
1876 | } | |
1877 | ||
1878 | static int exynos_gsc_m2m_wait_frame_done(void *handle) | |
1879 | { | |
1880 | struct GSC_HANDLE *gsc_handle; | |
1881 | struct v4l2_requestbuffers req_buf; | |
1882 | ||
1883 | gsc_handle = (struct GSC_HANDLE *)handle; | |
1884 | ||
1885 | Exynos_gsc_In(); | |
1886 | ||
1887 | if (handle == NULL) { | |
1888 | ALOGE("%s::handle == NULL() fail", __func__); | |
1889 | return -1; | |
1890 | } | |
1891 | ||
1892 | if ((gsc_handle->src.stream_on == false) || (gsc_handle->dst.stream_on == false)) { | |
1893 | ALOGE("%s:: src_strean_on or dst_stream_on are false", __func__); | |
1894 | return -1; | |
1895 | } | |
1896 | ||
70007c4e | 1897 | if (exynos_v4l2_dqbuf(gsc_handle->gsc_fd, &gsc_handle->src.buffer) < 0) { |
6134b8bb | 1898 | ALOGE("%s::exynos_v4l2_dqbuf(src) fail", __func__); |
7b062be7 | 1899 | return -1; |
70007c4e JC |
1900 | } |
1901 | ||
1902 | if (exynos_v4l2_dqbuf(gsc_handle->gsc_fd, &gsc_handle->dst.buffer) < 0) { | |
6134b8bb | 1903 | ALOGE("%s::exynos_v4l2_dqbuf(dst) fail", __func__); |
7b062be7 YS |
1904 | return -1; |
1905 | } | |
1906 | ||
1907 | if (exynos_v4l2_streamoff(gsc_handle->gsc_fd, gsc_handle->src.buf_type) < 0) { | |
1908 | ALOGE("%s::exynos_v4l2_streamoff(src) fail", __func__); | |
1909 | return -1; | |
1910 | } | |
1911 | gsc_handle->src.stream_on = false; | |
1912 | ||
1913 | if (exynos_v4l2_streamoff(gsc_handle->gsc_fd, gsc_handle->dst.buf_type) < 0) { | |
1914 | ALOGE("%s::exynos_v4l2_streamoff(dst) fail", __func__); | |
1915 | return -1; | |
1916 | } | |
1917 | gsc_handle->dst.stream_on = false; | |
1918 | ||
1919 | /* src: clear_buf */ | |
1920 | req_buf.count = 0; | |
1921 | req_buf.type = gsc_handle->src.buf_type; | |
1922 | req_buf.memory = V4L2_MEMORY_DMABUF; | |
1923 | if (exynos_v4l2_reqbufs(gsc_handle->gsc_fd, &req_buf) < 0) { | |
1924 | ALOGE("%s::exynos_v4l2_reqbufs():src: fail", __func__); | |
1925 | return -1; | |
1926 | } | |
1927 | ||
1928 | /* dst: clear_buf */ | |
1929 | req_buf.count = 0; | |
1930 | req_buf.type = gsc_handle->dst.buf_type; | |
1931 | req_buf.memory = V4L2_MEMORY_DMABUF; | |
1932 | if (exynos_v4l2_reqbufs(gsc_handle->gsc_fd, &req_buf) < 0) { | |
1933 | ALOGE("%s::exynos_v4l2_reqbufs():dst: fail", __func__); | |
1934 | return -1; | |
1935 | } | |
1936 | ||
1937 | Exynos_gsc_Out(); | |
1938 | ||
1939 | return 0; | |
1940 | } | |
1941 | ||
1942 | int exynos_gsc_convert( | |
1943 | void *handle) | |
1944 | { | |
1945 | struct GSC_HANDLE *gsc_handle; | |
1946 | int ret = -1; | |
1947 | gsc_handle = (struct GSC_HANDLE *)handle; | |
1948 | ||
1949 | Exynos_gsc_In(); | |
1950 | ||
1951 | if (handle == NULL) { | |
1952 | ALOGE("%s::handle == NULL() fail", __func__); | |
1953 | return -1; | |
1954 | } | |
1955 | ||
1956 | exynos_mutex_lock(gsc_handle->op_mutex); | |
1957 | ||
1958 | if (gsc_handle->flag_local_path == true) { | |
1959 | ALOGE("%s::this exynos_gsc is connected by another hw internaly. So, don't call exynos_gsc_convert()", __func__); | |
1960 | goto done; | |
1961 | } | |
1962 | ||
1963 | if (exynos_gsc_m2m_run_core(handle) < 0) { | |
1964 | ALOGE("%s::exynos_gsc_run_core fail", __func__); | |
1965 | goto done; | |
1966 | } | |
1967 | ||
1968 | if (exynos_gsc_m2m_wait_frame_done(handle) < 0) { | |
1969 | ALOGE("%s::exynos_gsc_m2m_wait_frame_done", __func__); | |
70007c4e JC |
1970 | goto done; |
1971 | } | |
1972 | ||
1973 | ret = 0; | |
1974 | ||
1975 | done: | |
1976 | if (gsc_handle->flag_exclusive_open == false) { | |
1977 | if (gsc_handle->flag_local_path == false) | |
1978 | exynos_mutex_unlock(gsc_handle->cur_obj_mutex); | |
1979 | } | |
1980 | ||
1981 | exynos_mutex_unlock(gsc_handle->op_mutex); | |
1982 | ||
e6a0625b JC |
1983 | Exynos_gsc_Out(); |
1984 | ||
70007c4e JC |
1985 | return ret; |
1986 | } | |
1987 | ||
e6a0625b JC |
1988 | int exynos_gsc_m2m_run(void *handle, |
1989 | exynos_gsc_img *src_img, | |
1990 | exynos_gsc_img *dst_img) | |
1991 | { | |
1992 | void *addr[3] = {NULL, NULL, NULL}; | |
1993 | int ret = 0; | |
1994 | ||
1995 | Exynos_gsc_In(); | |
1996 | ||
1997 | addr[0] = (void *)src_img->yaddr; | |
1998 | addr[1] = (void *)src_img->uaddr; | |
1999 | addr[2] = (void *)src_img->vaddr; | |
2000 | ||
2001 | ret = exynos_gsc_set_src_addr(handle, addr); | |
2002 | if (ret < 0) { | |
2003 | ALOGE("%s::fail: exynos_gsc_set_src_addr[%x %x %x]", __func__, | |
2004 | (unsigned int)addr[0], (unsigned int)addr[1], (unsigned int)addr[2]); | |
7b062be7 | 2005 | return -1; |
e6a0625b JC |
2006 | } |
2007 | ||
2008 | addr[0] = (void *)dst_img->yaddr; | |
2009 | addr[1] = (void *)dst_img->uaddr; | |
2010 | addr[2] = (void *)dst_img->vaddr; | |
2011 | ret = exynos_gsc_set_dst_addr(handle, addr); | |
2012 | if (ret < 0) { | |
2013 | ALOGE("%s::fail: exynos_gsc_set_dst_addr[%x %x %x]", __func__, | |
2014 | (unsigned int)addr[0], (unsigned int)addr[1], (unsigned int)addr[2]); | |
7b062be7 | 2015 | return -1; |
e6a0625b JC |
2016 | } |
2017 | ||
7b062be7 | 2018 | ret = exynos_gsc_m2m_run_core(handle); |
e6a0625b | 2019 | if (ret < 0) { |
7b062be7 YS |
2020 | ALOGE("%s::fail: exynos_gsc_m2m_run_core", __func__); |
2021 | return -1; | |
e6a0625b JC |
2022 | } |
2023 | ||
2024 | Exynos_gsc_Out(); | |
2025 | ||
2026 | return 0; | |
2027 | } | |
2028 | ||
70007c4e | 2029 | int exynos_gsc_config_exclusive(void *handle, |
e6a0625b JC |
2030 | exynos_gsc_img *src_img, |
2031 | exynos_gsc_img *dst_img) | |
70007c4e | 2032 | { |
e6a0625b JC |
2033 | |
2034 | Exynos_gsc_In(); | |
2035 | ||
70007c4e JC |
2036 | struct GSC_HANDLE *gsc_handle; |
2037 | int ret = 0; | |
2038 | gsc_handle = (struct GSC_HANDLE *)handle; | |
70007c4e | 2039 | if (handle == NULL) { |
6134b8bb | 2040 | ALOGE("%s::handle == NULL() fail", __func__); |
70007c4e JC |
2041 | return -1; |
2042 | } | |
2043 | ||
2044 | switch (gsc_handle->gsc_mode) { | |
2045 | case GSC_M2M_MODE: | |
e6a0625b | 2046 | ret = exynos_gsc_m2m_config(handle, src_img, dst_img); |
70007c4e JC |
2047 | break; |
2048 | case GSC_OUTPUT_MODE: | |
2049 | ret = exynos_gsc_out_config(handle, src_img, dst_img); | |
2050 | break; | |
2051 | case GSC_CAPTURE_MODE: | |
2052 | //to do | |
2053 | break; | |
2054 | default: | |
2055 | break; | |
2056 | } | |
e6a0625b JC |
2057 | |
2058 | Exynos_gsc_Out(); | |
2059 | ||
70007c4e JC |
2060 | return ret; |
2061 | ||
2062 | } | |
2063 | ||
2064 | int exynos_gsc_run_exclusive(void *handle, | |
e6a0625b JC |
2065 | exynos_gsc_img *src_img, |
2066 | exynos_gsc_img *dst_img) | |
70007c4e JC |
2067 | { |
2068 | struct GSC_HANDLE *gsc_handle; | |
2069 | int ret = 0; | |
7b062be7 YS |
2070 | |
2071 | Exynos_gsc_In(); | |
2072 | ||
70007c4e | 2073 | gsc_handle = (struct GSC_HANDLE *)handle; |
70007c4e | 2074 | if (handle == NULL) { |
6134b8bb | 2075 | ALOGE("%s::handle == NULL() fail", __func__); |
70007c4e JC |
2076 | return -1; |
2077 | } | |
2078 | ||
2079 | switch (gsc_handle->gsc_mode) { | |
2080 | case GSC_M2M_MODE: | |
e6a0625b | 2081 | ret = exynos_gsc_m2m_run(handle, src_img, dst_img); |
70007c4e JC |
2082 | break; |
2083 | case GSC_OUTPUT_MODE: | |
2084 | ret = exynos_gsc_out_run(handle, src_img->yaddr, | |
2085 | src_img->uaddr, src_img->vaddr); | |
2086 | break; | |
2087 | case GSC_CAPTURE_MODE: | |
2088 | //to do | |
2089 | break; | |
2090 | default: | |
2091 | break; | |
2092 | } | |
7b062be7 YS |
2093 | |
2094 | Exynos_gsc_Out(); | |
2095 | ||
70007c4e JC |
2096 | return ret; |
2097 | } | |
2098 | ||
2099 | int exynos_gsc_stop_exclusive(void *handle) | |
2100 | { | |
2101 | struct GSC_HANDLE *gsc_handle; | |
2102 | int ret = 0; | |
2103 | gsc_handle = (struct GSC_HANDLE *)handle; | |
e6a0625b JC |
2104 | |
2105 | Exynos_gsc_In(); | |
2106 | ||
70007c4e | 2107 | if (handle == NULL) { |
6134b8bb | 2108 | ALOGE("%s::handle == NULL() fail", __func__); |
70007c4e JC |
2109 | return -1; |
2110 | } | |
2111 | ||
2112 | switch (gsc_handle->gsc_mode) { | |
2113 | case GSC_M2M_MODE: | |
7b062be7 | 2114 | ret = exynos_gsc_m2m_wait_frame_done(handle); |
70007c4e JC |
2115 | break; |
2116 | case GSC_OUTPUT_MODE: | |
2117 | ret = exynos_gsc_out_stop(handle); | |
2118 | break; | |
2119 | case GSC_CAPTURE_MODE: | |
2120 | //to do | |
2121 | break; | |
2122 | default: | |
e6a0625b | 2123 | break; |
70007c4e | 2124 | } |
e6a0625b JC |
2125 | |
2126 | Exynos_gsc_Out(); | |
2127 | ||
70007c4e | 2128 | return ret; |
70007c4e JC |
2129 | } |
2130 | ||
70007c4e JC |
2131 | int exynos_gsc_connect( |
2132 | void *handle, | |
2133 | void *hw) | |
2134 | { | |
2135 | struct GSC_HANDLE *gsc_handle; | |
2136 | int ret = -1; | |
2137 | gsc_handle = (struct GSC_HANDLE *)handle; | |
2138 | ||
e6a0625b JC |
2139 | Exynos_gsc_In(); |
2140 | ||
70007c4e | 2141 | if (handle == NULL) { |
6134b8bb | 2142 | ALOGE("%s::handle == NULL() fail", __func__); |
70007c4e JC |
2143 | return -1; |
2144 | } | |
2145 | ||
2146 | exynos_mutex_lock(gsc_handle->op_mutex); | |
2147 | ||
2148 | gsc_handle->flag_local_path = true; | |
2149 | ||
2150 | if (exynos_mutex_trylock(gsc_handle->cur_obj_mutex) == false) { | |
2151 | if (m_exynos_gsc_find_and_trylock_and_create(gsc_handle) == false) { | |
6134b8bb | 2152 | ALOGE("%s::m_exynos_gsc_find_and_trylock_and_create() fail", __func__); |
70007c4e JC |
2153 | goto done; |
2154 | } | |
2155 | } | |
2156 | ||
2157 | ret = 0; | |
2158 | ||
e6a0625b JC |
2159 | Exynos_gsc_Out(); |
2160 | ||
70007c4e JC |
2161 | done: |
2162 | exynos_mutex_unlock(gsc_handle->op_mutex); | |
2163 | ||
2164 | return ret; | |
2165 | } | |
2166 | ||
2167 | int exynos_gsc_disconnect( | |
2168 | void *handle, | |
2169 | void *hw) | |
2170 | { | |
2171 | struct GSC_HANDLE *gsc_handle; | |
2172 | gsc_handle = (struct GSC_HANDLE *)handle; | |
2173 | ||
e6a0625b JC |
2174 | Exynos_gsc_In(); |
2175 | ||
70007c4e | 2176 | if (handle == NULL) { |
6134b8bb | 2177 | ALOGE("%s::handle == NULL() fail", __func__); |
70007c4e JC |
2178 | return -1; |
2179 | } | |
2180 | ||
2181 | exynos_mutex_lock(gsc_handle->op_mutex); | |
2182 | ||
2183 | gsc_handle->flag_local_path = false; | |
2184 | ||
2185 | exynos_mutex_unlock(gsc_handle->cur_obj_mutex); | |
2186 | ||
2187 | exynos_mutex_unlock(gsc_handle->op_mutex); | |
2188 | ||
e6a0625b JC |
2189 | Exynos_gsc_Out(); |
2190 | ||
70007c4e JC |
2191 | return 0; |
2192 | } |