blob: 43d17d9c9612ff407ecaf6ff8d43039f83c46841 [file] [log] [blame]
Benjamin Chan59a06052017-01-12 18:06:03 -05001/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
Alan Kwong4b416162017-08-11 21:03:10 -040012#define pr_fmt(fmt) "%s:%d: " fmt, __func__, __LINE__
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -070013
14#include <linux/vmalloc.h>
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/pm_runtime.h>
19#include <linux/regulator/consumer.h>
20#include <linux/ion.h>
21#include <linux/msm_ion.h>
22#include <linux/delay.h>
23#include <linux/wait.h>
24#include <linux/of.h>
25#include <media/v4l2-ioctl.h>
26#include <media/v4l2-event.h>
Alan Kwong3428f672016-04-18 12:32:06 -040027#include <media/videobuf2-v4l2.h>
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -070028#include <media/v4l2-mem2mem.h>
29
Alan Kwong6bc64622017-02-04 17:36:03 -080030#include "sde_rotator_inline.h"
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -070031#include "sde_rotator_base.h"
32#include "sde_rotator_core.h"
33#include "sde_rotator_dev.h"
34#include "sde_rotator_debug.h"
35#include "sde_rotator_trace.h"
36
37/* Start v4l2 device number (default allocation) */
38#define SDE_ROTATOR_BASE_DEVICE_NUMBER -1
39
40/* Default value for early_submit flag */
41#define SDE_ROTATOR_EARLY_SUBMIT 1
42
43/* Timeout (msec) waiting for stream to turn off. */
44#define SDE_ROTATOR_STREAM_OFF_TIMEOUT 500
45
46/* acquire fence time out, following other driver fence time out practice */
47#define SDE_ROTATOR_FENCE_TIMEOUT MSEC_PER_SEC
48
Alan Kwongbfda8b982017-08-01 14:54:34 -040049/* Timeout (msec) waiting for ctx open */
50#define SDE_ROTATOR_CTX_OPEN_TIMEOUT 500
51
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -070052/* Rotator default fps */
53#define SDE_ROTATOR_DEFAULT_FPS 60
54
55/* Rotator rotation angles */
56#define SDE_ROTATOR_DEGREE_270 270
57#define SDE_ROTATOR_DEGREE_180 180
58#define SDE_ROTATOR_DEGREE_90 90
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -070059
Benjamin Chanf8d9a462016-11-08 21:38:10 -050060static void sde_rotator_submit_handler(struct kthread_work *work);
61static void sde_rotator_retire_handler(struct kthread_work *work);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -070062#ifdef CONFIG_COMPAT
63static long sde_rotator_compat_ioctl32(struct file *file,
64 unsigned int cmd, unsigned long arg);
65#endif
66
67/*
68 * sde_rotator_ctx_from_fh - Get rotator context from v4l2 fh.
69 * @fh: Pointer to v4l2 fh.
70 */
71static inline struct sde_rotator_ctx *sde_rotator_ctx_from_fh(
72 struct v4l2_fh *fh)
73{
74 return container_of(fh, struct sde_rotator_ctx, fh);
75}
76
77/*
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -070078 * sde_rotator_get_flags_from_ctx - Get low-level command flag
79 * @ctx: Pointer to rotator context.
80 */
81static uint32_t sde_rotator_get_flags_from_ctx(struct sde_rotator_ctx *ctx)
82{
83 uint32_t ret_flags = 0;
84
85 if (ctx->rotate == SDE_ROTATOR_DEGREE_270)
86 ret_flags |= SDE_ROTATION_270;
87 else if (ctx->rotate == SDE_ROTATOR_DEGREE_180)
88 ret_flags |= SDE_ROTATION_180;
89 else if (ctx->rotate == SDE_ROTATOR_DEGREE_90)
90 ret_flags |= SDE_ROTATION_90;
91 if (ctx->hflip)
92 ret_flags ^= SDE_ROTATION_FLIP_LR;
93 if (ctx->vflip)
94 ret_flags ^= SDE_ROTATION_FLIP_UD;
95 if (ctx->secure)
96 ret_flags |= SDE_ROTATION_SECURE;
Abhijit Kulkarni298c8232016-09-26 22:32:10 -070097 if (ctx->secure_camera)
98 ret_flags |= SDE_ROTATION_SECURE_CAMERA;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -070099 if (ctx->format_out.fmt.pix.field == V4L2_FIELD_INTERLACED &&
100 ctx->format_cap.fmt.pix.field == V4L2_FIELD_NONE)
101 ret_flags |= SDE_ROTATION_DEINTERLACE;
102
103 return ret_flags;
104}
105
106/*
107 * sde_rotator_get_config_from_ctx - Fill rotator configure structure.
108 * @ctx: Pointer to rotator ctx.
109 * @config: Pointer to config structure.
110 */
111static void sde_rotator_get_config_from_ctx(struct sde_rotator_ctx *ctx,
112 struct sde_rotation_config *config)
113{
114 memset(config, 0, sizeof(struct sde_rotation_config));
115 config->flags = sde_rotator_get_flags_from_ctx(ctx);
116 config->frame_rate = (ctx->timeperframe.numerator) ?
117 ctx->timeperframe.denominator
118 / ctx->timeperframe.numerator : 0;
119 config->session_id = ctx->session_id;
120 config->input.width = ctx->crop_out.width;
121 config->input.height = ctx->crop_out.height;
122 config->input.format = ctx->format_out.fmt.pix.pixelformat;
123 config->input.comp_ratio.numer = 1;
124 config->input.comp_ratio.denom = 1;
125 config->output.width = ctx->crop_cap.width;
126 config->output.height = ctx->crop_cap.height;
127 config->output.format = ctx->format_cap.fmt.pix.pixelformat;
128 config->output.comp_ratio.numer = 1;
129 config->output.comp_ratio.denom = 1;
Alan Kwong09a36ef2016-11-10 01:39:16 -0500130
131 /*
132 * Use compression ratio of the first buffer to estimate
133 * performance requirement of the session. If core layer does
134 * not support dynamic per buffer compression ratio recalculation,
135 * this configuration will determine the overall static compression
136 * ratio of the session.
137 */
138 if (ctx->vbinfo_out)
139 config->input.comp_ratio = ctx->vbinfo_out[0].comp_ratio;
140 if (ctx->vbinfo_cap)
141 config->output.comp_ratio = ctx->vbinfo_cap[0].comp_ratio;
142
143 SDEDEV_DBG(ctx->rot_dev->dev, "config s:%d out_cr:%u/%u cap_cr:%u/%u\n",
144 ctx->session_id,
145 config->input.comp_ratio.numer,
146 config->input.comp_ratio.denom,
147 config->output.comp_ratio.numer,
148 config->output.comp_ratio.denom);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700149}
150
151/*
152 * sde_rotator_get_item_from_ctx - Fill rotator item structure.
153 * @ctx: Pointer to rotator ctx.
154 * @item: Pointer to item structure.
155 */
156static void sde_rotator_get_item_from_ctx(struct sde_rotator_ctx *ctx,
157 struct sde_rotation_item *item)
158{
159 memset(item, 0, sizeof(struct sde_rotation_item));
160 item->flags = sde_rotator_get_flags_from_ctx(ctx);
161 item->session_id = ctx->session_id;
162 item->sequence_id = 0;
163 /* assign high/low priority */
Alan Kwong3428f672016-04-18 12:32:06 -0400164 item->wb_idx = (ctx->fh.prio >= V4L2_PRIORITY_DEFAULT) ? 0 : 1;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700165 item->src_rect.x = ctx->crop_out.left;
166 item->src_rect.y = ctx->crop_out.top;
167 item->src_rect.w = ctx->crop_out.width;
168 item->src_rect.h = ctx->crop_out.height;
169 item->input.width = ctx->format_out.fmt.pix.width;
170 item->input.height = ctx->format_out.fmt.pix.height;
171 item->input.format = ctx->format_out.fmt.pix.pixelformat;
172 item->input.planes[0].fd = -1;
173 item->input.planes[0].offset = 0;
174 item->input.planes[0].stride = ctx->format_out.fmt.pix.bytesperline;
175 item->input.plane_count = 1;
176 item->input.fence = NULL;
177 item->input.comp_ratio.numer = 1;
178 item->input.comp_ratio.denom = 1;
179
180 item->dst_rect.x = ctx->crop_cap.left;
181 item->dst_rect.y = ctx->crop_cap.top;
182 item->dst_rect.w = ctx->crop_cap.width;
183 item->dst_rect.h = ctx->crop_cap.height;
184 item->output.width = ctx->format_cap.fmt.pix.width;
185 item->output.height = ctx->format_cap.fmt.pix.height;
186 item->output.format = ctx->format_cap.fmt.pix.pixelformat;
187 item->output.planes[0].fd = -1;
188 item->output.planes[0].offset = 0;
189 item->output.planes[0].stride = ctx->format_cap.fmt.pix.bytesperline;
190 item->output.plane_count = 1;
191 item->output.fence = NULL;
192 item->output.comp_ratio.numer = 1;
193 item->output.comp_ratio.denom = 1;
194}
195
196/*
197 * sde_rotator_format_recalc - Recalculate format parameters.
198 * @f: v4l2 format.
199 */
200static void sde_rotator_format_recalc(struct v4l2_format *f)
201{
202 int ret;
203 struct sde_mdp_format_params *fmt;
204 struct sde_mdp_plane_sizes ps;
205
206 fmt = sde_get_format_params(f->fmt.pix.pixelformat);
207 if (!fmt) {
208 SDEROT_ERR("invalid format\n");
209 goto error_fmt;
210 }
211
212 ret = sde_mdp_get_plane_sizes(fmt,
213 f->fmt.pix.width, f->fmt.pix.height, &ps, 0, 0);
214 if (ret) {
215 SDEROT_ERR("invalid plane size\n");
216 goto error_fmt;
217 }
218
219 f->fmt.pix.bytesperline = ps.ystride[0];
220 f->fmt.pix.sizeimage = ps.total_size;
221
222 return;
223error_fmt:
224 f->fmt.pix.bytesperline = 0;
225 f->fmt.pix.sizeimage = 0;
226}
227
228/*
229 * sde_rotator_validate_item - Check if rotator item is valid for processing.
230 * @ctx: Pointer to rotator ctx.
231 * @item: Pointer to item structure
232 */
233static int sde_rotator_validate_item(struct sde_rotator_ctx *ctx,
234 struct sde_rotation_item *item)
235{
236 int ret;
237 struct sde_rot_entry_container *req;
238 struct sde_rotator_device *rot_dev = ctx->rot_dev;
239
240 sde_rot_mgr_lock(rot_dev->mgr);
241 req = sde_rotator_req_init(rot_dev->mgr, ctx->private, item, 1, 0);
242 if (IS_ERR_OR_NULL(req)) {
243 SDEDEV_ERR(rot_dev->dev, "fail allocate item\n");
244 return -ENOMEM;
245 }
246
247 ret = sde_rotator_validate_request(rot_dev->mgr, ctx->private, req);
248 sde_rot_mgr_unlock(rot_dev->mgr);
249 devm_kfree(rot_dev->dev, req);
250 return ret;
251}
252
253/*
254 * sde_rotator_queue_setup - vb2_ops queue_setup callback.
255 * @q: Pointer to vb2 queue struct.
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700256 * @num_buffers: Pointer of number of buffers requested.
257 * @num_planes: Pointer to number of planes requested.
258 * @sizes: Array containing sizes of planes.
259 * @alloc_ctxs: Array of allocated contexts for each plane.
260 */
261static int sde_rotator_queue_setup(struct vb2_queue *q,
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700262 unsigned int *num_buffers, unsigned int *num_planes,
Alan Kwong6ce448d2016-11-24 18:45:20 -0800263 unsigned int sizes[], struct device *alloc_devs[])
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700264{
265 struct sde_rotator_ctx *ctx = vb2_get_drv_priv(q);
266 int i;
267
268 if (!num_buffers)
269 return -EINVAL;
270
Alan Kwong6ce448d2016-11-24 18:45:20 -0800271 switch (q->type) {
272 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
273 sizes[0] = ctx->format_out.fmt.pix.sizeimage;
274 break;
275 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
276 sizes[0] = ctx->format_cap.fmt.pix.sizeimage;
277 break;
278 default:
279 return -EINVAL;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700280 }
281
282 *num_planes = 1;
Alan Kwong6ce448d2016-11-24 18:45:20 -0800283 alloc_devs[0] = (struct device *)ctx;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700284
285 switch (q->type) {
286 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
287 ctx->nbuf_out = *num_buffers;
288 kfree(ctx->vbinfo_out);
289 ctx->vbinfo_out = kzalloc(sizeof(struct sde_rotator_vbinfo) *
290 ctx->nbuf_out, GFP_KERNEL);
291 if (!ctx->vbinfo_out)
292 return -ENOMEM;
Alan Kwong09a36ef2016-11-10 01:39:16 -0500293 for (i = 0; i < ctx->nbuf_out; i++) {
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700294 ctx->vbinfo_out[i].fd = -1;
Alan Kwong09a36ef2016-11-10 01:39:16 -0500295 ctx->vbinfo_out[i].comp_ratio.numer = 1;
296 ctx->vbinfo_out[i].comp_ratio.denom = 1;
297 }
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700298 break;
299 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
300 ctx->nbuf_cap = *num_buffers;
301 kfree(ctx->vbinfo_cap);
302 ctx->vbinfo_cap = kzalloc(sizeof(struct sde_rotator_vbinfo) *
303 ctx->nbuf_cap, GFP_KERNEL);
304 if (!ctx->vbinfo_cap)
305 return -ENOMEM;
Alan Kwong09a36ef2016-11-10 01:39:16 -0500306 for (i = 0; i < ctx->nbuf_cap; i++) {
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700307 ctx->vbinfo_cap[i].fd = -1;
Alan Kwong09a36ef2016-11-10 01:39:16 -0500308 ctx->vbinfo_cap[i].comp_ratio.numer = 1;
309 ctx->vbinfo_cap[i].comp_ratio.denom = 1;
310 }
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700311 break;
312 default:
313 return -EINVAL;
314 }
315
316 return 0;
317}
318
319/*
320 * sde_rotator_buf_queue - vb2_ops buf_queue callback.
321 * @vb: Pointer to vb2 buffer struct.
322 */
323static void sde_rotator_buf_queue(struct vb2_buffer *vb)
324{
325 struct sde_rotator_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
Alan Kwong3428f672016-04-18 12:32:06 -0400326 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700327
Alan Kwong3428f672016-04-18 12:32:06 -0400328 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700329}
330
331/*
Alan Kwongaf529092016-11-03 14:18:41 -0400332 * sde_rotator_buf_finish - vb2_ops buf_finish to finalize buffer before going
333 * back to user space
334 * @vb: Pointer to vb2 buffer struct.
335 */
336static void sde_rotator_buf_finish(struct vb2_buffer *vb)
337{
338 struct sde_rotator_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
339 int i;
340
341 SDEDEV_DBG(ctx->rot_dev->dev,
342 "buf_finish t:%d i:%d s:%d m:%u np:%d up:%lu\n",
343 vb->type, vb->index, vb->state,
344 vb->vb2_queue->memory,
345 vb->num_planes,
346 vb->planes[0].m.userptr);
347
348 if (vb->vb2_queue->memory != VB2_MEMORY_USERPTR)
349 return;
350
351 /*
352 * We use userptr to tunnel fd, and fd can be the same across qbuf
353 * even though the underlying buffer is different. Since vb2 layer
354 * optimizes memory mapping for userptr by first checking if userptr
355 * has changed, it will not trigger put_userptr if fd value does
356 * not change. In order to force buffer release, we need to clear
357 * userptr when the current buffer is done and ready to go back to
358 * user mode. Since 0 is a valid fd, reset userptr to -1 instead.
359 */
360 for (i = 0; i < vb->num_planes; i++)
361 vb->planes[i].m.userptr = ~0;
362}
363
364/*
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700365 * sde_rotator_return_all_buffers - Return all buffers with the given status.
366 * @q: Pointer to vb2 buffer queue struct.
367 * @state: State of the buffer
368 */
369static void sde_rotator_return_all_buffers(struct vb2_queue *q,
370 enum vb2_buffer_state state)
371{
372 struct sde_rotator_ctx *ctx = vb2_get_drv_priv(q);
373 struct sde_rotator_device *rot_dev = ctx->rot_dev;
374
375 SDEDEV_DBG(rot_dev->dev,
376 "return q t:%d c:%d dc:%d s:%d\n",
377 q->type, q->queued_count,
378 atomic_read(&q->owned_by_drv_count),
379 state);
380
381 /* return buffers according videobuffer2-core.h */
382 if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
Alan Kwong3428f672016-04-18 12:32:06 -0400383 struct vb2_v4l2_buffer *buf;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700384
Alan Kwong3428f672016-04-18 12:32:06 -0400385 while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) {
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700386 SDEDEV_DBG(rot_dev->dev,
387 "return vb t:%d i:%d\n",
Alan Kwong3428f672016-04-18 12:32:06 -0400388 buf->vb2_buf.type,
389 buf->vb2_buf.index);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700390 v4l2_m2m_buf_done(buf, state);
391 }
392 } else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
Alan Kwong3428f672016-04-18 12:32:06 -0400393 struct vb2_v4l2_buffer *buf;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700394
Alan Kwong3428f672016-04-18 12:32:06 -0400395 while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) {
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700396 SDEDEV_DBG(rot_dev->dev,
397 "return vb t:%d i:%d\n",
Alan Kwong3428f672016-04-18 12:32:06 -0400398 buf->vb2_buf.type,
399 buf->vb2_buf.index);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700400 v4l2_m2m_buf_done(buf, state);
401 }
402 } else {
403 SDEDEV_ERR(rot_dev->dev, "unsupported vb t:%d\n", q->type);
404 }
405}
406
407/*
408 * sde_rotator_start_streaming - vb2_ops start_streaming callback.
409 * @q: Pointer to vb2 queue struct.
410 * @count: Number of buffer queued before stream on call.
411 */
412static int sde_rotator_start_streaming(struct vb2_queue *q, unsigned int count)
413{
414 struct sde_rotator_ctx *ctx = vb2_get_drv_priv(q);
415 struct sde_rotator_device *rot_dev = ctx->rot_dev;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700416
417 SDEDEV_DBG(rot_dev->dev, "start streaming s:%d t:%d\n",
418 ctx->session_id, q->type);
419
Alan Kwongf94a2552016-12-28 09:41:22 -0800420 if (!list_empty(&ctx->pending_list)) {
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700421 SDEDEV_ERR(rot_dev->dev,
422 "command pending error s:%d t:%d p:%d\n",
423 ctx->session_id, q->type,
Alan Kwongf94a2552016-12-28 09:41:22 -0800424 !list_empty(&ctx->pending_list));
425 return -EINVAL;
426 }
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700427
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700428 ctx->abort_pending = 0;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700429
430 return 0;
431}
432
433/*
434 * sde_rotator_stop_streaming - vb2_ops stop_streaming callback.
435 * @q: Pointer to vb2 queue struct.
436 *
437 * This function will block waiting for stream to stop. Unlock queue
438 * lock to avoid deadlock.
439 */
440static void sde_rotator_stop_streaming(struct vb2_queue *q)
441{
442 struct sde_rotator_ctx *ctx = vb2_get_drv_priv(q);
443 struct sde_rotator_device *rot_dev = ctx->rot_dev;
Jayant Shekhar4e29b942017-04-04 17:37:54 +0530444 struct sde_rotator_request *request;
445 struct list_head *curr, *next;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700446 int i;
447 int ret;
448
449 SDEDEV_DBG(rot_dev->dev, "stop streaming s:%d t:%d p:%d\n",
450 ctx->session_id, q->type,
Alan Kwongf94a2552016-12-28 09:41:22 -0800451 !list_empty(&ctx->pending_list));
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700452 ctx->abort_pending = 1;
453 mutex_unlock(q->lock);
454 ret = wait_event_timeout(ctx->wait_queue,
Alan Kwongf94a2552016-12-28 09:41:22 -0800455 list_empty(&ctx->pending_list),
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700456 msecs_to_jiffies(rot_dev->streamoff_timeout));
457 mutex_lock(q->lock);
Benjamin Chand0a22cf2017-03-01 17:40:20 -0500458 if (!ret) {
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700459 SDEDEV_ERR(rot_dev->dev,
460 "timeout to stream off s:%d t:%d p:%d\n",
461 ctx->session_id, q->type,
Alan Kwongf94a2552016-12-28 09:41:22 -0800462 !list_empty(&ctx->pending_list));
Alan Kwongde85fcd2017-07-31 18:18:49 -0400463 SDEROT_EVTLOG(ctx->session_id, q->type,
464 !list_empty(&ctx->pending_list),
465 SDE_ROT_EVTLOG_ERROR);
Benjamin Chand0a22cf2017-03-01 17:40:20 -0500466 sde_rot_mgr_lock(rot_dev->mgr);
467 sde_rotator_cancel_all_requests(rot_dev->mgr, ctx->private);
468 sde_rot_mgr_unlock(rot_dev->mgr);
Jayant Shekhar4e29b942017-04-04 17:37:54 +0530469 list_for_each_safe(curr, next, &ctx->pending_list) {
470 request = container_of(curr, struct sde_rotator_request,
471 list);
472
473 SDEDEV_DBG(rot_dev->dev, "cancel request s:%d\n",
474 ctx->session_id);
475 mutex_unlock(q->lock);
Benjamin Chanf8d9a462016-11-08 21:38:10 -0500476 kthread_cancel_work_sync(&request->submit_work);
477 kthread_cancel_work_sync(&request->retire_work);
Jayant Shekhar4e29b942017-04-04 17:37:54 +0530478 mutex_lock(q->lock);
479 spin_lock(&ctx->list_lock);
480 list_del_init(&request->list);
481 list_add_tail(&request->list, &ctx->retired_list);
482 spin_unlock(&ctx->list_lock);
483 }
Benjamin Chand0a22cf2017-03-01 17:40:20 -0500484 }
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700485
486 sde_rotator_return_all_buffers(q, VB2_BUF_STATE_ERROR);
487
488 /* clear fence for buffer */
489 sde_rotator_resync_timeline(ctx->work_queue.timeline);
490 if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
491 for (i = 0; i < ctx->nbuf_cap; i++) {
492 struct sde_rotator_vbinfo *vbinfo =
493 &ctx->vbinfo_cap[i];
494
Benjamin Chan834d21d2017-06-15 18:18:54 -0400495 if (vbinfo->fence) {
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700496 /* fence is not used */
497 SDEDEV_DBG(rot_dev->dev,
498 "put fence s:%d t:%d i:%d\n",
499 ctx->session_id, q->type, i);
500 sde_rotator_put_sync_fence(vbinfo->fence);
501 }
502 vbinfo->fence = NULL;
503 vbinfo->fd = -1;
504 }
505 } else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
506 for (i = 0; i < ctx->nbuf_out; i++) {
507 struct sde_rotator_vbinfo *vbinfo =
508 &ctx->vbinfo_out[i];
509
510 if (vbinfo->fence) {
511 SDEDEV_DBG(rot_dev->dev,
512 "put fence s:%d t:%d i:%d\n",
513 ctx->session_id, q->type, i);
514 sde_rotator_put_sync_fence(vbinfo->fence);
515 }
516 vbinfo->fence = NULL;
517 vbinfo->fd = -1;
518 }
519 }
520}
521
522/* Videobuf2 queue callbacks. */
Alan Kwong6ce448d2016-11-24 18:45:20 -0800523static const struct vb2_ops sde_rotator_vb2_q_ops = {
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700524 .queue_setup = sde_rotator_queue_setup,
525 .buf_queue = sde_rotator_buf_queue,
526 .start_streaming = sde_rotator_start_streaming,
527 .stop_streaming = sde_rotator_stop_streaming,
528 .wait_prepare = vb2_ops_wait_prepare,
529 .wait_finish = vb2_ops_wait_finish,
Alan Kwongaf529092016-11-03 14:18:41 -0400530 .buf_finish = sde_rotator_buf_finish,
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700531};
532
533/*
534 * sde_rotator_get_userptr - Map and get buffer handler for user pointer buffer.
Alan Kwong6ce448d2016-11-24 18:45:20 -0800535 * @dev: device allocated in buf_setup.
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700536 * @vaddr: Virtual addr passed from userpsace (in our case ion fd)
537 * @size: Size of the buffer
Alan Kwong3428f672016-04-18 12:32:06 -0400538 * @dma_dir: DMA data direction of the given buffer.
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700539 */
Alan Kwong6ce448d2016-11-24 18:45:20 -0800540static void *sde_rotator_get_userptr(struct device *dev,
Alan Kwong3428f672016-04-18 12:32:06 -0400541 unsigned long vaddr, unsigned long size,
542 enum dma_data_direction dma_dir)
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700543{
Alan Kwong6ce448d2016-11-24 18:45:20 -0800544 struct sde_rotator_ctx *ctx = (struct sde_rotator_ctx *)dev;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700545 struct sde_rotator_device *rot_dev = ctx->rot_dev;
546 struct sde_rotator_buf_handle *buf;
Abhijit Kulkarni298c8232016-09-26 22:32:10 -0700547 struct ion_client *iclient = rot_dev->mdata->iclient;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700548
549 buf = kzalloc(sizeof(*buf), GFP_KERNEL);
550 if (!buf)
551 return ERR_PTR(-ENOMEM);
552
553 buf->fd = vaddr;
Abhijit Kulkarni298c8232016-09-26 22:32:10 -0700554 buf->secure = ctx->secure || ctx->secure_camera;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700555 buf->ctx = ctx;
556 buf->rot_dev = rot_dev;
Abhijit Kulkarni298c8232016-09-26 22:32:10 -0700557 if (ctx->secure_camera) {
Alan Kwong6ce448d2016-11-24 18:45:20 -0800558 buf->handle = ion_import_dma_buf_fd(iclient,
Abhijit Kulkarni298c8232016-09-26 22:32:10 -0700559 buf->fd);
560 if (IS_ERR_OR_NULL(buf->handle)) {
561 SDEDEV_ERR(rot_dev->dev,
562 "fail get ion_handler fd:%d r:%ld\n",
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700563 buf->fd, PTR_ERR(buf->buffer));
Abhijit Kulkarni298c8232016-09-26 22:32:10 -0700564 goto error_buf_get;
565 }
566 SDEDEV_DBG(rot_dev->dev,
567 "get ion_handle s:%d fd:%d buf:%pad\n",
568 buf->ctx->session_id,
569 buf->fd, &buf->handle);
570 } else {
571 buf->buffer = dma_buf_get(buf->fd);
572 if (IS_ERR_OR_NULL(buf->buffer)) {
573 SDEDEV_ERR(rot_dev->dev,
574 "fail get dmabuf fd:%d r:%ld\n",
575 buf->fd, PTR_ERR(buf->buffer));
576 goto error_buf_get;
577 }
578 SDEDEV_DBG(rot_dev->dev,
579 "get dmabuf s:%d fd:%d buf:%pad\n",
580 buf->ctx->session_id,
581 buf->fd, &buf->buffer);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700582 }
583
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700584 return buf;
Abhijit Kulkarni298c8232016-09-26 22:32:10 -0700585error_buf_get:
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700586 kfree(buf);
587 return ERR_PTR(-ENOMEM);
588}
589
590/*
591 * sde_rotator_put_userptr - Unmap and free buffer handler.
592 * @buf_priv: Buffer handler allocated get_userptr callback.
593 */
594static void sde_rotator_put_userptr(void *buf_priv)
595{
596 struct sde_rotator_buf_handle *buf = buf_priv;
597
598 if (IS_ERR_OR_NULL(buf))
599 return;
600
601 if (!buf->rot_dev || !buf->ctx) {
602 WARN_ON(!buf->rot_dev || !buf->ctx);
603 SDEROT_ERR("null rotator device/context\n");
604 return;
605 }
606
607 SDEDEV_DBG(buf->rot_dev->dev, "put dmabuf s:%d fd:%d buf:%pad\n",
608 buf->ctx->session_id,
609 buf->fd, &buf->buffer);
610
611 if (buf->buffer) {
612 dma_buf_put(buf->buffer);
613 buf->buffer = NULL;
614 }
615
616 kfree(buf_priv);
617}
618
619/* Videobuf2 memory callbacks. */
620static struct vb2_mem_ops sde_rotator_vb2_mem_ops = {
621 .get_userptr = sde_rotator_get_userptr,
622 .put_userptr = sde_rotator_put_userptr,
623};
624
625/*
626 * sde_rotator_s_ctx_ctrl - set context control variable to v4l2 control
627 * @ctx: Pointer to rotator context.
628 * @ctx_ctrl: Pointer to context control variable
629 * @ctrl: Pointer to v4l2 control variable
630 */
631static int sde_rotator_s_ctx_ctrl(struct sde_rotator_ctx *ctx,
632 s32 *ctx_ctrl, struct v4l2_ctrl *ctrl)
633{
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700634 *ctx_ctrl = ctrl->val;
Benjamin Chandbe13112016-09-26 12:10:06 -0400635 return 0;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700636}
637
638/*
639 * sde_rotator_s_ctrl - Set control.
640 * @ctrl: Pointer to v4l2 control structure.
641 */
642static int sde_rotator_s_ctrl(struct v4l2_ctrl *ctrl)
643{
644 struct sde_rotator_ctx *ctx =
645 container_of(ctrl->handler,
646 struct sde_rotator_ctx, ctrl_handler);
647 struct sde_rotator_device *rot_dev = ctx->rot_dev;
648 int ret;
649
650 SDEDEV_DBG(rot_dev->dev, "set %s:%d s:%d\n", ctrl->name, ctrl->val,
651 ctx->session_id);
652
653 sde_rot_mgr_lock(rot_dev->mgr);
654
655 switch (ctrl->id) {
656 case V4L2_CID_HFLIP:
657 ret = sde_rotator_s_ctx_ctrl(ctx, &ctx->hflip, ctrl);
658 break;
659
660 case V4L2_CID_VFLIP:
661 ret = sde_rotator_s_ctx_ctrl(ctx, &ctx->vflip, ctrl);
662 break;
663
664 case V4L2_CID_ROTATE:
665 ret = sde_rotator_s_ctx_ctrl(ctx, &ctx->rotate, ctrl);
666 break;
667
668 case V4L2_CID_SDE_ROTATOR_SECURE:
669 ret = sde_rotator_s_ctx_ctrl(ctx, &ctx->secure, ctrl);
670 break;
671
Abhijit Kulkarni298c8232016-09-26 22:32:10 -0700672 case V4L2_CID_SDE_ROTATOR_SECURE_CAMERA:
673 ret = sde_rotator_s_ctx_ctrl(ctx, &ctx->secure_camera, ctrl);
674 break;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700675 default:
676 v4l2_warn(&rot_dev->v4l2_dev, "invalid control %d\n", ctrl->id);
677 ret = -EINVAL;
678 }
679
680 sde_rot_mgr_unlock(rot_dev->mgr);
681 return ret;
682}
683
684/*
685 * sde_rotator_ctrl_ops - Control operations.
686 */
687static const struct v4l2_ctrl_ops sde_rotator_ctrl_ops = {
688 .s_ctrl = sde_rotator_s_ctrl,
689};
690
691/*
692 * sde_rotator_ctrl_secure - Non-secure/Secure.
693 */
694static const struct v4l2_ctrl_config sde_rotator_ctrl_secure = {
695 .ops = &sde_rotator_ctrl_ops,
696 .id = V4L2_CID_SDE_ROTATOR_SECURE,
697 .name = "Non-secure/Secure Domain",
698 .type = V4L2_CTRL_TYPE_INTEGER,
699 .def = 0,
700 .min = 0,
701 .max = 1,
702 .step = 1,
703};
704
Abhijit Kulkarni298c8232016-09-26 22:32:10 -0700705static const struct v4l2_ctrl_config sde_rotator_ctrl_secure_camera = {
706 .ops = &sde_rotator_ctrl_ops,
707 .id = V4L2_CID_SDE_ROTATOR_SECURE_CAMERA,
708 .name = "Secure Camera content",
709 .type = V4L2_CTRL_TYPE_INTEGER,
710 .def = 0,
711 .min = 0,
712 .max = 1,
713 .step = 1,
714};
715
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700716/*
717 * sde_rotator_ctx_show - show context state.
718 */
719static ssize_t sde_rotator_ctx_show(struct kobject *kobj,
720 struct kobj_attribute *attr, char *buf)
721{
722 size_t len = PAGE_SIZE;
723 int cnt = 0;
724 struct sde_rotator_ctx *ctx =
725 container_of(kobj, struct sde_rotator_ctx, kobj);
726
727 if (!ctx)
728 return cnt;
729
730#define SPRINT(fmt, ...) \
731 (cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__))
732
733 SPRINT("rotate=%d\n", ctx->rotate);
734 SPRINT("hflip=%d\n", ctx->hflip);
735 SPRINT("vflip=%d\n", ctx->vflip);
Alan Kwong3428f672016-04-18 12:32:06 -0400736 SPRINT("priority=%d\n", ctx->fh.prio);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700737 SPRINT("secure=%d\n", ctx->secure);
738 SPRINT("timeperframe=%u %u\n", ctx->timeperframe.numerator,
739 ctx->timeperframe.denominator);
740 SPRINT("nbuf_out=%d\n", ctx->nbuf_out);
741 SPRINT("nbuf_cap=%d\n", ctx->nbuf_cap);
742 SPRINT("crop_out=%u %u %u %u\n",
743 ctx->crop_out.left, ctx->crop_out.top,
744 ctx->crop_out.width, ctx->crop_out.height);
745 SPRINT("crop_cap=%u %u %u %u\n",
746 ctx->crop_cap.left, ctx->crop_cap.top,
747 ctx->crop_cap.width, ctx->crop_cap.height);
748 SPRINT("fmt_out=%c%c%c%c %u %u %u %u\n",
749 (ctx->format_out.fmt.pix.pixelformat>>0)&0xff,
750 (ctx->format_out.fmt.pix.pixelformat>>8)&0xff,
751 (ctx->format_out.fmt.pix.pixelformat>>16)&0xff,
752 (ctx->format_out.fmt.pix.pixelformat>>24)&0xff,
753 ctx->format_out.fmt.pix.width,
754 ctx->format_out.fmt.pix.height,
755 ctx->format_out.fmt.pix.bytesperline,
756 ctx->format_out.fmt.pix.sizeimage);
757 SPRINT("fmt_cap=%c%c%c%c %u %u %u %u\n",
758 (ctx->format_cap.fmt.pix.pixelformat>>0)&0xff,
759 (ctx->format_cap.fmt.pix.pixelformat>>8)&0xff,
760 (ctx->format_cap.fmt.pix.pixelformat>>16)&0xff,
761 (ctx->format_cap.fmt.pix.pixelformat>>24)&0xff,
762 ctx->format_cap.fmt.pix.width,
763 ctx->format_cap.fmt.pix.height,
764 ctx->format_cap.fmt.pix.bytesperline,
765 ctx->format_cap.fmt.pix.sizeimage);
766 SPRINT("abort_pending=%d\n", ctx->abort_pending);
Alan Kwongf94a2552016-12-28 09:41:22 -0800767 SPRINT("command_pending=%d\n", !list_empty(&ctx->pending_list));
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700768 SPRINT("sequence=%u\n",
769 sde_rotator_get_timeline_commit_ts(ctx->work_queue.timeline));
770 SPRINT("timestamp=%u\n",
771 sde_rotator_get_timeline_retire_ts(ctx->work_queue.timeline));
772 return cnt;
773}
774
775static struct kobj_attribute sde_rotator_ctx_attr =
776 __ATTR(state, 0664, sde_rotator_ctx_show, NULL);
777
778static struct attribute *sde_rotator_fs_attrs[] = {
779 &sde_rotator_ctx_attr.attr,
780 NULL
781};
782
783static struct attribute_group sde_rotator_fs_attr_group = {
784 .attrs = sde_rotator_fs_attrs
785};
786
787/*
788 * sde_rotator_ctx_show - sysfs show callback.
789 */
790static ssize_t sde_rotator_fs_show(struct kobject *kobj,
791 struct attribute *attr, char *buf)
792{
793 ssize_t ret = -EIO;
794 struct kobj_attribute *kattr =
795 container_of(attr, struct kobj_attribute, attr);
796 if (kattr->show)
797 ret = kattr->show(kobj, kattr, buf);
798 return ret;
799}
800
801/*
802 * sde_rotator_fs_store - sysfs store callback.
803 */
804static ssize_t sde_rotator_fs_store(struct kobject *kobj,
805 struct attribute *attr, const char *buf, size_t count)
806{
807 ssize_t ret = -EIO;
808 struct kobj_attribute *kattr =
809 container_of(attr, struct kobj_attribute, attr);
810 if (kattr->store)
811 ret = kattr->store(kobj, kattr, buf, count);
812 return ret;
813}
814
815static const struct sysfs_ops sde_rotator_fs_ops = {
816 .show = sde_rotator_fs_show,
817 .store = sde_rotator_fs_store,
818};
819
820static struct kobj_type sde_rotator_fs_ktype = {
821 .sysfs_ops = &sde_rotator_fs_ops,
822};
823
824/*
825 * sde_rotator_queue_init - m2m_ops queue_setup callback.
826 * @priv: Pointer to rotator ctx.
827 * @src_vq: vb2 source queue.
828 * @dst_vq: vb2 destination queue.
829 */
830static int sde_rotator_queue_init(void *priv, struct vb2_queue *src_vq,
831 struct vb2_queue *dst_vq)
832{
833 struct sde_rotator_ctx *ctx = priv;
834 int ret;
835
836 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
837 src_vq->io_modes = VB2_USERPTR;
838 src_vq->drv_priv = ctx;
839 src_vq->mem_ops = &sde_rotator_vb2_mem_ops;
840 src_vq->ops = &sde_rotator_vb2_q_ops;
841 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
842 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
843 src_vq->lock = &ctx->rot_dev->lock;
844 src_vq->min_buffers_needed = 1;
Alan Kwong6ce448d2016-11-24 18:45:20 -0800845 src_vq->dev = ctx->rot_dev->dev;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700846
847 ret = vb2_queue_init(src_vq);
848 if (ret) {
849 SDEDEV_ERR(ctx->rot_dev->dev,
850 "fail init src queue r:%d\n", ret);
851 return ret;
852 }
853
854 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
855 dst_vq->io_modes = VB2_USERPTR;
856 dst_vq->drv_priv = ctx;
857 dst_vq->mem_ops = &sde_rotator_vb2_mem_ops;
858 dst_vq->ops = &sde_rotator_vb2_q_ops;
859 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
860 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
861 dst_vq->lock = &ctx->rot_dev->lock;
862 dst_vq->min_buffers_needed = 1;
Alan Kwong6ce448d2016-11-24 18:45:20 -0800863 src_vq->dev = ctx->rot_dev->dev;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700864
865 ret = vb2_queue_init(dst_vq);
866 if (ret) {
867 SDEDEV_ERR(ctx->rot_dev->dev,
868 "fail init dst queue r:%d\n", ret);
869 return ret;
870 }
871
872 return 0;
873}
874
875/*
Alan Kwong6bc64622017-02-04 17:36:03 -0800876 * sde_rotator_ctx_open - Rotator device open method.
877 * @rot_dev: Pointer to rotator device structure
878 * @file: Pointer to file struct (optional)
879 * return: Pointer rotator context if success; ptr error code, otherwise.
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700880 */
Alan Kwong6bc64622017-02-04 17:36:03 -0800881struct sde_rotator_ctx *sde_rotator_ctx_open(
882 struct sde_rotator_device *rot_dev, struct file *file)
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700883{
Alan Kwong6bc64622017-02-04 17:36:03 -0800884 struct video_device *video = file ? video_devdata(file) : NULL;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700885 struct sde_rotator_ctx *ctx;
886 struct v4l2_ctrl_handler *ctrl_handler;
887 char name[32];
Alan Kwongf94a2552016-12-28 09:41:22 -0800888 int i, ret;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700889
890 if (atomic_read(&rot_dev->mgr->device_suspended))
Alan Kwong6bc64622017-02-04 17:36:03 -0800891 return ERR_PTR(-EPERM);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700892
893 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
894 if (!ctx)
Alan Kwong6bc64622017-02-04 17:36:03 -0800895 return ERR_PTR(-ENOMEM);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700896
897 if (mutex_lock_interruptible(&rot_dev->lock)) {
898 ret = -ERESTARTSYS;
899 goto error_lock;
900 }
901
Alan Kwongbfda8b982017-08-01 14:54:34 -0400902 /* wait until exclusive ctx, if exists, finishes or timeout */
903 while (rot_dev->excl_ctx) {
904 SDEROT_DBG("waiting to open %s session %d ...\n",
905 file ? "v4l2" : "excl", rot_dev->session_id);
906 mutex_unlock(&rot_dev->lock);
907 ret = wait_event_interruptible_timeout(rot_dev->open_wq,
908 !rot_dev->excl_ctx,
909 msecs_to_jiffies(rot_dev->open_timeout));
910 if (ret < 0) {
911 goto error_lock;
912 } else if (!ret) {
913 SDEROT_WARN("timeout to open session %d\n",
914 rot_dev->session_id);
915 SDEROT_EVTLOG(rot_dev->session_id,
916 SDE_ROT_EVTLOG_ERROR);
917 ret = -EBUSY;
918 goto error_lock;
919 } else if (mutex_lock_interruptible(&rot_dev->lock)) {
920 ret = -ERESTARTSYS;
921 goto error_lock;
922 }
923 }
924
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700925 ctx->rot_dev = rot_dev;
Alan Kwong6bc64622017-02-04 17:36:03 -0800926 ctx->file = file;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700927
928 /* Set context defaults */
929 ctx->session_id = rot_dev->session_id++;
930 SDEDEV_DBG(ctx->rot_dev->dev, "open %d\n", ctx->session_id);
931 ctx->timeperframe.numerator = 1;
932 ctx->timeperframe.denominator = SDE_ROTATOR_DEFAULT_FPS;
933 ctx->hflip = 0;
934 ctx->vflip = 0;
935 ctx->rotate = 0;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700936 ctx->secure = 0;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700937 ctx->abort_pending = 0;
938 ctx->format_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
939 ctx->format_cap.fmt.pix.pixelformat = SDE_PIX_FMT_Y_CBCR_H2V2;
940 ctx->format_cap.fmt.pix.width = 640;
941 ctx->format_cap.fmt.pix.height = 480;
942 ctx->crop_cap.width = 640;
943 ctx->crop_cap.height = 480;
944 ctx->format_out.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
945 ctx->format_out.fmt.pix.pixelformat = SDE_PIX_FMT_Y_CBCR_H2V2;
946 ctx->format_out.fmt.pix.width = 640;
947 ctx->format_out.fmt.pix.height = 480;
948 ctx->crop_out.width = 640;
949 ctx->crop_out.height = 480;
950 init_waitqueue_head(&ctx->wait_queue);
Alan Kwongf94a2552016-12-28 09:41:22 -0800951 spin_lock_init(&ctx->list_lock);
952 INIT_LIST_HEAD(&ctx->pending_list);
953 INIT_LIST_HEAD(&ctx->retired_list);
954
955 for (i = 0 ; i < ARRAY_SIZE(ctx->requests); i++) {
956 struct sde_rotator_request *request = &ctx->requests[i];
957
Benjamin Chanf8d9a462016-11-08 21:38:10 -0500958 kthread_init_work(&request->submit_work,
Alan Kwongf94a2552016-12-28 09:41:22 -0800959 sde_rotator_submit_handler);
Benjamin Chanf8d9a462016-11-08 21:38:10 -0500960 kthread_init_work(&request->retire_work,
Alan Kwongf94a2552016-12-28 09:41:22 -0800961 sde_rotator_retire_handler);
962 request->ctx = ctx;
963 INIT_LIST_HEAD(&request->list);
964 list_add_tail(&request->list, &ctx->retired_list);
965 }
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700966
Alan Kwong6bc64622017-02-04 17:36:03 -0800967 if (ctx->file) {
968 v4l2_fh_init(&ctx->fh, video);
969 file->private_data = &ctx->fh;
970 v4l2_fh_add(&ctx->fh);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700971
Alan Kwong6bc64622017-02-04 17:36:03 -0800972 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(rot_dev->m2m_dev,
973 ctx, sde_rotator_queue_init);
974 if (IS_ERR_OR_NULL(ctx->fh.m2m_ctx)) {
975 ret = PTR_ERR(ctx->fh.m2m_ctx);
976 goto error_m2m_init;
977 }
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700978 }
979
980 ret = kobject_init_and_add(&ctx->kobj, &sde_rotator_fs_ktype,
981 &rot_dev->dev->kobj, "session_%d", ctx->session_id);
982 if (ret) {
983 SDEDEV_ERR(ctx->rot_dev->dev,
984 "fail initialize context kobject\n");
985 goto error_kobj_init;
986 }
987
988 ret = sysfs_create_group(&ctx->kobj, &sde_rotator_fs_attr_group);
989 if (ret) {
990 SDEDEV_ERR(ctx->rot_dev->dev,
991 "fail register rotator sysfs nodes\n");
992 goto error_create_sysfs;
993 }
994
995 snprintf(name, sizeof(name), "rot_fenceq_%d_%d", rot_dev->dev->id,
996 ctx->session_id);
Benjamin Chanf8d9a462016-11-08 21:38:10 -0500997 kthread_init_worker(&ctx->work_queue.rot_kw);
998 ctx->work_queue.rot_thread = kthread_run(kthread_worker_fn,
999 &ctx->work_queue.rot_kw, name);
1000 if (IS_ERR(ctx->work_queue.rot_thread)) {
1001 SDEDEV_ERR(ctx->rot_dev->dev, "fail allocate kthread\n");
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001002 ret = -EPERM;
Benjamin Chanf8d9a462016-11-08 21:38:10 -05001003 ctx->work_queue.rot_thread = NULL;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001004 goto error_alloc_workqueue;
1005 }
Benjamin Chanf8d9a462016-11-08 21:38:10 -05001006 SDEDEV_DBG(ctx->rot_dev->dev, "kthread name=%s\n", name);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001007
1008 snprintf(name, sizeof(name), "%d_%d", rot_dev->dev->id,
1009 ctx->session_id);
1010 ctx->work_queue.timeline = sde_rotator_create_timeline(name);
1011 if (!ctx->work_queue.timeline)
1012 SDEDEV_DBG(ctx->rot_dev->dev, "timeline is not available\n");
1013
1014 sde_rot_mgr_lock(rot_dev->mgr);
1015 ret = sde_rotator_session_open(rot_dev->mgr, &ctx->private,
1016 ctx->session_id, &ctx->work_queue);
1017 if (ret < 0) {
1018 SDEDEV_ERR(ctx->rot_dev->dev, "fail open session\n");
1019 goto error_open_session;
1020 }
1021 sde_rot_mgr_unlock(rot_dev->mgr);
1022
Alan Kwong6bc64622017-02-04 17:36:03 -08001023 if (ctx->file) {
Alan Kwongbfda8b982017-08-01 14:54:34 -04001024 /* Create control */
Alan Kwong6bc64622017-02-04 17:36:03 -08001025 ctrl_handler = &ctx->ctrl_handler;
1026 v4l2_ctrl_handler_init(ctrl_handler, 4);
1027 v4l2_ctrl_new_std(ctrl_handler,
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001028 &sde_rotator_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
Alan Kwong6bc64622017-02-04 17:36:03 -08001029 v4l2_ctrl_new_std(ctrl_handler,
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001030 &sde_rotator_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
Alan Kwong6bc64622017-02-04 17:36:03 -08001031 v4l2_ctrl_new_std(ctrl_handler,
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001032 &sde_rotator_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0);
Alan Kwong6bc64622017-02-04 17:36:03 -08001033 v4l2_ctrl_new_custom(ctrl_handler,
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001034 &sde_rotator_ctrl_secure, NULL);
Alan Kwong6bc64622017-02-04 17:36:03 -08001035 v4l2_ctrl_new_custom(ctrl_handler,
Abhijit Kulkarni298c8232016-09-26 22:32:10 -07001036 &sde_rotator_ctrl_secure_camera, NULL);
Alan Kwong6bc64622017-02-04 17:36:03 -08001037 if (ctrl_handler->error) {
1038 ret = ctrl_handler->error;
1039 v4l2_ctrl_handler_free(ctrl_handler);
1040 goto error_ctrl_handler;
1041 }
1042 ctx->fh.ctrl_handler = ctrl_handler;
1043 v4l2_ctrl_handler_setup(ctrl_handler);
Alan Kwongbfda8b982017-08-01 14:54:34 -04001044 } else {
1045 /* acquire exclusive context */
1046 SDEDEV_DBG(rot_dev->dev, "acquire exclusive session id:%u\n",
1047 ctx->session_id);
1048 SDEROT_EVTLOG(ctx->session_id);
1049 rot_dev->excl_ctx = ctx;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001050 }
Alan Kwongbfda8b982017-08-01 14:54:34 -04001051
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001052 mutex_unlock(&rot_dev->lock);
1053
1054 SDEDEV_DBG(ctx->rot_dev->dev, "SDE v4l2 rotator open success\n");
1055
1056 ATRACE_BEGIN(ctx->kobj.name);
1057
Alan Kwong6bc64622017-02-04 17:36:03 -08001058 return ctx;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001059error_ctrl_handler:
1060error_open_session:
1061 sde_rot_mgr_unlock(rot_dev->mgr);
1062 sde_rotator_destroy_timeline(ctx->work_queue.timeline);
Benjamin Chanf8d9a462016-11-08 21:38:10 -05001063 kthread_flush_worker(&ctx->work_queue.rot_kw);
1064 kthread_stop(ctx->work_queue.rot_thread);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001065error_alloc_workqueue:
1066 sysfs_remove_group(&ctx->kobj, &sde_rotator_fs_attr_group);
1067error_create_sysfs:
1068 kobject_put(&ctx->kobj);
1069error_kobj_init:
1070error_m2m_init:
Alan Kwong6bc64622017-02-04 17:36:03 -08001071 if (ctx->file) {
1072 v4l2_fh_del(&ctx->fh);
1073 v4l2_fh_exit(&ctx->fh);
1074 }
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001075 mutex_unlock(&rot_dev->lock);
1076error_lock:
1077 kfree(ctx);
Alan Kwong6bc64622017-02-04 17:36:03 -08001078 return ERR_PTR(ret);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001079}
1080
1081/*
Alan Kwong6bc64622017-02-04 17:36:03 -08001082 * sde_rotator_ctx_release - Rotator device release method.
1083 * @ctx: Pointer rotator context.
1084 * @file: Pointer to file struct (optional)
1085 * return: 0 if success; error code, otherwise
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001086 */
Alan Kwong6bc64622017-02-04 17:36:03 -08001087static int sde_rotator_ctx_release(struct sde_rotator_ctx *ctx,
1088 struct file *file)
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001089{
Alan Kwong6bc64622017-02-04 17:36:03 -08001090 struct sde_rotator_device *rot_dev = ctx->rot_dev;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001091 u32 session_id = ctx->session_id;
Alan Kwongf94a2552016-12-28 09:41:22 -08001092 struct list_head *curr, *next;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001093
1094 ATRACE_END(ctx->kobj.name);
1095
1096 SDEDEV_DBG(rot_dev->dev, "release s:%d\n", session_id);
1097 mutex_lock(&rot_dev->lock);
Alan Kwongbfda8b982017-08-01 14:54:34 -04001098 if (rot_dev->excl_ctx == ctx) {
1099 SDEDEV_DBG(rot_dev->dev, "release exclusive session id:%u\n",
1100 session_id);
1101 SDEROT_EVTLOG(session_id);
1102 rot_dev->excl_ctx = NULL;
1103 }
Alan Kwong6bc64622017-02-04 17:36:03 -08001104 if (ctx->file) {
1105 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
1106 SDEDEV_DBG(rot_dev->dev, "release streams s:%d\n", session_id);
1107 v4l2_m2m_streamoff(file, ctx->fh.m2m_ctx,
1108 V4L2_BUF_TYPE_VIDEO_OUTPUT);
1109 v4l2_m2m_streamoff(file, ctx->fh.m2m_ctx,
1110 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1111 }
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001112 mutex_unlock(&rot_dev->lock);
Alan Kwongf94a2552016-12-28 09:41:22 -08001113 SDEDEV_DBG(rot_dev->dev, "release submit work s:%d\n", session_id);
1114 list_for_each_safe(curr, next, &ctx->pending_list) {
1115 struct sde_rotator_request *request =
1116 container_of(curr, struct sde_rotator_request, list);
1117
1118 SDEDEV_DBG(rot_dev->dev, "release submit work s:%d\n",
1119 session_id);
Benjamin Chanf8d9a462016-11-08 21:38:10 -05001120 kthread_cancel_work_sync(&request->submit_work);
Alan Kwongf94a2552016-12-28 09:41:22 -08001121 }
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001122 SDEDEV_DBG(rot_dev->dev, "release session s:%d\n", session_id);
1123 sde_rot_mgr_lock(rot_dev->mgr);
1124 sde_rotator_session_close(rot_dev->mgr, ctx->private, session_id);
1125 sde_rot_mgr_unlock(rot_dev->mgr);
Alan Kwongf94a2552016-12-28 09:41:22 -08001126 SDEDEV_DBG(rot_dev->dev, "release retire work s:%d\n", session_id);
1127 list_for_each_safe(curr, next, &ctx->pending_list) {
1128 struct sde_rotator_request *request =
1129 container_of(curr, struct sde_rotator_request, list);
1130
1131 SDEDEV_DBG(rot_dev->dev, "release retire work s:%d\n",
1132 session_id);
Benjamin Chanf8d9a462016-11-08 21:38:10 -05001133 kthread_cancel_work_sync(&request->retire_work);
Alan Kwongf94a2552016-12-28 09:41:22 -08001134 }
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001135 mutex_lock(&rot_dev->lock);
1136 SDEDEV_DBG(rot_dev->dev, "release context s:%d\n", session_id);
1137 sde_rotator_destroy_timeline(ctx->work_queue.timeline);
Benjamin Chanf8d9a462016-11-08 21:38:10 -05001138 kthread_flush_worker(&ctx->work_queue.rot_kw);
1139 kthread_stop(ctx->work_queue.rot_thread);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001140 sysfs_remove_group(&ctx->kobj, &sde_rotator_fs_attr_group);
1141 kobject_put(&ctx->kobj);
Alan Kwong6bc64622017-02-04 17:36:03 -08001142 if (ctx->file) {
1143 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
1144 v4l2_fh_del(&ctx->fh);
1145 v4l2_fh_exit(&ctx->fh);
1146 }
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001147 kfree(ctx->vbinfo_out);
1148 kfree(ctx->vbinfo_cap);
1149 kfree(ctx);
Alan Kwongbfda8b982017-08-01 14:54:34 -04001150 wake_up_interruptible(&rot_dev->open_wq);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001151 mutex_unlock(&rot_dev->lock);
1152 SDEDEV_DBG(rot_dev->dev, "release complete s:%d\n", session_id);
1153 return 0;
1154}
1155
1156/*
Alan Kwongf94a2552016-12-28 09:41:22 -08001157 * sde_rotator_update_retire_sequence - update retired sequence of the context
1158 * referenced in the request, and wake up any waiting for update event
1159 * @request: Pointer to rotator request
1160 */
1161static void sde_rotator_update_retire_sequence(
1162 struct sde_rotator_request *request)
1163{
1164 struct sde_rotator_ctx *ctx;
Alan Kwongf94a2552016-12-28 09:41:22 -08001165
1166 if (!request || !request->ctx) {
1167 SDEROT_ERR("invalid parameters\n");
1168 return;
1169 }
1170
1171 ctx = request->ctx;
Alan Kwong3ddf48c2017-10-06 10:45:41 -04001172 ctx->retired_sequence_id = request->sequence_id;
Alan Kwongf94a2552016-12-28 09:41:22 -08001173
1174 wake_up(&ctx->wait_queue);
1175
1176 SDEROT_DBG("update sequence s:%d.%d\n",
1177 ctx->session_id, ctx->retired_sequence_id);
1178}
1179
1180/*
1181 * sde_rotator_retire_request - retire the given rotator request with
1182 * device mutex locked
1183 * @request: Pointer to rotator request
1184 */
1185static void sde_rotator_retire_request(struct sde_rotator_request *request)
1186{
1187 struct sde_rotator_ctx *ctx;
1188
1189 if (!request || !request->ctx) {
1190 SDEROT_ERR("invalid parameters\n");
1191 return;
1192 }
1193
1194 ctx = request->ctx;
1195
1196 request->req = NULL;
Alan Kwong3ddf48c2017-10-06 10:45:41 -04001197 request->sequence_id = 0;
Alan Kwong6bc64622017-02-04 17:36:03 -08001198 request->committed = false;
Alan Kwongf94a2552016-12-28 09:41:22 -08001199 spin_lock(&ctx->list_lock);
1200 list_del_init(&request->list);
1201 list_add_tail(&request->list, &ctx->retired_list);
1202 spin_unlock(&ctx->list_lock);
1203
Alan Kwong49311e82017-11-20 18:11:29 -05001204 wake_up(&ctx->wait_queue);
1205
Alan Kwongf94a2552016-12-28 09:41:22 -08001206 SDEROT_DBG("retire request s:%d.%d\n",
1207 ctx->session_id, ctx->retired_sequence_id);
1208}
1209
1210/*
Alan Kwong6bc64622017-02-04 17:36:03 -08001211 * sde_rotator_is_request_retired - Return true if given request already expired
1212 * @request: Pointer to rotator request
1213 */
1214static bool sde_rotator_is_request_retired(struct sde_rotator_request *request)
1215{
1216 struct sde_rotator_ctx *ctx;
Alan Kwong6bc64622017-02-04 17:36:03 -08001217 u32 sequence_id;
1218 s32 retire_delta;
1219
Alan Kwong3ddf48c2017-10-06 10:45:41 -04001220 if (!request || !request->ctx)
Alan Kwong6bc64622017-02-04 17:36:03 -08001221 return true;
1222
1223 ctx = request->ctx;
Alan Kwong3ddf48c2017-10-06 10:45:41 -04001224 sequence_id = request->sequence_id;
Alan Kwong6bc64622017-02-04 17:36:03 -08001225
1226 retire_delta = (s32) (ctx->retired_sequence_id - sequence_id);
1227
1228 SDEROT_DBG("sequence:%u/%u\n", sequence_id, ctx->retired_sequence_id);
1229
1230 return retire_delta >= 0;
1231}
1232
1233/*
1234 * sde_rotator_inline_open - open inline rotator session
1235 * @pdev: Pointer to rotator platform device
1236 * @video_mode: true if video mode is requested
1237 * return: Pointer to new rotator session context
1238 */
1239void *sde_rotator_inline_open(struct platform_device *pdev)
1240{
1241 struct sde_rotator_device *rot_dev;
1242 struct sde_rotator_ctx *ctx;
1243 int rc;
1244
1245 if (!pdev) {
1246 SDEROT_ERR("invalid platform device\n");
1247 return ERR_PTR(-EINVAL);
1248 }
1249
1250 rot_dev = (struct sde_rotator_device *) platform_get_drvdata(pdev);
1251 if (!rot_dev) {
1252 SDEROT_ERR("invalid rotator device\n");
1253 return ERR_PTR(-EINVAL);
1254 }
1255
1256 ctx = sde_rotator_ctx_open(rot_dev, NULL);
1257 if (IS_ERR_OR_NULL(ctx)) {
1258 rc = PTR_ERR(ctx);
1259 SDEROT_ERR("failed to open rotator context %d\n", rc);
1260 goto rotator_open_error;
1261 }
1262
1263 ctx->slice = llcc_slice_getd(rot_dev->dev, "rotator");
1264 if (IS_ERR(ctx->slice)) {
1265 rc = PTR_ERR(ctx->slice);
1266 SDEROT_ERR("failed to get system cache %d\n", rc);
1267 goto slice_getd_error;
1268 }
1269
1270 if (!rot_dev->disable_syscache) {
1271 rc = llcc_slice_activate(ctx->slice);
1272 if (rc) {
1273 SDEROT_ERR("failed to activate slice %d\n", rc);
1274 goto activate_error;
1275 }
1276 SDEROT_DBG("scid %d size %zukb\n",
1277 llcc_get_slice_id(ctx->slice),
1278 llcc_get_slice_size(ctx->slice));
1279 } else {
1280 SDEROT_DBG("syscache bypassed\n");
1281 }
1282
1283 SDEROT_EVTLOG(ctx->session_id, llcc_get_slice_id(ctx->slice),
1284 llcc_get_slice_size(ctx->slice),
1285 rot_dev->disable_syscache);
1286
1287 return ctx;
1288
1289activate_error:
1290 llcc_slice_putd(ctx->slice);
1291 ctx->slice = NULL;
1292slice_getd_error:
1293 sde_rotator_ctx_release(ctx, NULL);
1294rotator_open_error:
1295 return ERR_PTR(rc);
1296}
1297EXPORT_SYMBOL(sde_rotator_inline_open);
1298
1299int sde_rotator_inline_release(void *handle)
1300{
1301 struct sde_rotator_device *rot_dev;
1302 struct sde_rotator_ctx *ctx;
1303
1304 if (!handle) {
1305 SDEROT_ERR("invalid rotator ctx\n");
1306 return -EINVAL;
1307 }
1308
1309 ctx = handle;
1310 rot_dev = ctx->rot_dev;
1311
1312 if (!rot_dev) {
1313 SDEROT_ERR("invalid rotator device\n");
1314 return -EINVAL;
1315 }
1316
1317 if (ctx->slice) {
1318 if (!rot_dev->disable_syscache)
1319 llcc_slice_deactivate(ctx->slice);
1320 llcc_slice_putd(ctx->slice);
1321 ctx->slice = NULL;
1322 }
1323
1324 SDEROT_EVTLOG(ctx->session_id);
1325
1326 return sde_rotator_ctx_release(ctx, NULL);
1327}
1328EXPORT_SYMBOL(sde_rotator_inline_release);
1329
1330/*
1331 * sde_rotator_inline_get_dst_pixfmt - determine output pixel format
1332 * @pdev: Pointer to platform device
1333 * @src_pixfmt: input pixel format
1334 * @dst_pixfmt: Pointer to output pixel format (output)
1335 * return: 0 if success; error code otherwise
1336 */
1337int sde_rotator_inline_get_dst_pixfmt(struct platform_device *pdev,
1338 u32 src_pixfmt, u32 *dst_pixfmt)
1339{
Alan Kwongd12a4812017-11-30 16:12:57 -05001340 int rc;
1341
1342 if (!src_pixfmt || !dst_pixfmt)
1343 return -EINVAL;
1344
1345 rc = sde_rot_get_base_tilea5x_pixfmt(src_pixfmt, dst_pixfmt);
1346 if (rc)
1347 return rc;
1348
1349 /*
1350 * Currently, NV21 tile is not supported as output; hence,
1351 * override with NV12 tile.
1352 */
1353 if (*dst_pixfmt == SDE_PIX_FMT_Y_CRCB_H2V2_TILE)
1354 *dst_pixfmt = SDE_PIX_FMT_Y_CBCR_H2V2_TILE;
1355
1356 return 0;
Alan Kwong6bc64622017-02-04 17:36:03 -08001357}
1358EXPORT_SYMBOL(sde_rotator_inline_get_dst_pixfmt);
1359
1360/*
1361 * sde_rotator_inline_get_downscale_caps - get scaling capability
1362 * @pdev: Pointer to platform device
1363 * @caps: string buffer for capability
1364 * @len: length of string buffer
1365 * return: length of capability string
1366 */
1367int sde_rotator_inline_get_downscale_caps(struct platform_device *pdev,
1368 char *caps, int len)
1369{
1370 struct sde_rotator_device *rot_dev;
1371 int rc;
1372
1373 if (!pdev) {
1374 SDEROT_ERR("invalid platform device\n");
1375 return -EINVAL;
1376 }
1377
1378 rot_dev = (struct sde_rotator_device *) platform_get_drvdata(pdev);
1379 if (!rot_dev || !rot_dev->mgr) {
1380 SDEROT_ERR("invalid rotator device\n");
1381 return -EINVAL;
1382 }
1383
1384 sde_rot_mgr_lock(rot_dev->mgr);
1385 rc = sde_rotator_get_downscale_caps(rot_dev->mgr, caps, len);
1386 sde_rot_mgr_unlock(rot_dev->mgr);
1387
1388 return rc;
1389}
1390EXPORT_SYMBOL(sde_rotator_inline_get_downscale_caps);
1391
1392/*
Alan Kwongb6c049c2017-03-31 12:50:27 -07001393 * sde_rotator_inline_get_maxlinewidth - get maximum line width of rotator
1394 * @pdev: Pointer to platform device
1395 * return: maximum line width
1396 */
1397int sde_rotator_inline_get_maxlinewidth(struct platform_device *pdev)
1398{
1399 struct sde_rotator_device *rot_dev;
1400 int maxlinewidth;
1401
1402 if (!pdev) {
1403 SDEROT_ERR("invalid platform device\n");
1404 return -EINVAL;
1405 }
1406
1407 rot_dev = (struct sde_rotator_device *)platform_get_drvdata(pdev);
1408 if (!rot_dev || !rot_dev->mgr) {
1409 SDEROT_ERR("invalid rotator device\n");
1410 return -EINVAL;
1411 }
1412
1413 sde_rot_mgr_lock(rot_dev->mgr);
1414 maxlinewidth = sde_rotator_get_maxlinewidth(rot_dev->mgr);
1415 sde_rot_mgr_unlock(rot_dev->mgr);
1416
1417 return maxlinewidth;
1418}
1419EXPORT_SYMBOL(sde_rotator_inline_get_maxlinewidth);
1420
1421/*
Alan Kwong6bc64622017-02-04 17:36:03 -08001422 * sde_rotator_inline_get_pixfmt_caps - get pixel format capability
1423 * @pdev: Pointer to platform device
1424 * @pixfmt: array of pixel format buffer
1425 * @len: length of pixel format buffer
1426 * return: length of pixel format capability if success; error code otherwise
1427 */
1428int sde_rotator_inline_get_pixfmt_caps(struct platform_device *pdev,
1429 bool input, u32 *pixfmts, int len)
1430{
1431 struct sde_rotator_device *rot_dev;
1432 u32 i, pixfmt;
1433
1434 if (!pdev) {
1435 SDEROT_ERR("invalid platform device\n");
1436 return -EINVAL;
1437 }
1438
1439 rot_dev = (struct sde_rotator_device *) platform_get_drvdata(pdev);
1440 if (!rot_dev || !rot_dev->mgr) {
1441 SDEROT_ERR("invalid rotator device\n");
1442 return -EINVAL;
1443 }
1444
1445 sde_rot_mgr_lock(rot_dev->mgr);
1446 for (i = 0;; i++) {
Alan Kwong4b416162017-08-11 21:03:10 -04001447 pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, input,
1448 SDE_ROTATOR_MODE_SBUF);
Alan Kwong6bc64622017-02-04 17:36:03 -08001449 if (!pixfmt)
1450 break;
1451 if (pixfmts && i < len)
1452 pixfmts[i] = pixfmt;
1453 }
1454 sde_rot_mgr_unlock(rot_dev->mgr);
1455
1456 return i;
1457}
1458EXPORT_SYMBOL(sde_rotator_inline_get_pixfmt_caps);
1459
1460/*
Clarence Ipd59419e2017-11-15 16:42:45 -05001461 * _sde_rotator_inline_cleanup - perform inline related request cleanup
1462 * This function assumes rot_dev->mgr lock has been taken when called.
1463 * @handle: Pointer to rotator context
1464 * @request: Pointer to rotation request
1465 * return: 0 if success; -EAGAIN if cleanup should be retried
1466 */
1467static int _sde_rotator_inline_cleanup(void *handle,
1468 struct sde_rotator_request *request)
1469{
1470 struct sde_rotator_ctx *ctx;
1471 struct sde_rotator_device *rot_dev;
1472 int ret;
1473
1474 if (!handle || !request) {
1475 SDEROT_ERR("invalid rotator handle/request\n");
1476 return -EINVAL;
1477 }
1478
1479 ctx = handle;
1480 rot_dev = ctx->rot_dev;
1481
1482 if (!rot_dev || !rot_dev->mgr) {
1483 SDEROT_ERR("invalid rotator device\n");
1484 return -EINVAL;
1485 }
1486
1487 if (request->committed) {
1488 /* wait until request is finished */
1489 sde_rot_mgr_unlock(rot_dev->mgr);
1490 mutex_unlock(&rot_dev->lock);
1491 ret = wait_event_timeout(ctx->wait_queue,
1492 sde_rotator_is_request_retired(request),
1493 msecs_to_jiffies(rot_dev->streamoff_timeout));
1494 mutex_lock(&rot_dev->lock);
1495 sde_rot_mgr_lock(rot_dev->mgr);
1496
1497 if (!ret) {
1498 SDEROT_ERR("timeout w/o retire s:%d\n",
1499 ctx->session_id);
1500 SDEROT_EVTLOG(ctx->session_id, SDE_ROT_EVTLOG_ERROR);
1501 sde_rotator_abort_inline_request(rot_dev->mgr,
1502 ctx->private, request->req);
1503 return -EAGAIN;
1504 } else if (ret == 1) {
1505 SDEROT_ERR("timeout w/ retire s:%d\n", ctx->session_id);
1506 SDEROT_EVTLOG(ctx->session_id, SDE_ROT_EVTLOG_ERROR);
1507 }
1508 }
1509
1510 sde_rotator_req_finish(rot_dev->mgr, ctx->private, request->req);
1511 sde_rotator_retire_request(request);
1512 return 0;
1513}
1514
1515/*
Alan Kwong6bc64622017-02-04 17:36:03 -08001516 * sde_rotator_inline_commit - commit given rotator command
1517 * @handle: Pointer to rotator context
1518 * @cmd: Pointer to rotator command
1519 * @cmd_type: command type - validate/prepare/commit/cleanup
1520 * return: 0 if success; error code otherwise
1521 */
1522int sde_rotator_inline_commit(void *handle, struct sde_rotator_inline_cmd *cmd,
1523 enum sde_rotator_inline_cmd_type cmd_type)
1524{
1525 struct sde_rotator_ctx *ctx;
1526 struct sde_rotator_device *rot_dev;
1527 struct sde_rotator_request *request = NULL;
1528 struct sde_rot_entry_container *req = NULL;
Alan Kwong871fc482017-09-20 11:17:28 -04001529 struct sde_rotation_config rotcfg;
Alan Kwong6bc64622017-02-04 17:36:03 -08001530 ktime_t *ts;
1531 u32 flags = 0;
Alan Kwong871fc482017-09-20 11:17:28 -04001532 int i, ret = 0;
Alan Kwong6bc64622017-02-04 17:36:03 -08001533
1534 if (!handle || !cmd) {
1535 SDEROT_ERR("invalid rotator handle/cmd\n");
1536 return -EINVAL;
1537 }
1538
1539 ctx = handle;
1540 rot_dev = ctx->rot_dev;
1541
Clarence Ipd59419e2017-11-15 16:42:45 -05001542 if (!rot_dev || !rot_dev->mgr) {
Alan Kwong6bc64622017-02-04 17:36:03 -08001543 SDEROT_ERR("invalid rotator device\n");
1544 return -EINVAL;
1545 }
1546
1547 SDEROT_DBG(
Alan Kwong1513d3d2017-08-27 21:20:01 -04001548 "s:%d.%u src:(%u,%u,%u,%u)/%ux%u/%c%c%c%c dst:(%u,%u,%u,%u)/%c%c%c%c r:%d f:%d/%d s:%d fps:%u clk:%llu bw:%llu prefill:%llu wb:%d vid:%d cmd:%d\n",
Alan Kwong6bc64622017-02-04 17:36:03 -08001549 ctx->session_id, cmd->sequence_id,
1550 cmd->src_rect_x, cmd->src_rect_y,
1551 cmd->src_rect_w, cmd->src_rect_h,
1552 cmd->src_width, cmd->src_height,
1553 cmd->src_pixfmt >> 0, cmd->src_pixfmt >> 8,
1554 cmd->src_pixfmt >> 16, cmd->src_pixfmt >> 24,
1555 cmd->dst_rect_x, cmd->dst_rect_y,
1556 cmd->dst_rect_w, cmd->dst_rect_h,
1557 cmd->dst_pixfmt >> 0, cmd->dst_pixfmt >> 8,
1558 cmd->dst_pixfmt >> 16, cmd->dst_pixfmt >> 24,
1559 cmd->rot90, cmd->hflip, cmd->vflip, cmd->secure, cmd->fps,
Alan Kwong1513d3d2017-08-27 21:20:01 -04001560 cmd->clkrate, cmd->data_bw, cmd->prefill_bw,
Alan Kwong6bc64622017-02-04 17:36:03 -08001561 cmd->dst_writeback, cmd->video_mode, cmd_type);
Alan Kwongf366a012017-02-10 20:54:46 -08001562 SDEROT_EVTLOG(ctx->session_id, cmd->sequence_id,
1563 cmd->src_rect_x, cmd->src_rect_y,
1564 cmd->src_rect_w, cmd->src_rect_h,
Alan Kwongf366a012017-02-10 20:54:46 -08001565 cmd->src_pixfmt,
Alan Kwongf366a012017-02-10 20:54:46 -08001566 cmd->dst_rect_w, cmd->dst_rect_h,
1567 cmd->dst_pixfmt,
Alan Kwong1513d3d2017-08-27 21:20:01 -04001568 cmd->fps, cmd->clkrate, cmd->data_bw, cmd->prefill_bw,
Alan Kwongde85fcd2017-07-31 18:18:49 -04001569 (cmd->rot90 << 0) | (cmd->hflip << 1) | (cmd->vflip << 2) |
1570 (cmd->secure << 3) | (cmd->dst_writeback << 4) |
Alan Kwong1513d3d2017-08-27 21:20:01 -04001571 (cmd->video_mode << 5) |
1572 (cmd_type << 24));
Alan Kwong6bc64622017-02-04 17:36:03 -08001573
Clarence Ipd59419e2017-11-15 16:42:45 -05001574 mutex_lock(&rot_dev->lock);
Alan Kwong6bc64622017-02-04 17:36:03 -08001575 sde_rot_mgr_lock(rot_dev->mgr);
1576
1577 if (cmd_type == SDE_ROTATOR_INLINE_CMD_VALIDATE ||
1578 cmd_type == SDE_ROTATOR_INLINE_CMD_COMMIT) {
1579
1580 struct sde_rotation_item item;
1581 struct sde_rotator_statistics *stats = &rot_dev->stats;
1582 int scid = llcc_get_slice_id(ctx->slice);
1583
1584 /* allocate slot for timestamp */
Clarence Ipb25c65c2017-05-17 12:09:23 -04001585 ts = stats->ts[stats->count % SDE_ROTATOR_NUM_EVENTS];
1586 if (cmd_type == SDE_ROTATOR_INLINE_CMD_COMMIT)
1587 stats->count++;
Alan Kwong6bc64622017-02-04 17:36:03 -08001588
1589 if (cmd->rot90)
1590 flags |= SDE_ROTATION_90;
1591 if (cmd->hflip)
1592 flags |= SDE_ROTATION_FLIP_LR;
1593 if (cmd->vflip)
1594 flags |= SDE_ROTATION_FLIP_UD;
1595 if (cmd->secure)
1596 flags |= SDE_ROTATION_SECURE;
1597
Alan Kwongf366a012017-02-10 20:54:46 -08001598 flags |= SDE_ROTATION_EXT_PERF;
1599
Alan Kwong6bc64622017-02-04 17:36:03 -08001600 /* fill in item work structure */
1601 memset(&item, 0, sizeof(struct sde_rotation_item));
1602 item.flags = flags | SDE_ROTATION_EXT_IOVA;
1603 item.trigger = cmd->video_mode ? SDE_ROTATOR_TRIGGER_VIDEO :
1604 SDE_ROTATOR_TRIGGER_COMMAND;
Alan Kwong498d59f2017-02-11 18:56:34 -08001605 item.prefill_bw = cmd->prefill_bw;
Alan Kwong6bc64622017-02-04 17:36:03 -08001606 item.session_id = ctx->session_id;
1607 item.sequence_id = cmd->sequence_id;
1608 item.src_rect.x = cmd->src_rect_x;
1609 item.src_rect.y = cmd->src_rect_y;
1610 item.src_rect.w = cmd->src_rect_w;
1611 item.src_rect.h = cmd->src_rect_h;
1612 item.input.width = cmd->src_width;
1613 item.input.height = cmd->src_height;
1614 item.input.format = cmd->src_pixfmt;
1615
1616 for (i = 0; i < SDE_ROTATOR_INLINE_PLANE_MAX; i++) {
1617 item.input.planes[i].addr = cmd->src_addr[i];
1618 item.input.planes[i].len = cmd->src_len[i];
1619 item.input.planes[i].fd = -1;
1620 }
1621 item.input.plane_count = cmd->src_planes;
1622 item.input.comp_ratio.numer = 1;
1623 item.input.comp_ratio.denom = 1;
1624
1625 item.output.width = cmd->dst_rect_x + cmd->dst_rect_w;
1626 item.output.height = cmd->dst_rect_y + cmd->dst_rect_h;
1627 item.dst_rect.x = cmd->dst_rect_x;
1628 item.dst_rect.y = cmd->dst_rect_y;
1629 item.dst_rect.w = cmd->dst_rect_w;
1630 item.dst_rect.h = cmd->dst_rect_h;
1631 item.output.sbuf = true;
1632 item.output.scid = scid;
1633 item.output.writeback = cmd->dst_writeback;
1634 item.output.format = cmd->dst_pixfmt;
1635
1636 for (i = 0; i < SDE_ROTATOR_INLINE_PLANE_MAX; i++) {
1637 item.output.planes[i].addr = cmd->dst_addr[i];
1638 item.output.planes[i].len = cmd->dst_len[i];
1639 item.output.planes[i].fd = -1;
1640 }
1641 item.output.plane_count = cmd->dst_planes;
1642 item.output.comp_ratio.numer = 1;
1643 item.output.comp_ratio.denom = 1;
1644 item.sequence_id = ++(ctx->commit_sequence_id);
1645 item.ts = ts;
1646
1647 req = sde_rotator_req_init(rot_dev->mgr, ctx->private,
1648 &item, 1, 0);
1649 if (IS_ERR_OR_NULL(req)) {
1650 SDEROT_ERR("fail allocate request s:%d\n",
1651 ctx->session_id);
1652 ret = -ENOMEM;
1653 goto error_init_request;
1654 }
Alan Kwong6bc64622017-02-04 17:36:03 -08001655
Alan Kwong871fc482017-09-20 11:17:28 -04001656 /* initialize session configuration */
Alan Kwong6bc64622017-02-04 17:36:03 -08001657 memset(&rotcfg, 0, sizeof(struct sde_rotation_config));
1658 rotcfg.flags = flags;
1659 rotcfg.frame_rate = cmd->fps;
Alan Kwongf366a012017-02-10 20:54:46 -08001660 rotcfg.clk_rate = cmd->clkrate;
1661 rotcfg.data_bw = cmd->data_bw;
Alan Kwong6bc64622017-02-04 17:36:03 -08001662 rotcfg.session_id = ctx->session_id;
1663 rotcfg.input.width = cmd->src_rect_w;
1664 rotcfg.input.height = cmd->src_rect_h;
1665 rotcfg.input.format = cmd->src_pixfmt;
1666 rotcfg.input.comp_ratio.numer = 1;
1667 rotcfg.input.comp_ratio.denom = 1;
1668 rotcfg.output.width = cmd->dst_rect_w;
1669 rotcfg.output.height = cmd->dst_rect_h;
1670 rotcfg.output.format = cmd->dst_pixfmt;
1671 rotcfg.output.comp_ratio.numer = 1;
1672 rotcfg.output.comp_ratio.denom = 1;
1673 rotcfg.output.sbuf = true;
Alan Kwong871fc482017-09-20 11:17:28 -04001674 }
Alan Kwong6bc64622017-02-04 17:36:03 -08001675
Alan Kwong871fc482017-09-20 11:17:28 -04001676 if (cmd_type == SDE_ROTATOR_INLINE_CMD_VALIDATE) {
Alan Kwong6bc64622017-02-04 17:36:03 -08001677
Alan Kwong871fc482017-09-20 11:17:28 -04001678 ret = sde_rotator_session_validate(rot_dev->mgr,
1679 ctx->private, &rotcfg);
Alan Kwong6bc64622017-02-04 17:36:03 -08001680 if (ret) {
Alan Kwong871fc482017-09-20 11:17:28 -04001681 SDEROT_WARN("fail session validation s:%d\n",
Alan Kwong6bc64622017-02-04 17:36:03 -08001682 ctx->session_id);
Alan Kwong871fc482017-09-20 11:17:28 -04001683 goto error_session_validate;
Alan Kwong6bc64622017-02-04 17:36:03 -08001684 }
1685
1686 devm_kfree(rot_dev->dev, req);
1687 req = NULL;
1688
1689 } else if (cmd_type == SDE_ROTATOR_INLINE_CMD_COMMIT) {
1690
Alan Kwong871fc482017-09-20 11:17:28 -04001691 if (memcmp(&rotcfg, &ctx->rotcfg, sizeof(rotcfg))) {
1692 ret = sde_rotator_session_config(rot_dev->mgr,
1693 ctx->private, &rotcfg);
1694 if (ret) {
1695 SDEROT_ERR("fail session config s:%d\n",
1696 ctx->session_id);
1697 goto error_session_config;
1698 }
1699
1700 ctx->rotcfg = rotcfg;
1701 }
1702
Alan Kwong6bc64622017-02-04 17:36:03 -08001703 request = list_first_entry_or_null(&ctx->retired_list,
1704 struct sde_rotator_request, list);
1705 if (!request) {
1706 /* should not happen */
1707 ret = -ENOMEM;
1708 SDEROT_ERR("no free request s:%d\n", ctx->session_id);
1709 goto error_retired_list;
1710 }
1711
1712 request->req = req;
Alan Kwong3ddf48c2017-10-06 10:45:41 -04001713 request->sequence_id = req->entries[0].item.sequence_id;
Alan Kwong6bc64622017-02-04 17:36:03 -08001714
1715 spin_lock(&ctx->list_lock);
1716 list_del_init(&request->list);
1717 list_add_tail(&request->list, &ctx->pending_list);
1718 spin_unlock(&ctx->list_lock);
1719
1720 ts = req->entries[0].item.ts;
1721 if (ts) {
1722 ts[SDE_ROTATOR_TS_SRCQB] = ktime_get();
1723 ts[SDE_ROTATOR_TS_DSTQB] = ktime_get();
1724 ts[SDE_ROTATOR_TS_FENCE] = ktime_get();
1725 } else {
1726 SDEROT_ERR("invalid stats timestamp\n");
1727 }
Benjamin Chanf8d9a462016-11-08 21:38:10 -05001728 req->retire_kw = &ctx->work_queue.rot_kw;
Alan Kwong6bc64622017-02-04 17:36:03 -08001729 req->retire_work = &request->retire_work;
1730
1731 trace_rot_entry_fence(
1732 ctx->session_id, cmd->sequence_id,
1733 req->entries[0].item.wb_idx,
1734 req->entries[0].item.flags,
1735 req->entries[0].item.input.format,
1736 req->entries[0].item.input.width,
1737 req->entries[0].item.input.height,
1738 req->entries[0].item.src_rect.x,
1739 req->entries[0].item.src_rect.y,
1740 req->entries[0].item.src_rect.w,
1741 req->entries[0].item.src_rect.h,
1742 req->entries[0].item.output.format,
1743 req->entries[0].item.output.width,
1744 req->entries[0].item.output.height,
1745 req->entries[0].item.dst_rect.x,
1746 req->entries[0].item.dst_rect.y,
1747 req->entries[0].item.dst_rect.w,
1748 req->entries[0].item.dst_rect.h);
1749
1750 ret = sde_rotator_handle_request_common(
1751 rot_dev->mgr, ctx->private, req);
1752 if (ret) {
1753 SDEROT_ERR("fail handle request s:%d\n",
1754 ctx->session_id);
1755 goto error_handle_request;
1756 }
1757
Clarence Ip3ce07c02017-08-11 16:21:45 -04001758 sde_rotator_req_reset_start(rot_dev->mgr, req);
Clarence Ip618de0a2017-05-17 12:10:47 -04001759
Clarence Ip3ce07c02017-08-11 16:21:45 -04001760 sde_rotator_queue_request(rot_dev->mgr, ctx->private, req);
Alan Kwong6bc64622017-02-04 17:36:03 -08001761
1762 request->committed = true;
1763
1764 /* save request in private handle */
1765 cmd->priv_handle = request;
1766
Clarence Ipb25c65c2017-05-17 12:09:23 -04001767 } else if (cmd_type == SDE_ROTATOR_INLINE_CMD_START) {
1768 if (!cmd->priv_handle) {
1769 ret = -EINVAL;
1770 SDEROT_ERR("invalid private handle\n");
1771 goto error_invalid_handle;
1772 }
1773
1774 request = cmd->priv_handle;
Clarence Ip3ce07c02017-08-11 16:21:45 -04001775 sde_rotator_req_set_start(rot_dev->mgr, request->req);
Alan Kwong6bc64622017-02-04 17:36:03 -08001776 } else if (cmd_type == SDE_ROTATOR_INLINE_CMD_CLEANUP) {
1777 if (!cmd->priv_handle) {
1778 ret = -EINVAL;
1779 SDEROT_ERR("invalid private handle\n");
1780 goto error_invalid_handle;
1781 }
1782
1783 request = cmd->priv_handle;
Alan Kwong6bc64622017-02-04 17:36:03 -08001784
Clarence Ipd59419e2017-11-15 16:42:45 -05001785 /* attempt single retry if first cleanup attempt failed */
1786 if (_sde_rotator_inline_cleanup(handle, request) == -EAGAIN)
1787 _sde_rotator_inline_cleanup(handle, request);
Alan Kwong6bc64622017-02-04 17:36:03 -08001788
Clarence Ip34079002017-11-09 16:15:33 -05001789 cmd->priv_handle = NULL;
Clarence Ip19339b32017-10-14 20:59:00 -04001790 } else if (cmd_type == SDE_ROTATOR_INLINE_CMD_ABORT) {
1791 if (!cmd->priv_handle) {
1792 ret = -EINVAL;
1793 SDEROT_ERR("invalid private handle\n");
1794 goto error_invalid_handle;
1795 }
1796
1797 request = cmd->priv_handle;
Clarence Ip34079002017-11-09 16:15:33 -05001798 if (!sde_rotator_is_request_retired(request))
1799 sde_rotator_abort_inline_request(rot_dev->mgr,
1800 ctx->private, request->req);
Alan Kwong6bc64622017-02-04 17:36:03 -08001801 }
1802
1803 sde_rot_mgr_unlock(rot_dev->mgr);
Clarence Ipd59419e2017-11-15 16:42:45 -05001804 mutex_unlock(&rot_dev->lock);
Alan Kwong6bc64622017-02-04 17:36:03 -08001805 return 0;
1806
1807error_handle_request:
1808 sde_rotator_update_retire_sequence(request);
1809 sde_rotator_retire_request(request);
1810error_retired_list:
Alan Kwong871fc482017-09-20 11:17:28 -04001811error_session_validate:
Alan Kwong6bc64622017-02-04 17:36:03 -08001812error_session_config:
1813 devm_kfree(rot_dev->dev, req);
1814error_invalid_handle:
1815error_init_request:
1816 sde_rot_mgr_unlock(rot_dev->mgr);
Clarence Ipd59419e2017-11-15 16:42:45 -05001817 mutex_unlock(&rot_dev->lock);
Alan Kwong6bc64622017-02-04 17:36:03 -08001818 return ret;
1819}
1820EXPORT_SYMBOL(sde_rotator_inline_commit);
1821
Alan Kwongde85fcd2017-07-31 18:18:49 -04001822void sde_rotator_inline_reg_dump(struct platform_device *pdev)
1823{
Clarence Ipcd140292017-09-22 16:24:08 -04001824 struct sde_rotator_device *rot_dev;
1825
1826 if (!pdev) {
1827 SDEROT_ERR("invalid platform device\n");
1828 return;
1829 }
1830
1831 rot_dev = (struct sde_rotator_device *) platform_get_drvdata(pdev);
1832 if (!rot_dev || !rot_dev->mgr) {
1833 SDEROT_ERR("invalid rotator device\n");
1834 return;
1835 }
1836
1837 sde_rot_mgr_lock(rot_dev->mgr);
1838 sde_rotator_core_dump(rot_dev->mgr);
1839 sde_rot_mgr_unlock(rot_dev->mgr);
Alan Kwongde85fcd2017-07-31 18:18:49 -04001840}
1841EXPORT_SYMBOL(sde_rotator_inline_reg_dump);
1842
Alan Kwong6bc64622017-02-04 17:36:03 -08001843/*
1844 * sde_rotator_open - Rotator device open method.
1845 * @file: Pointer to file struct.
1846 */
1847static int sde_rotator_open(struct file *file)
1848{
1849 struct sde_rotator_device *rot_dev = video_drvdata(file);
1850 struct sde_rotator_ctx *ctx;
1851 int ret = 0;
1852
1853 ctx = sde_rotator_ctx_open(rot_dev, file);
1854 if (IS_ERR_OR_NULL(ctx)) {
1855 SDEDEV_DBG(rot_dev->dev, "failed to open %d\n", ret);
1856 ret = PTR_ERR(ctx);
1857 }
1858
1859 return ret;
1860}
1861
1862/*
1863 * sde_rotator_release - Rotator device release method.
1864 * @file: Pointer to file struct.
1865 */
1866static int sde_rotator_release(struct file *file)
1867{
1868 struct sde_rotator_ctx *ctx =
1869 sde_rotator_ctx_from_fh(file->private_data);
1870
1871 return sde_rotator_ctx_release(ctx, file);
1872}
1873
1874/*
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001875 * sde_rotator_poll - rotator device pool method.
1876 * @file: Pointer to file struct.
1877 * @wait: Pointer to poll table struct.
1878 */
1879static unsigned int sde_rotator_poll(struct file *file,
1880 struct poll_table_struct *wait)
1881{
1882 struct sde_rotator_device *rot_dev = video_drvdata(file);
1883 struct sde_rotator_ctx *ctx =
1884 sde_rotator_ctx_from_fh(file->private_data);
1885 int ret;
1886
1887 mutex_lock(&rot_dev->lock);
Alan Kwong3428f672016-04-18 12:32:06 -04001888 ret = v4l2_m2m_poll(file, ctx->fh.m2m_ctx, wait);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001889 mutex_unlock(&rot_dev->lock);
1890 return ret;
1891}
1892
1893/* rotator device file operations callbacks */
1894static const struct v4l2_file_operations sde_rotator_fops = {
1895 .owner = THIS_MODULE,
1896 .open = sde_rotator_open,
1897 .release = sde_rotator_release,
1898 .poll = sde_rotator_poll,
1899 .unlocked_ioctl = video_ioctl2,
1900#ifdef CONFIG_COMPAT
1901 .compat_ioctl32 = sde_rotator_compat_ioctl32,
1902#endif
1903};
1904
1905/*
1906 * sde_rotator_querycap - V4l2 ioctl query capability handler.
1907 * @file: Pointer to file struct.
1908 * @fh: V4l2 File handle.
1909 * @cap: Pointer to v4l2_capability struct need to be filled.
1910 */
1911static int sde_rotator_querycap(struct file *file,
1912 void *fh, struct v4l2_capability *cap)
1913{
1914 cap->bus_info[0] = 0;
1915 strlcpy(cap->driver, SDE_ROTATOR_DRV_NAME, sizeof(cap->driver));
1916 strlcpy(cap->card, SDE_ROTATOR_DRV_NAME, sizeof(cap->card));
Alan Kwong3428f672016-04-18 12:32:06 -04001917 cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M |
1918 V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_CAPTURE;
1919 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001920
1921 return 0;
1922}
1923
1924/*
1925 * sde_rotator_enum_fmt_vid_cap - V4l2 ioctl enumerate output format handler.
1926 * @file: Pointer to file struct.
1927 * @fh: V4l2 File handle.
1928 * @f: Pointer to v4l2_fmtdesc struct need to be filled.
1929 */
1930static int sde_rotator_enum_fmt_vid_cap(struct file *file,
1931 void *fh, struct v4l2_fmtdesc *f)
1932{
Alan Kwongda16e442016-08-14 20:47:18 -04001933 struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh);
1934 struct sde_rotator_device *rot_dev = ctx->rot_dev;
1935 struct sde_mdp_format_params *fmt;
Alan Kwong2c7cc252016-12-28 12:21:00 -08001936 u32 i, index, pixfmt;
1937 bool found = false;
Alan Kwongda16e442016-08-14 20:47:18 -04001938
Alan Kwong2c7cc252016-12-28 12:21:00 -08001939 for (i = 0, index = 0; index <= f->index; i++) {
Alan Kwong4b416162017-08-11 21:03:10 -04001940 pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, false,
1941 SDE_ROTATOR_MODE_OFFLINE);
Alan Kwong2c7cc252016-12-28 12:21:00 -08001942 if (!pixfmt)
1943 return -EINVAL;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001944
Alan Kwong2c7cc252016-12-28 12:21:00 -08001945 fmt = sde_get_format_params(pixfmt);
1946 if (!fmt)
1947 return -EINVAL;
1948
1949 if (sde_mdp_is_private_format(fmt))
1950 continue;
1951
1952 if (index == f->index) {
1953 found = true;
1954 break;
1955 }
1956
1957 index++;
1958 }
1959
1960 if (!found)
Alan Kwongda16e442016-08-14 20:47:18 -04001961 return -EINVAL;
1962
1963 f->pixelformat = pixfmt;
1964 strlcpy(f->description, fmt->description, sizeof(f->description));
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001965
1966 return 0;
1967}
1968
1969/*
1970 * sde_rotator_enum_fmt_vid_out - V4l2 ioctl enumerate capture format handler.
1971 * @file: Pointer to file struct.
1972 * @fh: V4l2 File handle.
1973 * @f: Pointer to v4l2_fmtdesc struct need to be filled.
1974 */
1975static int sde_rotator_enum_fmt_vid_out(struct file *file,
1976 void *fh, struct v4l2_fmtdesc *f)
1977{
Alan Kwongda16e442016-08-14 20:47:18 -04001978 struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh);
1979 struct sde_rotator_device *rot_dev = ctx->rot_dev;
1980 struct sde_mdp_format_params *fmt;
Alan Kwong2c7cc252016-12-28 12:21:00 -08001981 u32 i, index, pixfmt;
1982 bool found = false;
Alan Kwongda16e442016-08-14 20:47:18 -04001983
Alan Kwong2c7cc252016-12-28 12:21:00 -08001984 for (i = 0, index = 0; index <= f->index; i++) {
Alan Kwong4b416162017-08-11 21:03:10 -04001985 pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, true,
1986 SDE_ROTATOR_MODE_OFFLINE);
Alan Kwong2c7cc252016-12-28 12:21:00 -08001987 if (!pixfmt)
1988 return -EINVAL;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001989
Alan Kwong2c7cc252016-12-28 12:21:00 -08001990 fmt = sde_get_format_params(pixfmt);
1991 if (!fmt)
1992 return -EINVAL;
1993
1994 if (sde_mdp_is_private_format(fmt))
1995 continue;
1996
1997 if (index == f->index) {
1998 found = true;
1999 break;
2000 }
2001
2002 index++;
2003 }
2004
2005 if (!found)
Alan Kwongda16e442016-08-14 20:47:18 -04002006 return -EINVAL;
2007
2008 f->pixelformat = pixfmt;
2009 strlcpy(f->description, fmt->description, sizeof(f->description));
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002010
2011 return 0;
2012}
2013
2014/*
2015 * sde_rotator_g_fmt_cap - V4l2 ioctl get capture format handler.
2016 * @file: Pointer to file struct.
2017 * @fh: V4l2 File handle.
2018 * @f: Pointer to v4l2_format struct need to be filled.
2019 */
2020static int sde_rotator_g_fmt_cap(struct file *file, void *fh,
2021 struct v4l2_format *f)
2022{
2023 struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh);
2024
2025 *f = ctx->format_cap;
2026
2027 return 0;
2028}
2029
2030/*
2031 * sde_rotator_g_fmt_out - V4l2 ioctl get output format handler.
2032 * @file: Pointer to file struct.
2033 * @fh: V4l2 File handle.
2034 * @f: Pointer to v4l2_format struct need to be filled.
2035 */
2036static int sde_rotator_g_fmt_out(struct file *file, void *fh,
2037 struct v4l2_format *f)
2038{
2039 struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh);
2040
2041 *f = ctx->format_out;
2042
2043 return 0;
2044}
2045
2046/*
2047 * sde_rotator_try_fmt_vid_cap - V4l2 ioctl try capture format handler.
2048 * @file: Pointer to file struct.
2049 * @fh: V4l2 File handle.
2050 * @f: Pointer to v4l2_format struct.
2051 */
2052static int sde_rotator_try_fmt_vid_cap(struct file *file,
2053 void *fh, struct v4l2_format *f)
2054{
2055 struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh);
2056 struct sde_rotator_device *rot_dev = ctx->rot_dev;
2057 struct sde_rotation_config config;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002058 int ret;
2059
Benjamin Chanb1be8db2016-10-06 17:36:48 -04002060 if ((f->fmt.pix.width == 0) || (f->fmt.pix.height == 0)) {
2061 SDEDEV_WARN(ctx->rot_dev->dev,
2062 "Not supporting 0 width/height: %dx%d\n",
2063 f->fmt.pix.width, f->fmt.pix.height);
2064 return -EINVAL;
2065 }
2066
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002067 sde_rot_mgr_lock(rot_dev->mgr);
2068 sde_rotator_get_config_from_ctx(ctx, &config);
2069 config.output.format = f->fmt.pix.pixelformat;
2070 config.output.width = f->fmt.pix.width;
2071 config.output.height = f->fmt.pix.height;
Benjamin Chan59a06052017-01-12 18:06:03 -05002072 config.flags |= SDE_ROTATION_VERIFY_INPUT_ONLY;
2073 ret = sde_rotator_verify_config_output(rot_dev->mgr, &config);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002074 sde_rot_mgr_unlock(rot_dev->mgr);
2075 if (ret) {
2076 if ((config.output.width == f->fmt.pix.width) &&
2077 (config.output.height == f->fmt.pix.height)) {
2078 SDEDEV_WARN(ctx->rot_dev->dev,
2079 "invalid capture format 0x%8.8x %dx%d\n",
2080 f->fmt.pix.pixelformat,
2081 f->fmt.pix.width,
2082 f->fmt.pix.height);
2083 return -EINVAL;
2084 }
2085 f->fmt.pix.width = config.output.width;
2086 f->fmt.pix.height = config.output.height;
2087 }
2088
2089 sde_rotator_format_recalc(f);
Benjamin Chan59a06052017-01-12 18:06:03 -05002090 return ret;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002091}
2092
2093/*
2094 * sde_rotator_try_fmt_vid_out - V4l2 ioctl try output format handler.
2095 * @file: Pointer to file struct.
2096 * @fh: V4l2 File handle.
2097 * @f: Pointer to v4l2_format struct.
2098 */
2099static int sde_rotator_try_fmt_vid_out(struct file *file,
2100 void *fh, struct v4l2_format *f)
2101{
2102 struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh);
2103 struct sde_rotator_device *rot_dev = ctx->rot_dev;
2104 struct sde_rotation_config config;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002105 int ret;
2106
Benjamin Chanb1be8db2016-10-06 17:36:48 -04002107 if ((f->fmt.pix.width == 0) || (f->fmt.pix.height == 0)) {
2108 SDEDEV_WARN(ctx->rot_dev->dev,
2109 "Not supporting 0 width/height: %dx%d\n",
2110 f->fmt.pix.width, f->fmt.pix.height);
2111 return -EINVAL;
2112 }
2113
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002114 sde_rot_mgr_lock(rot_dev->mgr);
2115 sde_rotator_get_config_from_ctx(ctx, &config);
2116 config.input.format = f->fmt.pix.pixelformat;
2117 config.input.width = f->fmt.pix.width;
2118 config.input.height = f->fmt.pix.height;
2119 config.flags |= SDE_ROTATION_VERIFY_INPUT_ONLY;
Benjamin Chan59a06052017-01-12 18:06:03 -05002120 ret = sde_rotator_verify_config_input(rot_dev->mgr, &config);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002121 sde_rot_mgr_unlock(rot_dev->mgr);
2122 if (ret) {
2123 if ((config.input.width == f->fmt.pix.width) &&
2124 (config.input.height == f->fmt.pix.height)) {
2125 SDEDEV_WARN(ctx->rot_dev->dev,
2126 "invalid output format 0x%8.8x %dx%d\n",
2127 f->fmt.pix.pixelformat,
2128 f->fmt.pix.width,
2129 f->fmt.pix.height);
2130 return -EINVAL;
2131 }
2132 f->fmt.pix.width = config.input.width;
2133 f->fmt.pix.height = config.input.height;
2134 }
2135
2136 sde_rotator_format_recalc(f);
Benjamin Chan59a06052017-01-12 18:06:03 -05002137 return ret;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002138}
2139
2140/*
2141 * sde_rotator_s_fmt_vid_cap - V4l2 ioctl set capture format handler.
2142 * @file: Pointer to file struct.
2143 * @fh: V4l2 File handle.
2144 * @f: Pointer to v4l2_format struct.
2145 */
2146static int sde_rotator_s_fmt_vid_cap(struct file *file,
2147 void *fh, struct v4l2_format *f)
2148{
2149 struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh);
2150 struct sde_rotator_device *rot_dev = ctx->rot_dev;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002151 int ret;
2152
2153 ret = sde_rotator_try_fmt_vid_cap(file, fh, f);
2154 if (ret)
2155 return -EINVAL;
2156
2157 /* Initialize crop */
2158 ctx->crop_cap.top = 0;
2159 ctx->crop_cap.left = 0;
2160 ctx->crop_cap.width = f->fmt.pix.width;
2161 ctx->crop_cap.height = f->fmt.pix.height;
2162
2163 ctx->format_cap = *f;
2164
2165 SDEDEV_DBG(rot_dev->dev,
2166 "s_fmt s:%d t:%d fmt:0x%8.8x field:%u (%u,%u)\n",
2167 ctx->session_id, f->type,
2168 f->fmt.pix.pixelformat,
2169 f->fmt.pix.field,
2170 f->fmt.pix.width, f->fmt.pix.height);
2171
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002172 return 0;
2173}
2174
2175/*
2176 * sde_rotator_s_fmt_vid_out - V4l2 ioctl set output format handler.
2177 * @file: Pointer to file struct.
2178 * @fh: V4l2 File handle.
2179 * @f: Pointer to v4l2_format struct.
2180 */
2181static int sde_rotator_s_fmt_vid_out(struct file *file,
2182 void *fh, struct v4l2_format *f)
2183{
2184 struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh);
2185 struct sde_rotator_device *rot_dev = ctx->rot_dev;
2186 int ret;
2187
2188 ret = sde_rotator_try_fmt_vid_out(file, fh, f);
2189 if (ret)
2190 return -EINVAL;
2191
2192 /* Initialize crop */
2193 ctx->crop_out.top = 0;
2194 ctx->crop_out.left = 0;
2195 ctx->crop_out.width = f->fmt.pix.width;
2196 ctx->crop_out.height = f->fmt.pix.height;
2197
2198 ctx->format_out = *f;
2199
2200 SDEDEV_DBG(rot_dev->dev,
2201 "s_fmt s:%d t:%d fmt:0x%8.8x field:%u (%u,%u)\n",
2202 ctx->session_id, f->type,
2203 f->fmt.pix.pixelformat,
2204 f->fmt.pix.field,
2205 f->fmt.pix.width, f->fmt.pix.height);
2206
2207 return 0;
2208}
2209
2210/*
2211 * sde_rotator_reqbufs - V4l2 ioctl request buffers handler.
2212 * @file: Pointer to file struct.
2213 * @fh: V4l2 File handle.
2214 * @req: Pointer to v4l2_requestbuffer struct.
2215 */
2216static int sde_rotator_reqbufs(struct file *file,
2217 void *fh, struct v4l2_requestbuffers *req)
2218{
2219 struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh);
2220
Alan Kwong3428f672016-04-18 12:32:06 -04002221 return v4l2_m2m_reqbufs(file, ctx->fh.m2m_ctx, req);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002222}
2223
2224/*
2225 * sde_rotator_qbuf - V4l2 ioctl queue buffer handler.
2226 * @file: Pointer to file struct.
2227 * @fh: V4l2 File handle.
2228 * @buf: Pointer to v4l2_buffer struct.
2229 */
2230static int sde_rotator_qbuf(struct file *file, void *fh,
2231 struct v4l2_buffer *buf)
2232{
2233 struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh);
2234 int ret;
2235
2236 /* create fence for capture buffer */
2237 if ((buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
2238 && (buf->index < ctx->nbuf_cap)) {
2239 int idx = buf->index;
2240
2241 ctx->vbinfo_cap[idx].fd = -1;
2242 ctx->vbinfo_cap[idx].fence = sde_rotator_get_sync_fence(
2243 ctx->work_queue.timeline, NULL,
2244 &ctx->vbinfo_cap[idx].fence_ts);
2245 ctx->vbinfo_cap[idx].qbuf_ts = ktime_get();
2246 ctx->vbinfo_cap[idx].dqbuf_ts = NULL;
2247 SDEDEV_DBG(ctx->rot_dev->dev,
2248 "create buffer fence s:%d.%u i:%d f:%p\n",
2249 ctx->session_id,
2250 ctx->vbinfo_cap[idx].fence_ts,
2251 idx,
2252 ctx->vbinfo_cap[idx].fence);
2253 } else if ((buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
2254 && (buf->index < ctx->nbuf_out)) {
2255 int idx = buf->index;
2256
2257 ctx->vbinfo_out[idx].qbuf_ts = ktime_get();
2258 ctx->vbinfo_out[idx].dqbuf_ts = NULL;
2259 }
2260
Alan Kwong3428f672016-04-18 12:32:06 -04002261 ret = v4l2_m2m_qbuf(file, ctx->fh.m2m_ctx, buf);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002262 if (ret < 0)
2263 SDEDEV_ERR(ctx->rot_dev->dev, "fail qbuf s:%d t:%d r:%d\n",
2264 ctx->session_id, buf->type, ret);
Benjamin Chanfa082372017-09-19 17:19:28 -04002265 SDEROT_EVTLOG(buf->type, buf->bytesused, buf->length, buf->m.fd, ret);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002266
2267 return ret;
2268}
2269
2270/*
2271 * sde_rotator_dqbuf - V4l2 ioctl dequeue buffer handler.
2272 * @file: Pointer to file struct.
2273 * @fh: V4l2 File handle.
2274 * @buf: Pointer to v4l2_buffer struct.
2275 */
2276static int sde_rotator_dqbuf(struct file *file,
2277 void *fh, struct v4l2_buffer *buf)
2278{
2279 struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh);
2280 int ret;
2281
Alan Kwong3428f672016-04-18 12:32:06 -04002282 ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002283
2284 if (ret) {
2285 SDEDEV_ERR(ctx->rot_dev->dev,
2286 "fail dqbuf s:%d t:%d i:%d r:%d\n",
2287 ctx->session_id, buf->type, buf->index, ret);
2288 return ret;
2289 }
2290
2291 /* clear fence for buffer */
2292 if ((buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
2293 && (buf->index < ctx->nbuf_cap)) {
2294 int idx = buf->index;
2295
Benjamin Chan834d21d2017-06-15 18:18:54 -04002296 if (ctx->vbinfo_cap[idx].fence) {
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002297 /* fence is not used */
2298 SDEDEV_DBG(ctx->rot_dev->dev, "put fence s:%d i:%d\n",
2299 ctx->session_id, idx);
2300 sde_rotator_put_sync_fence(ctx->vbinfo_cap[idx].fence);
2301 }
2302 ctx->vbinfo_cap[idx].fence = NULL;
2303 ctx->vbinfo_cap[idx].fd = -1;
2304 if (ctx->vbinfo_cap[idx].dqbuf_ts)
2305 *(ctx->vbinfo_cap[idx].dqbuf_ts) = ktime_get();
2306 } else if ((buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
2307 && (buf->index < ctx->nbuf_out)) {
2308 int idx = buf->index;
2309
2310 ctx->vbinfo_out[idx].fence = NULL;
2311 ctx->vbinfo_out[idx].fd = -1;
2312 if (ctx->vbinfo_out[idx].dqbuf_ts)
2313 *(ctx->vbinfo_out[idx].dqbuf_ts) = ktime_get();
2314 } else {
2315 SDEDEV_WARN(ctx->rot_dev->dev, "invalid dq s:%d t:%d i:%d\n",
2316 ctx->session_id, buf->type, buf->index);
2317 }
2318
2319 return 0;
2320}
2321
2322/*
2323 * sde_rotator_querybuf - V4l2 ioctl query buffer handler.
2324 * @file: Pointer to file struct.
2325 * @fh: V4l2 File handle.
2326 * @buf: Pointer to v4l2_buffer struct.
2327 */
2328static int sde_rotator_querybuf(struct file *file,
2329 void *fh, struct v4l2_buffer *buf)
2330{
2331 struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh);
2332
Alan Kwong3428f672016-04-18 12:32:06 -04002333 return v4l2_m2m_querybuf(file, ctx->fh.m2m_ctx, buf);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002334}
2335
2336/*
2337 * sde_rotator_streamon - V4l2 ioctl stream on handler.
2338 * @file: Pointer to file struct.
2339 * @fh: V4l2 File handle.
2340 * @buf_type: V4l2 buffer type.
2341 */
2342static int sde_rotator_streamon(struct file *file,
2343 void *fh, enum v4l2_buf_type buf_type)
2344{
2345 struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh);
Alan Kwong360f01b2016-12-22 08:34:43 -08002346 struct sde_rotator_device *rot_dev = ctx->rot_dev;
2347 struct sde_rotation_config config;
2348 struct vb2_queue *vq;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002349 int ret;
2350
2351 SDEDEV_DBG(ctx->rot_dev->dev, "stream on s:%d t:%d\n",
2352 ctx->session_id, buf_type);
2353
Alan Kwong360f01b2016-12-22 08:34:43 -08002354 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
2355 buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT ?
2356 V4L2_BUF_TYPE_VIDEO_CAPTURE :
2357 V4L2_BUF_TYPE_VIDEO_OUTPUT);
2358
2359 if (!vq) {
2360 SDEDEV_ERR(ctx->rot_dev->dev, "fail to get vq on s:%d t:%d\n",
2361 ctx->session_id, buf_type);
2362 return -EINVAL;
2363 }
2364
2365 if (vb2_is_streaming(vq)) {
2366 sde_rot_mgr_lock(rot_dev->mgr);
2367 sde_rotator_get_config_from_ctx(ctx, &config);
Benjamin Chan59a06052017-01-12 18:06:03 -05002368 config.flags &= ~SDE_ROTATION_VERIFY_INPUT_ONLY;
Alan Kwong360f01b2016-12-22 08:34:43 -08002369 ret = sde_rotator_session_config(rot_dev->mgr, ctx->private,
2370 &config);
2371 sde_rot_mgr_unlock(rot_dev->mgr);
2372 if (ret < 0) {
2373 SDEDEV_ERR(rot_dev->dev,
2374 "fail config in stream on s:%d t:%d r:%d\n",
2375 ctx->session_id, buf_type, ret);
2376 return ret;
2377 }
Alan Kwong6bc64622017-02-04 17:36:03 -08002378 ctx->rotcfg = config;
Alan Kwong360f01b2016-12-22 08:34:43 -08002379 }
2380
Alan Kwong3428f672016-04-18 12:32:06 -04002381 ret = v4l2_m2m_streamon(file, ctx->fh.m2m_ctx, buf_type);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002382 if (ret < 0)
2383 SDEDEV_ERR(ctx->rot_dev->dev, "fail stream on s:%d t:%d\n",
2384 ctx->session_id, buf_type);
2385
2386 return ret;
2387}
2388
2389/*
2390 * sde_rotator_streamoff - V4l2 ioctl stream off handler.
2391 * @file: Pointer to file struct.
2392 * @fh: V4l2 File handle.
2393 * @buf_type: V4l2 buffer type.
2394 */
2395static int sde_rotator_streamoff(struct file *file,
2396 void *fh, enum v4l2_buf_type buf_type)
2397{
2398 struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh);
2399 int ret;
2400
2401 SDEDEV_DBG(ctx->rot_dev->dev, "stream off s:%d t:%d\n",
2402 ctx->session_id, buf_type);
2403
Alan Kwong3428f672016-04-18 12:32:06 -04002404 ret = v4l2_m2m_streamoff(file, ctx->fh.m2m_ctx, buf_type);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002405 if (ret < 0)
2406 SDEDEV_ERR(ctx->rot_dev->dev, "fail stream off s:%d t:%d\n",
2407 ctx->session_id, buf_type);
2408
2409 return ret;
2410}
2411
2412/*
2413 * sde_rotator_cropcap - V4l2 ioctl crop capabilities.
2414 * @file: Pointer to file struct.
2415 * @fh: V4l2 File handle.
2416 * @a: Pointer to v4l2_cropcap struct need to be set.
2417 */
2418static int sde_rotator_cropcap(struct file *file, void *fh,
2419 struct v4l2_cropcap *a)
2420{
2421 struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh);
2422 struct v4l2_format *format;
2423 struct v4l2_rect *crop;
2424
2425 switch (a->type) {
2426 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
2427 format = &ctx->format_out;
2428 crop = &ctx->crop_out;
2429 break;
2430 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2431 format = &ctx->format_cap;
2432 crop = &ctx->crop_cap;
2433 break;
2434 default:
2435 return -EINVAL;
2436 }
2437
2438 a->bounds.top = 0;
2439 a->bounds.left = 0;
2440 a->bounds.width = format->fmt.pix.width;
2441 a->bounds.height = format->fmt.pix.height;
2442
2443 a->defrect = *crop;
2444
2445 a->pixelaspect.numerator = 1;
2446 a->pixelaspect.denominator = 1;
2447
Benjamin Chanfa082372017-09-19 17:19:28 -04002448 SDEROT_EVTLOG(format->fmt.pix.width, format->fmt.pix.height, a->type);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002449 return 0;
2450}
2451
2452/*
2453 * sde_rotator_g_crop - V4l2 ioctl get crop.
2454 * @file: Pointer to file struct.
2455 * @fh: V4l2 File handle.
2456 * @crop: Pointer to v4l2_crop struct need to be set.
2457 */
2458static int sde_rotator_g_crop(struct file *file, void *fh,
2459 struct v4l2_crop *crop)
2460{
2461 struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh);
2462
2463 switch (crop->type) {
2464 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
2465 crop->c = ctx->crop_out;
2466 break;
2467 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2468 crop->c = ctx->crop_cap;
2469 break;
2470 default:
2471 return -EINVAL;
2472 }
2473 return 0;
2474}
2475
2476/*
2477 * sde_rotator_s_crop - V4l2 ioctl set crop.
2478 * @file: Pointer to file struct.
2479 * @fh: V4l2 File handle.
2480 * @crop: Pointer to v4l2_crop struct need to be set.
2481 */
2482static int sde_rotator_s_crop(struct file *file, void *fh,
2483 const struct v4l2_crop *crop)
2484{
2485 struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh);
2486 struct sde_rotator_device *rot_dev = ctx->rot_dev;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002487 struct sde_rotation_item item;
2488 struct v4l2_rect rect;
2489
2490 sde_rotator_get_item_from_ctx(ctx, &item);
2491
2492 rect.left = max_t(__u32, crop->c.left, 0);
2493 rect.top = max_t(__u32, crop->c.top, 0);
2494 rect.height = max_t(__u32, crop->c.height, 0);
2495 rect.width = max_t(__u32, crop->c.width, 0);
2496
2497 if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
2498 rect.left = min_t(__u32, rect.left,
2499 ctx->format_out.fmt.pix.width - 1);
2500 rect.top = min_t(__u32, rect.top,
2501 ctx->format_out.fmt.pix.height - 1);
2502 rect.width = min_t(__u32, rect.width,
2503 (ctx->format_out.fmt.pix.width - rect.left));
2504 rect.height = min_t(__u32, rect.height,
2505 (ctx->format_out.fmt.pix.height - rect.top));
2506
2507 item.src_rect.x = rect.left;
2508 item.src_rect.y = rect.top;
2509 item.src_rect.w = rect.width;
2510 item.src_rect.h = rect.height;
2511
2512 sde_rotator_validate_item(ctx, &item);
2513
2514 SDEDEV_DBG(rot_dev->dev,
2515 "s_crop s:%d t:%d (%u,%u,%u,%u)->(%u,%u,%u,%u)\n",
2516 ctx->session_id, crop->type,
2517 crop->c.left, crop->c.top,
2518 crop->c.width, crop->c.height,
2519 item.src_rect.x, item.src_rect.y,
2520 item.src_rect.w, item.src_rect.h);
2521
2522 ctx->crop_out.left = item.src_rect.x;
2523 ctx->crop_out.top = item.src_rect.y;
2524 ctx->crop_out.width = item.src_rect.w;
2525 ctx->crop_out.height = item.src_rect.h;
2526 } else if (crop->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
2527 rect.left = min_t(__u32, rect.left,
2528 ctx->format_cap.fmt.pix.width - 1);
2529 rect.top = min_t(__u32, rect.top,
2530 ctx->format_cap.fmt.pix.height - 1);
2531 rect.width = min_t(__u32, rect.width,
2532 (ctx->format_cap.fmt.pix.width - rect.left));
2533 rect.height = min_t(__u32, rect.height,
2534 (ctx->format_cap.fmt.pix.height - rect.top));
2535
2536 item.dst_rect.x = rect.left;
2537 item.dst_rect.y = rect.top;
2538 item.dst_rect.w = rect.width;
2539 item.dst_rect.h = rect.height;
2540
2541 sde_rotator_validate_item(ctx, &item);
2542
2543 SDEDEV_DBG(rot_dev->dev,
2544 "s_crop s:%d t:%d (%u,%u,%u,%u)->(%u,%u,%u,%u)\n",
2545 ctx->session_id, crop->type,
2546 crop->c.left, crop->c.top,
2547 crop->c.width, crop->c.height,
2548 item.dst_rect.x, item.dst_rect.y,
2549 item.dst_rect.w, item.dst_rect.h);
2550
2551 ctx->crop_cap.left = item.dst_rect.x;
2552 ctx->crop_cap.top = item.dst_rect.y;
2553 ctx->crop_cap.width = item.dst_rect.w;
2554 ctx->crop_cap.height = item.dst_rect.h;
2555 } else {
2556 return -EINVAL;
2557 }
2558
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002559 return 0;
2560}
2561
2562/*
2563 * sde_rotator_g_parm - V4l2 ioctl get parm.
2564 * @file: Pointer to file struct.
2565 * @fh: V4l2 File handle.
2566 * @a: Pointer to v4l2_streamparm struct need to be filled.
2567 */
2568static int sde_rotator_g_parm(struct file *file, void *fh,
2569 struct v4l2_streamparm *a)
2570{
2571 struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh);
2572
2573 /* Get param is supported only for input buffers */
2574 if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
2575 return -EINVAL;
2576
2577 a->parm.output.capability = 0;
2578 a->parm.output.extendedmode = 0;
2579 a->parm.output.outputmode = 0;
2580 a->parm.output.writebuffers = 0;
2581 a->parm.output.timeperframe = ctx->timeperframe;
2582
2583 return 0;
2584}
2585
2586/*
2587 * sde_rotator_s_parm - V4l2 ioctl set parm.
2588 * @file: Pointer to file struct.
2589 * @fh: V4l2 File handle.
2590 * @a: Pointer to v4l2_streamparm struct need to be set.
2591 */
2592static int sde_rotator_s_parm(struct file *file, void *fh,
2593 struct v4l2_streamparm *a)
2594{
2595 struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh);
2596
2597 /* Set param is supported only for input buffers */
2598 if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
2599 return -EINVAL;
2600
2601 if (!a->parm.output.timeperframe.numerator ||
2602 !a->parm.output.timeperframe.denominator)
2603 return -EINVAL;
2604
2605 ctx->timeperframe = a->parm.output.timeperframe;
2606 return 0;
2607}
2608
2609/*
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002610 * sde_rotator_private_ioctl - V4l2 private ioctl handler.
2611 * @file: Pointer to file struct.
2612 * @fd: V4l2 device file handle.
2613 * @valid_prio: Priority ioctl valid flag.
2614 * @cmd: Ioctl command.
2615 * @arg: Ioctl argument.
2616 */
2617static long sde_rotator_private_ioctl(struct file *file, void *fh,
2618 bool valid_prio, unsigned int cmd, void *arg)
2619{
2620 struct sde_rotator_ctx *ctx =
2621 sde_rotator_ctx_from_fh(file->private_data);
2622 struct sde_rotator_device *rot_dev = ctx->rot_dev;
2623 struct msm_sde_rotator_fence *fence = arg;
Alan Kwong09a36ef2016-11-10 01:39:16 -05002624 struct msm_sde_rotator_comp_ratio *comp_ratio = arg;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002625 struct sde_rotator_vbinfo *vbinfo;
Benjamin Chan834d21d2017-06-15 18:18:54 -04002626 int ret;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002627
2628 switch (cmd) {
2629 case VIDIOC_S_SDE_ROTATOR_FENCE:
2630 if (!fence)
2631 return -EINVAL;
2632
2633 if (fence->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
2634 return -EINVAL;
2635
2636 if (fence->index >= ctx->nbuf_out)
2637 return -EINVAL;
2638
2639 SDEDEV_DBG(rot_dev->dev,
2640 "VIDIOC_S_SDE_ROTATOR_FENCE s:%d i:%d fd:%d\n",
2641 ctx->session_id, fence->index,
2642 fence->fd);
2643
2644 vbinfo = &ctx->vbinfo_out[fence->index];
2645
2646 if (vbinfo->fd >= 0) {
2647 if (vbinfo->fence) {
2648 SDEDEV_DBG(rot_dev->dev,
2649 "put fence s:%d t:%d i:%d\n",
2650 ctx->session_id,
2651 fence->type, fence->index);
2652 sde_rotator_put_sync_fence(vbinfo->fence);
2653 }
2654 vbinfo->fence = NULL;
2655 vbinfo->fd = -1;
2656 }
2657
2658 vbinfo->fd = fence->fd;
2659 if (vbinfo->fd >= 0) {
2660 vbinfo->fence =
2661 sde_rotator_get_fd_sync_fence(vbinfo->fd);
2662 if (!vbinfo->fence) {
2663 SDEDEV_WARN(rot_dev->dev,
2664 "invalid input fence fd s:%d fd:%d\n",
2665 ctx->session_id, vbinfo->fd);
2666 vbinfo->fd = -1;
2667 return -EINVAL;
2668 }
2669 } else {
2670 vbinfo->fence = NULL;
2671 }
2672 break;
2673 case VIDIOC_G_SDE_ROTATOR_FENCE:
2674 if (!fence)
2675 return -EINVAL;
2676
2677 if (fence->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
2678 return -EINVAL;
2679
2680 if (fence->index >= ctx->nbuf_cap)
2681 return -EINVAL;
2682
2683 vbinfo = &ctx->vbinfo_cap[fence->index];
2684
Benjamin Chan834d21d2017-06-15 18:18:54 -04002685 if (!vbinfo)
2686 return -EINVAL;
2687
2688 if (vbinfo->fence) {
2689 ret = sde_rotator_get_sync_fence_fd(vbinfo->fence);
2690 if (ret < 0) {
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002691 SDEDEV_ERR(rot_dev->dev,
Benjamin Chan834d21d2017-06-15 18:18:54 -04002692 "fail get fence fd s:%d\n",
2693 ctx->session_id);
2694 return ret;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002695 }
Benjamin Chan834d21d2017-06-15 18:18:54 -04002696
2697 /**
Benjamin Chan834d21d2017-06-15 18:18:54 -04002698 * Cache fence descriptor in case user calls this
2699 * ioctl multiple times. Cached value would be stale
2700 * if user duplicated and closed old descriptor.
2701 */
2702 vbinfo->fd = ret;
2703 } else if (!sde_rotator_get_fd_sync_fence(vbinfo->fd)) {
2704 /**
2705 * User has closed cached fence descriptor.
2706 * Invalidate descriptor cache.
2707 */
2708 vbinfo->fd = -1;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002709 }
2710 fence->fd = vbinfo->fd;
2711
2712 SDEDEV_DBG(rot_dev->dev,
2713 "VIDIOC_G_SDE_ROTATOR_FENCE s:%d i:%d fd:%d\n",
2714 ctx->session_id, fence->index,
2715 fence->fd);
2716 break;
Alan Kwong09a36ef2016-11-10 01:39:16 -05002717 case VIDIOC_S_SDE_ROTATOR_COMP_RATIO:
2718 if (!comp_ratio)
2719 return -EINVAL;
2720 else if (!comp_ratio->numer || !comp_ratio->denom)
2721 return -EINVAL;
2722 else if (comp_ratio->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
2723 comp_ratio->index < ctx->nbuf_out)
2724 vbinfo = &ctx->vbinfo_out[comp_ratio->index];
2725 else if (comp_ratio->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
2726 comp_ratio->index < ctx->nbuf_cap)
2727 vbinfo = &ctx->vbinfo_cap[comp_ratio->index];
2728 else
2729 return -EINVAL;
2730
2731 vbinfo->comp_ratio.numer = comp_ratio->numer;
2732 vbinfo->comp_ratio.denom = comp_ratio->denom;
2733
2734 SDEDEV_DBG(rot_dev->dev,
2735 "VIDIOC_S_SDE_ROTATOR_COMP_RATIO s:%d i:%d t:%d cr:%u/%u\n",
2736 ctx->session_id, comp_ratio->index,
2737 comp_ratio->type,
2738 vbinfo->comp_ratio.numer,
2739 vbinfo->comp_ratio.denom);
2740 break;
2741 case VIDIOC_G_SDE_ROTATOR_COMP_RATIO:
2742 if (!comp_ratio)
2743 return -EINVAL;
2744 else if (comp_ratio->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
2745 comp_ratio->index < ctx->nbuf_out)
2746 vbinfo = &ctx->vbinfo_out[comp_ratio->index];
2747 else if (comp_ratio->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
2748 comp_ratio->index < ctx->nbuf_cap)
2749 vbinfo = &ctx->vbinfo_cap[comp_ratio->index];
2750 else
2751 return -EINVAL;
2752
2753 comp_ratio->numer = vbinfo->comp_ratio.numer;
2754 comp_ratio->denom = vbinfo->comp_ratio.denom;
2755
2756 SDEDEV_DBG(rot_dev->dev,
2757 "VIDIOC_G_SDE_ROTATOR_COMP_RATIO s:%d i:%d t:%d cr:%u/%u\n",
2758 ctx->session_id, comp_ratio->index,
2759 comp_ratio->type,
2760 comp_ratio->numer,
2761 comp_ratio->denom);
2762 break;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002763 default:
2764 SDEDEV_WARN(rot_dev->dev, "invalid ioctl type %x\n", cmd);
2765 return -ENOTTY;
2766 }
2767
2768 return 0;
2769}
2770
2771#ifdef CONFIG_COMPAT
2772/*
2773 * sde_rotator_compat_ioctl32 - Compat ioctl handler function.
2774 * @file: Pointer to file struct.
2775 * @cmd: Ioctl command.
2776 * @arg: Ioctl argument.
2777 */
2778static long sde_rotator_compat_ioctl32(struct file *file,
2779 unsigned int cmd, unsigned long arg)
2780{
Benjamin Chan87b81d52017-03-21 14:21:41 -04002781 struct video_device *vdev = video_devdata(file);
2782 struct sde_rotator_ctx *ctx =
2783 sde_rotator_ctx_from_fh(file->private_data);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002784 long ret;
2785
Benjamin Chan87b81d52017-03-21 14:21:41 -04002786 mutex_lock(vdev->lock);
2787
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002788 switch (cmd) {
2789 case VIDIOC_S_SDE_ROTATOR_FENCE:
2790 case VIDIOC_G_SDE_ROTATOR_FENCE:
2791 {
2792 struct msm_sde_rotator_fence fence;
2793
2794 if (copy_from_user(&fence, (void __user *)arg,
2795 sizeof(struct msm_sde_rotator_fence)))
Benjamin Chan87b81d52017-03-21 14:21:41 -04002796 goto ioctl32_error;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002797
2798 ret = sde_rotator_private_ioctl(file, file->private_data,
2799 0, cmd, (void *)&fence);
2800
2801 if (copy_to_user((void __user *)arg, &fence,
2802 sizeof(struct msm_sde_rotator_fence)))
Benjamin Chan87b81d52017-03-21 14:21:41 -04002803 goto ioctl32_error;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002804
2805 break;
2806 }
Alan Kwong09a36ef2016-11-10 01:39:16 -05002807 case VIDIOC_S_SDE_ROTATOR_COMP_RATIO:
2808 case VIDIOC_G_SDE_ROTATOR_COMP_RATIO:
2809 {
2810 struct msm_sde_rotator_comp_ratio comp_ratio;
2811
2812 if (copy_from_user(&comp_ratio, (void __user *)arg,
2813 sizeof(struct msm_sde_rotator_comp_ratio)))
Benjamin Chan87b81d52017-03-21 14:21:41 -04002814 goto ioctl32_error;
Alan Kwong09a36ef2016-11-10 01:39:16 -05002815
2816 ret = sde_rotator_private_ioctl(file, file->private_data,
2817 0, cmd, (void *)&comp_ratio);
2818
2819 if (copy_to_user((void __user *)arg, &comp_ratio,
2820 sizeof(struct msm_sde_rotator_comp_ratio)))
Benjamin Chan87b81d52017-03-21 14:21:41 -04002821 goto ioctl32_error;
Alan Kwong09a36ef2016-11-10 01:39:16 -05002822
2823 break;
2824 }
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002825 default:
Benjamin Chan87b81d52017-03-21 14:21:41 -04002826 SDEDEV_ERR(ctx->rot_dev->dev, "invalid ioctl32 type:%x\n", cmd);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002827 ret = -ENOIOCTLCMD;
2828 break;
2829
2830 }
2831
Benjamin Chan87b81d52017-03-21 14:21:41 -04002832 mutex_unlock(vdev->lock);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002833 return ret;
Benjamin Chan87b81d52017-03-21 14:21:41 -04002834
2835ioctl32_error:
2836 mutex_unlock(vdev->lock);
2837 SDEDEV_ERR(ctx->rot_dev->dev, "error handling ioctl32 cmd:%x\n", cmd);
2838 return -EFAULT;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002839}
2840#endif
2841
Alan Kwong915ac412017-10-12 11:49:55 -04002842static int sde_rotator_ctrl_subscribe_event(struct v4l2_fh *fh,
2843 const struct v4l2_event_subscription *sub)
2844{
2845 return -EINVAL;
2846}
2847
2848static int sde_rotator_event_unsubscribe(struct v4l2_fh *fh,
2849 const struct v4l2_event_subscription *sub)
2850{
2851 return -EINVAL;
2852}
2853
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002854/* V4l2 ioctl handlers */
2855static const struct v4l2_ioctl_ops sde_rotator_ioctl_ops = {
2856 .vidioc_querycap = sde_rotator_querycap,
2857 .vidioc_enum_fmt_vid_out = sde_rotator_enum_fmt_vid_out,
2858 .vidioc_enum_fmt_vid_cap = sde_rotator_enum_fmt_vid_cap,
2859 .vidioc_g_fmt_vid_out = sde_rotator_g_fmt_out,
2860 .vidioc_g_fmt_vid_cap = sde_rotator_g_fmt_cap,
2861 .vidioc_try_fmt_vid_out = sde_rotator_try_fmt_vid_out,
2862 .vidioc_try_fmt_vid_cap = sde_rotator_try_fmt_vid_cap,
2863 .vidioc_s_fmt_vid_out = sde_rotator_s_fmt_vid_out,
2864 .vidioc_s_fmt_vid_cap = sde_rotator_s_fmt_vid_cap,
2865 .vidioc_reqbufs = sde_rotator_reqbufs,
2866 .vidioc_qbuf = sde_rotator_qbuf,
2867 .vidioc_dqbuf = sde_rotator_dqbuf,
2868 .vidioc_querybuf = sde_rotator_querybuf,
2869 .vidioc_streamon = sde_rotator_streamon,
2870 .vidioc_streamoff = sde_rotator_streamoff,
2871 .vidioc_cropcap = sde_rotator_cropcap,
2872 .vidioc_g_crop = sde_rotator_g_crop,
2873 .vidioc_s_crop = sde_rotator_s_crop,
2874 .vidioc_g_parm = sde_rotator_g_parm,
2875 .vidioc_s_parm = sde_rotator_s_parm,
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002876 .vidioc_default = sde_rotator_private_ioctl,
2877 .vidioc_log_status = v4l2_ctrl_log_status,
Alan Kwong915ac412017-10-12 11:49:55 -04002878 .vidioc_subscribe_event = sde_rotator_ctrl_subscribe_event,
2879 .vidioc_unsubscribe_event = sde_rotator_event_unsubscribe,
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002880};
2881
2882/*
2883 * sde_rotator_retire_handler - Invoked by hal when processing is done.
2884 * @work: Pointer to work structure.
2885 *
2886 * This function is scheduled in work queue context.
2887 */
Benjamin Chanf8d9a462016-11-08 21:38:10 -05002888static void sde_rotator_retire_handler(struct kthread_work *work)
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002889{
Alan Kwong3428f672016-04-18 12:32:06 -04002890 struct vb2_v4l2_buffer *src_buf;
2891 struct vb2_v4l2_buffer *dst_buf;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002892 struct sde_rotator_ctx *ctx;
2893 struct sde_rotator_device *rot_dev;
Alan Kwongf94a2552016-12-28 09:41:22 -08002894 struct sde_rotator_request *request;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002895
Alan Kwongf94a2552016-12-28 09:41:22 -08002896 request = container_of(work, struct sde_rotator_request, retire_work);
2897 ctx = request->ctx;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002898
2899 if (!ctx || !ctx->rot_dev) {
2900 SDEROT_ERR("null context/device\n");
2901 return;
2902 }
2903
2904 rot_dev = ctx->rot_dev;
2905
2906 SDEDEV_DBG(rot_dev->dev, "retire handler s:%d\n", ctx->session_id);
2907
2908 mutex_lock(&rot_dev->lock);
2909 if (ctx->abort_pending) {
2910 SDEDEV_DBG(rot_dev->dev, "abort command in retire s:%d\n",
2911 ctx->session_id);
Alan Kwongf94a2552016-12-28 09:41:22 -08002912 sde_rotator_update_retire_sequence(request);
2913 sde_rotator_retire_request(request);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002914 mutex_unlock(&rot_dev->lock);
2915 return;
2916 }
2917
Alan Kwong6bc64622017-02-04 17:36:03 -08002918 if (!ctx->file) {
2919 sde_rotator_update_retire_sequence(request);
2920 } else if (rot_dev->early_submit) {
Alan Kwongf94a2552016-12-28 09:41:22 -08002921 if (IS_ERR_OR_NULL(request->req)) {
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002922 /* fail pending request or something wrong */
2923 SDEDEV_ERR(rot_dev->dev,
2924 "pending request fail in retire s:%d\n",
2925 ctx->session_id);
2926 }
2927
2928 /* pending request. reschedule this context. */
Alan Kwong3428f672016-04-18 12:32:06 -04002929 v4l2_m2m_try_schedule(ctx->fh.m2m_ctx);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002930 } else {
2931 /* no pending request. acknowledge the usual way. */
Alan Kwong3428f672016-04-18 12:32:06 -04002932 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
2933 dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002934
2935 if (!src_buf || !dst_buf) {
2936 SDEDEV_ERR(rot_dev->dev,
2937 "null buffer in retire s:%d sb:%p db:%p\n",
2938 ctx->session_id,
2939 src_buf, dst_buf);
2940 }
2941
Alan Kwongf94a2552016-12-28 09:41:22 -08002942 sde_rotator_update_retire_sequence(request);
2943 sde_rotator_retire_request(request);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002944 v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
2945 v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
Alan Kwong3428f672016-04-18 12:32:06 -04002946 v4l2_m2m_job_finish(rot_dev->m2m_dev, ctx->fh.m2m_ctx);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002947 }
2948 mutex_unlock(&rot_dev->lock);
2949}
2950
2951/*
2952 * sde_rotator_process_buffers - Start rotator processing.
2953 * @ctx: Pointer rotator context.
2954 * @src_buf: Pointer to Vb2 source buffer.
2955 * @dst_buf: Pointer to Vb2 destination buffer.
Alan Kwongf94a2552016-12-28 09:41:22 -08002956 * @request: Pointer to rotator request
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002957 */
2958static int sde_rotator_process_buffers(struct sde_rotator_ctx *ctx,
Alan Kwongf94a2552016-12-28 09:41:22 -08002959 struct vb2_buffer *src_buf, struct vb2_buffer *dst_buf,
2960 struct sde_rotator_request *request)
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002961{
2962 struct sde_rotator_device *rot_dev = ctx->rot_dev;
2963 struct sde_rotation_item item;
2964 struct sde_rot_entry_container *req = NULL;
2965 struct sde_rotator_buf_handle *src_handle;
2966 struct sde_rotator_buf_handle *dst_handle;
2967 struct sde_rotator_statistics *stats = &rot_dev->stats;
2968 struct sde_rotator_vbinfo *vbinfo_out;
2969 struct sde_rotator_vbinfo *vbinfo_cap;
2970 ktime_t *ts;
2971 int ret;
2972
2973 if (!src_buf || !dst_buf) {
2974 SDEDEV_ERR(rot_dev->dev, "null vb2 buffers\n");
2975 ret = -EINVAL;
2976 goto error_null_buffer;
2977 }
2978
2979 src_handle = src_buf->planes[0].mem_priv;
2980 dst_handle = dst_buf->planes[0].mem_priv;
2981
2982 if (!src_handle || !dst_handle) {
2983 SDEDEV_ERR(rot_dev->dev, "null buffer handle\n");
2984 ret = -EINVAL;
2985 goto error_null_buffer;
2986 }
2987
Alan Kwong3428f672016-04-18 12:32:06 -04002988 vbinfo_out = &ctx->vbinfo_out[src_buf->index];
2989 vbinfo_cap = &ctx->vbinfo_cap[dst_buf->index];
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002990
2991 SDEDEV_DBG(rot_dev->dev,
Alan Kwong09a36ef2016-11-10 01:39:16 -05002992 "process buffer s:%d.%u src:(%u,%u,%u,%u) dst:(%u,%u,%u,%u) rot:%d flip:%d/%d sec:%d src_cr:%u/%u dst_cr:%u/%u\n",
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002993 ctx->session_id, vbinfo_cap->fence_ts,
2994 ctx->crop_out.left, ctx->crop_out.top,
2995 ctx->crop_out.width, ctx->crop_out.height,
2996 ctx->crop_cap.left, ctx->crop_cap.top,
2997 ctx->crop_cap.width, ctx->crop_cap.height,
Alan Kwong09a36ef2016-11-10 01:39:16 -05002998 ctx->rotate, ctx->hflip, ctx->vflip, ctx->secure,
2999 vbinfo_out->comp_ratio.numer, vbinfo_out->comp_ratio.denom,
3000 vbinfo_cap->comp_ratio.numer, vbinfo_cap->comp_ratio.denom);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003001
3002 /* allocate slot for timestamp */
3003 ts = stats->ts[stats->count++ % SDE_ROTATOR_NUM_EVENTS];
3004 ts[SDE_ROTATOR_TS_SRCQB] = vbinfo_out->qbuf_ts;
3005 ts[SDE_ROTATOR_TS_DSTQB] = vbinfo_cap->qbuf_ts;
3006 vbinfo_out->dqbuf_ts = &ts[SDE_ROTATOR_TS_SRCDQB];
3007 vbinfo_cap->dqbuf_ts = &ts[SDE_ROTATOR_TS_DSTDQB];
3008
3009 ts[SDE_ROTATOR_TS_FENCE] = ktime_get();
3010
3011 trace_rot_entry_fence(
3012 ctx->session_id, vbinfo_cap->fence_ts,
Alan Kwong3428f672016-04-18 12:32:06 -04003013 ctx->fh.prio,
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003014 (ctx->rotate << 0) | (ctx->hflip << 8) |
3015 (ctx->hflip << 9) | (ctx->secure << 10),
3016 ctx->format_out.fmt.pix.pixelformat,
3017 ctx->format_out.fmt.pix.width,
3018 ctx->format_out.fmt.pix.height,
3019 ctx->crop_out.left, ctx->crop_out.top,
3020 ctx->crop_out.width, ctx->crop_out.height,
3021 ctx->format_cap.fmt.pix.pixelformat,
3022 ctx->format_cap.fmt.pix.width,
3023 ctx->format_cap.fmt.pix.height,
3024 ctx->crop_cap.left, ctx->crop_cap.top,
3025 ctx->crop_cap.width, ctx->crop_cap.height);
3026
3027 if (vbinfo_out->fence) {
3028 sde_rot_mgr_unlock(rot_dev->mgr);
3029 mutex_unlock(&rot_dev->lock);
3030 SDEDEV_DBG(rot_dev->dev, "fence enter s:%d.%d fd:%d\n",
3031 ctx->session_id, vbinfo_cap->fence_ts, vbinfo_out->fd);
3032 ret = sde_rotator_wait_sync_fence(vbinfo_out->fence,
3033 rot_dev->fence_timeout);
3034 mutex_lock(&rot_dev->lock);
3035 sde_rot_mgr_lock(rot_dev->mgr);
3036 sde_rotator_put_sync_fence(vbinfo_out->fence);
3037 vbinfo_out->fence = NULL;
3038 if (ret) {
3039 SDEDEV_ERR(rot_dev->dev,
3040 "error waiting for fence s:%d.%d fd:%d r:%d\n",
3041 ctx->session_id,
3042 vbinfo_cap->fence_ts, vbinfo_out->fd, ret);
Alan Kwongde85fcd2017-07-31 18:18:49 -04003043 SDEROT_EVTLOG(ctx->session_id, vbinfo_cap->fence_ts,
3044 vbinfo_out->fd, ret,
3045 SDE_ROT_EVTLOG_ERROR);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003046 goto error_fence_wait;
3047 } else {
3048 SDEDEV_DBG(rot_dev->dev, "fence exit s:%d.%d fd:%d\n",
3049 ctx->session_id,
3050 vbinfo_cap->fence_ts, vbinfo_out->fd);
3051 }
3052 }
3053
3054 /* fill in item work structure */
3055 sde_rotator_get_item_from_ctx(ctx, &item);
3056 item.flags |= SDE_ROTATION_EXT_DMA_BUF;
3057 item.input.planes[0].buffer = src_handle->buffer;
Abhijit Kulkarni298c8232016-09-26 22:32:10 -07003058 item.input.planes[0].handle = src_handle->handle;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003059 item.input.planes[0].offset = src_handle->addr;
3060 item.input.planes[0].stride = ctx->format_out.fmt.pix.bytesperline;
3061 item.input.plane_count = 1;
3062 item.input.fence = NULL;
Alan Kwong09a36ef2016-11-10 01:39:16 -05003063 item.input.comp_ratio = vbinfo_out->comp_ratio;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003064 item.output.planes[0].buffer = dst_handle->buffer;
Abhijit Kulkarni298c8232016-09-26 22:32:10 -07003065 item.output.planes[0].handle = dst_handle->handle;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003066 item.output.planes[0].offset = dst_handle->addr;
3067 item.output.planes[0].stride = ctx->format_cap.fmt.pix.bytesperline;
3068 item.output.plane_count = 1;
3069 item.output.fence = NULL;
Alan Kwong09a36ef2016-11-10 01:39:16 -05003070 item.output.comp_ratio = vbinfo_cap->comp_ratio;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003071 item.sequence_id = vbinfo_cap->fence_ts;
3072 item.ts = ts;
3073
3074 req = sde_rotator_req_init(rot_dev->mgr, ctx->private, &item, 1, 0);
3075 if (IS_ERR_OR_NULL(req)) {
3076 SDEDEV_ERR(rot_dev->dev, "fail allocate rotation request\n");
3077 ret = -ENOMEM;
3078 goto error_init_request;
3079 }
3080
Benjamin Chanf8d9a462016-11-08 21:38:10 -05003081 req->retire_kw = &ctx->work_queue.rot_kw;
Alan Kwongf94a2552016-12-28 09:41:22 -08003082 req->retire_work = &request->retire_work;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003083
3084 ret = sde_rotator_handle_request_common(
Alan Kwongf94a2552016-12-28 09:41:22 -08003085 rot_dev->mgr, ctx->private, req);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003086 if (ret) {
3087 SDEDEV_ERR(rot_dev->dev, "fail handle request\n");
3088 goto error_handle_request;
3089 }
3090
3091 sde_rotator_queue_request(rot_dev->mgr, ctx->private, req);
Alan Kwongf94a2552016-12-28 09:41:22 -08003092 request->req = req;
Alan Kwong3ddf48c2017-10-06 10:45:41 -04003093 request->sequence_id = item.sequence_id;
3094 request->committed = true;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003095
3096 return 0;
3097error_handle_request:
3098 devm_kfree(rot_dev->dev, req);
3099error_init_request:
3100error_fence_wait:
3101error_null_buffer:
Alan Kwongf94a2552016-12-28 09:41:22 -08003102 request->req = NULL;
Alan Kwong3ddf48c2017-10-06 10:45:41 -04003103 request->sequence_id = 0;
3104 request->committed = false;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003105 return ret;
3106}
3107
3108/*
3109 * sde_rotator_submit_handler - Invoked by m2m to submit job.
3110 * @work: Pointer to work structure.
3111 *
3112 * This function is scheduled in work queue context.
3113 */
Benjamin Chanf8d9a462016-11-08 21:38:10 -05003114static void sde_rotator_submit_handler(struct kthread_work *work)
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003115{
3116 struct sde_rotator_ctx *ctx;
3117 struct sde_rotator_device *rot_dev;
Alan Kwong3428f672016-04-18 12:32:06 -04003118 struct vb2_v4l2_buffer *src_buf;
3119 struct vb2_v4l2_buffer *dst_buf;
Alan Kwongf94a2552016-12-28 09:41:22 -08003120 struct sde_rotator_request *request;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003121 int ret;
3122
Alan Kwongf94a2552016-12-28 09:41:22 -08003123 request = container_of(work, struct sde_rotator_request, submit_work);
3124 ctx = request->ctx;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003125
Alan Kwongf94a2552016-12-28 09:41:22 -08003126 if (!ctx || !ctx->rot_dev) {
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003127 SDEROT_ERR("null device\n");
3128 return;
3129 }
3130
3131 rot_dev = ctx->rot_dev;
3132 SDEDEV_DBG(rot_dev->dev, "submit handler s:%d\n", ctx->session_id);
3133
3134 mutex_lock(&rot_dev->lock);
3135 if (ctx->abort_pending) {
3136 SDEDEV_DBG(rot_dev->dev, "abort command in submit s:%d\n",
3137 ctx->session_id);
Alan Kwongf94a2552016-12-28 09:41:22 -08003138 sde_rotator_update_retire_sequence(request);
3139 sde_rotator_retire_request(request);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003140 mutex_unlock(&rot_dev->lock);
3141 return;
3142 }
3143
3144 /* submit new request */
Alan Kwong3428f672016-04-18 12:32:06 -04003145 dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
3146 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003147 sde_rot_mgr_lock(rot_dev->mgr);
Alan Kwong3428f672016-04-18 12:32:06 -04003148 ret = sde_rotator_process_buffers(ctx, &src_buf->vb2_buf,
Alan Kwongf94a2552016-12-28 09:41:22 -08003149 &dst_buf->vb2_buf, request);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003150 sde_rot_mgr_unlock(rot_dev->mgr);
3151 if (ret) {
3152 SDEDEV_ERR(rot_dev->dev,
3153 "fail process buffer in submit s:%d\n",
3154 ctx->session_id);
3155 /* advance to device run to clean up buffers */
Alan Kwong3428f672016-04-18 12:32:06 -04003156 v4l2_m2m_try_schedule(ctx->fh.m2m_ctx);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003157 }
3158
3159 mutex_unlock(&rot_dev->lock);
3160}
3161
3162/*
3163 * sde_rotator_device_run - rotator m2m device run callback
3164 * @priv: Pointer rotator context.
3165 */
3166static void sde_rotator_device_run(void *priv)
3167{
3168 struct sde_rotator_ctx *ctx = priv;
3169 struct sde_rotator_device *rot_dev;
Alan Kwong3428f672016-04-18 12:32:06 -04003170 struct vb2_v4l2_buffer *src_buf;
3171 struct vb2_v4l2_buffer *dst_buf;
Alan Kwongf94a2552016-12-28 09:41:22 -08003172 struct sde_rotator_request *request;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003173 int ret;
3174
3175 if (!ctx || !ctx->rot_dev) {
3176 SDEROT_ERR("null context/device\n");
3177 return;
3178 }
3179
3180 rot_dev = ctx->rot_dev;
3181 SDEDEV_DBG(rot_dev->dev, "device run s:%d\n", ctx->session_id);
3182
3183 if (rot_dev->early_submit) {
Alan Kwongf94a2552016-12-28 09:41:22 -08003184 request = list_first_entry_or_null(&ctx->pending_list,
3185 struct sde_rotator_request, list);
3186
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003187 /* pending request mode, check for completion */
Alan Kwongf94a2552016-12-28 09:41:22 -08003188 if (!request || IS_ERR_OR_NULL(request->req)) {
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003189 /* pending request fails or something wrong. */
3190 SDEDEV_ERR(rot_dev->dev,
3191 "pending request fail in device run s:%d\n",
3192 ctx->session_id);
3193 rot_dev->stats.fail_count++;
3194 ATRACE_INT("fail_count", rot_dev->stats.fail_count);
3195 goto error_process_buffers;
Alan Kwongf94a2552016-12-28 09:41:22 -08003196
3197 } else if (!atomic_read(&request->req->pending_count)) {
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003198 /* pending request completed. signal done. */
3199 int failed_count =
Alan Kwongf94a2552016-12-28 09:41:22 -08003200 atomic_read(&request->req->failed_count);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003201 SDEDEV_DBG(rot_dev->dev,
3202 "pending request completed in device run s:%d\n",
3203 ctx->session_id);
3204
3205 /* disconnect request (will be freed by core layer) */
3206 sde_rot_mgr_lock(rot_dev->mgr);
Alan Kwongf94a2552016-12-28 09:41:22 -08003207 sde_rotator_req_finish(rot_dev->mgr, ctx->private,
3208 request->req);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003209 sde_rot_mgr_unlock(rot_dev->mgr);
3210
3211 if (failed_count) {
3212 SDEDEV_ERR(rot_dev->dev,
3213 "pending request failed in device run s:%d f:%d\n",
3214 ctx->session_id,
3215 failed_count);
3216 rot_dev->stats.fail_count++;
3217 ATRACE_INT("fail_count",
3218 rot_dev->stats.fail_count);
3219 goto error_process_buffers;
3220 }
3221
Alan Kwong3428f672016-04-18 12:32:06 -04003222 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
3223 dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003224 if (!src_buf || !dst_buf) {
3225 SDEDEV_ERR(rot_dev->dev,
3226 "null buffer in device run s:%d sb:%p db:%p\n",
3227 ctx->session_id,
3228 src_buf, dst_buf);
3229 goto error_process_buffers;
3230 }
3231
Alan Kwongf94a2552016-12-28 09:41:22 -08003232 sde_rotator_update_retire_sequence(request);
3233 sde_rotator_retire_request(request);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003234 v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
3235 v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
Alan Kwong3428f672016-04-18 12:32:06 -04003236 v4l2_m2m_job_finish(rot_dev->m2m_dev, ctx->fh.m2m_ctx);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003237 } else {
3238 /* pending request not complete. something wrong. */
3239 SDEDEV_ERR(rot_dev->dev,
3240 "Incomplete pending request in device run s:%d\n",
3241 ctx->session_id);
3242
3243 /* disconnect request (will be freed by core layer) */
3244 sde_rot_mgr_lock(rot_dev->mgr);
Alan Kwongf94a2552016-12-28 09:41:22 -08003245 sde_rotator_req_finish(rot_dev->mgr, ctx->private,
3246 request->req);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003247 sde_rot_mgr_unlock(rot_dev->mgr);
3248
3249 goto error_process_buffers;
3250 }
3251 } else {
Alan Kwongf94a2552016-12-28 09:41:22 -08003252 request = list_first_entry_or_null(&ctx->retired_list,
3253 struct sde_rotator_request, list);
3254 if (!request) {
3255 SDEDEV_ERR(rot_dev->dev,
3256 "no free request in device run s:%d\n",
3257 ctx->session_id);
3258 goto error_retired_list;
3259 }
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003260
Alan Kwongf94a2552016-12-28 09:41:22 -08003261 spin_lock(&ctx->list_lock);
3262 list_del_init(&request->list);
3263 list_add_tail(&request->list, &ctx->pending_list);
3264 spin_unlock(&ctx->list_lock);
3265
3266 /* no pending request. submit buffer the usual way. */
Alan Kwong3428f672016-04-18 12:32:06 -04003267 dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
3268 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003269 if (!src_buf || !dst_buf) {
3270 SDEDEV_ERR(rot_dev->dev,
Alan Kwong6bc64622017-02-04 17:36:03 -08003271 "null buffer in device run s:%d sb:%pK db:%pK\n",
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003272 ctx->session_id,
3273 src_buf, dst_buf);
3274 goto error_empty_buffer;
3275 }
3276
3277 sde_rot_mgr_lock(rot_dev->mgr);
Alan Kwong3428f672016-04-18 12:32:06 -04003278 ret = sde_rotator_process_buffers(ctx, &src_buf->vb2_buf,
Alan Kwongf94a2552016-12-28 09:41:22 -08003279 &dst_buf->vb2_buf, request);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003280 sde_rot_mgr_unlock(rot_dev->mgr);
3281 if (ret) {
3282 SDEDEV_ERR(rot_dev->dev,
3283 "fail process buffer in device run s:%d\n",
3284 ctx->session_id);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003285 rot_dev->stats.fail_count++;
3286 ATRACE_INT("fail_count", rot_dev->stats.fail_count);
3287 goto error_process_buffers;
3288 }
3289 }
3290
3291 return;
3292error_process_buffers:
3293error_empty_buffer:
Alan Kwongf94a2552016-12-28 09:41:22 -08003294error_retired_list:
3295 sde_rotator_update_retire_sequence(request);
3296 sde_rotator_retire_request(request);
Alan Kwong3428f672016-04-18 12:32:06 -04003297 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
3298 dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003299 if (src_buf)
3300 v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
3301 if (dst_buf)
3302 v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
3303 sde_rotator_resync_timeline(ctx->work_queue.timeline);
Alan Kwong3428f672016-04-18 12:32:06 -04003304 v4l2_m2m_job_finish(rot_dev->m2m_dev, ctx->fh.m2m_ctx);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003305}
3306
3307/*
3308 * sde_rotator_job_abort - rotator m2m job abort callback
3309 * @priv: Pointer rotator context.
3310 */
3311static void sde_rotator_job_abort(void *priv)
3312{
3313 struct sde_rotator_ctx *ctx = priv;
3314 struct sde_rotator_device *rot_dev;
3315
3316 if (!ctx || !ctx->rot_dev) {
3317 SDEROT_ERR("null context/device\n");
3318 return;
3319 }
3320
3321 rot_dev = ctx->rot_dev;
3322 SDEDEV_DBG(rot_dev->dev, "job abort s:%d\n", ctx->session_id);
3323
Alan Kwong3428f672016-04-18 12:32:06 -04003324 v4l2_m2m_job_finish(rot_dev->m2m_dev, ctx->fh.m2m_ctx);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003325}
3326
3327/*
3328 * sde_rotator_job_ready - rotator m2m job ready callback
3329 * @priv: Pointer rotator context.
3330 */
3331static int sde_rotator_job_ready(void *priv)
3332{
3333 struct sde_rotator_ctx *ctx = priv;
3334 struct sde_rotator_device *rot_dev;
Alan Kwongf94a2552016-12-28 09:41:22 -08003335 struct sde_rotator_request *request;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003336 int ret = 0;
3337
3338 if (!ctx || !ctx->rot_dev) {
3339 SDEROT_ERR("null context/device\n");
3340 return 0;
3341 }
3342
3343 rot_dev = ctx->rot_dev;
3344 SDEDEV_DBG(rot_dev->dev, "job ready s:%d\n", ctx->session_id);
3345
Alan Kwongf94a2552016-12-28 09:41:22 -08003346 request = list_first_entry_or_null(&ctx->pending_list,
3347 struct sde_rotator_request, list);
3348
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003349 if (!rot_dev->early_submit) {
3350 /* always ready in normal mode. */
3351 ret = 1;
Alan Kwongf94a2552016-12-28 09:41:22 -08003352 } else if (request && IS_ERR_OR_NULL(request->req)) {
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003353 /* if pending request fails, forward to device run state. */
3354 SDEDEV_DBG(rot_dev->dev,
3355 "pending request fail in job ready s:%d\n",
3356 ctx->session_id);
3357 ret = 1;
Alan Kwongf94a2552016-12-28 09:41:22 -08003358 } else if (list_empty(&ctx->pending_list)) {
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003359 /* if no pending request, submit a new request. */
3360 SDEDEV_DBG(rot_dev->dev,
3361 "submit job s:%d sc:%d dc:%d p:%d\n",
3362 ctx->session_id,
Alan Kwong3428f672016-04-18 12:32:06 -04003363 v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx),
3364 v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx),
Alan Kwongf94a2552016-12-28 09:41:22 -08003365 !list_empty(&ctx->pending_list));
3366
3367 request = list_first_entry_or_null(&ctx->retired_list,
3368 struct sde_rotator_request, list);
3369 if (!request) {
3370 /* should not happen */
3371 SDEDEV_ERR(rot_dev->dev,
3372 "no free request in job ready s:%d\n",
3373 ctx->session_id);
3374 } else {
3375 spin_lock(&ctx->list_lock);
3376 list_del_init(&request->list);
3377 list_add_tail(&request->list, &ctx->pending_list);
3378 spin_unlock(&ctx->list_lock);
Benjamin Chanf8d9a462016-11-08 21:38:10 -05003379 kthread_queue_work(&ctx->work_queue.rot_kw,
Alan Kwongf94a2552016-12-28 09:41:22 -08003380 &request->submit_work);
3381 }
3382 } else if (request && !atomic_read(&request->req->pending_count)) {
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003383 /* if pending request completed, forward to device run state */
3384 SDEDEV_DBG(rot_dev->dev,
3385 "pending request completed in job ready s:%d\n",
3386 ctx->session_id);
3387 ret = 1;
3388 }
3389
3390 return ret;
3391}
3392
3393/* V4l2 mem2mem handlers */
3394static struct v4l2_m2m_ops sde_rotator_m2m_ops = {
3395 .device_run = sde_rotator_device_run,
3396 .job_abort = sde_rotator_job_abort,
3397 .job_ready = sde_rotator_job_ready,
3398};
3399
3400/* Device tree match struct */
3401static const struct of_device_id sde_rotator_dt_match[] = {
3402 {
3403 .compatible = "qcom,sde_rotator",
3404 .data = NULL,
3405 },
3406 {}
3407};
3408
3409/*
3410 * sde_rotator_get_drv_data - rotator device driver data.
3411 * @dev: Pointer to device.
3412 */
3413static const void *sde_rotator_get_drv_data(struct device *dev)
3414{
3415 const struct of_device_id *match;
3416
3417 match = of_match_node(sde_rotator_dt_match, dev->of_node);
3418
3419 if (match)
3420 return match->data;
3421
3422 return NULL;
3423}
3424
3425/*
3426 * sde_rotator_probe - rotator device probe method.
3427 * @pdev: Pointer to rotator platform device.
3428 */
3429static int sde_rotator_probe(struct platform_device *pdev)
3430{
3431 struct sde_rotator_device *rot_dev;
3432 struct video_device *vdev;
3433 int ret;
3434
3435 SDEDEV_DBG(&pdev->dev, "SDE v4l2 rotator probed\n");
3436
3437 /* sde rotator device struct */
3438 rot_dev = kzalloc(sizeof(struct sde_rotator_device), GFP_KERNEL);
3439 if (!rot_dev)
3440 return -ENOMEM;
3441
3442 mutex_init(&rot_dev->lock);
3443 rot_dev->early_submit = SDE_ROTATOR_EARLY_SUBMIT;
3444 rot_dev->fence_timeout = SDE_ROTATOR_FENCE_TIMEOUT;
3445 rot_dev->streamoff_timeout = SDE_ROTATOR_STREAM_OFF_TIMEOUT;
Benjamin Chandbe13112016-09-26 12:10:06 -04003446 rot_dev->min_rot_clk = 0;
3447 rot_dev->min_bw = 0;
3448 rot_dev->min_overhead_us = 0;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003449 rot_dev->drvdata = sde_rotator_get_drv_data(&pdev->dev);
Alan Kwongbfda8b982017-08-01 14:54:34 -04003450 rot_dev->open_timeout = SDE_ROTATOR_CTX_OPEN_TIMEOUT;
3451 init_waitqueue_head(&rot_dev->open_wq);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003452
3453 rot_dev->pdev = pdev;
3454 rot_dev->dev = &pdev->dev;
3455 platform_set_drvdata(pdev, rot_dev);
3456
3457 ret = sde_rotator_base_init(&rot_dev->mdata, pdev, rot_dev->drvdata);
3458 if (ret < 0) {
3459 SDEDEV_ERR(&pdev->dev, "fail init base data %d\n", ret);
3460 goto error_rotator_base_init;
3461 }
3462
3463 ret = sde_rotator_core_init(&rot_dev->mgr, pdev);
3464 if (ret < 0) {
Benjamin Chanc4949de2017-06-21 16:53:15 -04003465 if (ret == -EPROBE_DEFER)
3466 SDEDEV_INFO(&pdev->dev, "probe defer for core init\n");
3467 else
3468 SDEDEV_ERR(&pdev->dev, "fail init core %d\n", ret);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003469 goto error_rotator_core_init;
3470 }
3471
3472 /* mem2mem device */
3473 rot_dev->m2m_dev = v4l2_m2m_init(&sde_rotator_m2m_ops);
3474 if (IS_ERR(rot_dev->m2m_dev)) {
3475 ret = PTR_ERR(rot_dev->m2m_dev);
3476 SDEDEV_ERR(&pdev->dev, "fail init mem2mem device %d\n", ret);
3477 goto error_m2m_init;
3478 }
3479
3480 /* v4l2 device */
3481 ret = v4l2_device_register(&pdev->dev, &rot_dev->v4l2_dev);
3482 if (ret < 0) {
3483 SDEDEV_ERR(&pdev->dev, "fail register v4l2 device %d\n", ret);
3484 goto error_v4l2_register;
3485 }
3486
3487 vdev = video_device_alloc();
3488 if (!vdev) {
3489 SDEDEV_ERR(&pdev->dev, "fail allocate video device\n");
3490 goto error_alloc_video_device;
3491 }
3492
3493 vdev->fops = &sde_rotator_fops;
3494 vdev->ioctl_ops = &sde_rotator_ioctl_ops;
3495 vdev->lock = &rot_dev->lock;
3496 vdev->minor = -1;
3497 vdev->release = video_device_release;
3498 vdev->v4l2_dev = &rot_dev->v4l2_dev;
3499 vdev->vfl_dir = VFL_DIR_M2M;
3500 vdev->vfl_type = VFL_TYPE_GRABBER;
3501 strlcpy(vdev->name, SDE_ROTATOR_DRV_NAME, sizeof(vdev->name));
3502
3503 ret = video_register_device(vdev, VFL_TYPE_GRABBER,
3504 SDE_ROTATOR_BASE_DEVICE_NUMBER);
3505 if (ret < 0) {
3506 SDEDEV_ERR(&pdev->dev, "fail register video device %d\n",
3507 ret);
3508 goto error_video_register;
3509 }
3510
3511 rot_dev->vdev = vdev;
3512 video_set_drvdata(rot_dev->vdev, rot_dev);
3513
3514 rot_dev->debugfs_root = sde_rotator_create_debugfs(rot_dev);
3515
3516 SDEDEV_INFO(&pdev->dev, "SDE v4l2 rotator probe success\n");
3517
3518 return 0;
3519error_video_register:
3520 video_device_release(vdev);
3521error_alloc_video_device:
3522 v4l2_device_unregister(&rot_dev->v4l2_dev);
3523error_v4l2_register:
3524 v4l2_m2m_release(rot_dev->m2m_dev);
3525error_m2m_init:
3526 sde_rotator_core_destroy(rot_dev->mgr);
3527error_rotator_core_init:
3528 sde_rotator_base_destroy(rot_dev->mdata);
3529error_rotator_base_init:
3530 kfree(rot_dev);
3531 return ret;
3532}
3533
3534/*
3535 * sde_rotator_remove - rotator device remove method.
3536 * @pdev: Pointer rotator platform device.
3537 */
3538static int sde_rotator_remove(struct platform_device *pdev)
3539{
3540 struct sde_rotator_device *rot_dev;
3541
3542 rot_dev = platform_get_drvdata(pdev);
3543 if (rot_dev == NULL) {
3544 SDEDEV_ERR(&pdev->dev, "fail get rotator drvdata\n");
3545 return 0;
3546 }
3547
3548 sde_rotator_destroy_debugfs(rot_dev->debugfs_root);
3549 video_unregister_device(rot_dev->vdev);
3550 video_device_release(rot_dev->vdev);
3551 v4l2_device_unregister(&rot_dev->v4l2_dev);
3552 v4l2_m2m_release(rot_dev->m2m_dev);
3553 sde_rotator_core_destroy(rot_dev->mgr);
3554 sde_rotator_base_destroy(rot_dev->mdata);
3555 kfree(rot_dev);
3556 return 0;
3557}
3558
3559static const struct dev_pm_ops sde_rotator_pm_ops = {
3560 SET_SYSTEM_SLEEP_PM_OPS(sde_rotator_pm_suspend, sde_rotator_pm_resume)
3561 SET_RUNTIME_PM_OPS(sde_rotator_runtime_suspend,
3562 sde_rotator_runtime_resume,
3563 sde_rotator_runtime_idle)
3564};
3565
3566/* SDE Rotator platform driver definition */
3567static struct platform_driver rotator_driver = {
3568 .probe = sde_rotator_probe,
3569 .remove = sde_rotator_remove,
3570 .suspend = sde_rotator_suspend,
3571 .resume = sde_rotator_resume,
3572 .driver = {
3573 .name = SDE_ROTATOR_DRV_NAME,
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07003574 .of_match_table = sde_rotator_dt_match,
3575 .pm = &sde_rotator_pm_ops,
3576 },
3577};
3578
3579static int __init sde_rotator_init_module(void)
3580{
3581 return platform_driver_register(&rotator_driver);
3582}
3583
3584static void __exit sde_rotator_exit_module(void)
3585{
3586 platform_driver_unregister(&rotator_driver);
3587}
3588
3589module_init(sde_rotator_init_module);
3590module_exit(sde_rotator_exit_module);
3591MODULE_DESCRIPTION("MSM SDE ROTATOR driver");