Benjamin Chan | 59a0605 | 2017-01-12 18:06:03 -0500 | [diff] [blame] | 1 | /* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2 | * |
| 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 Kwong | 4b41616 | 2017-08-11 21:03:10 -0400 | [diff] [blame] | 12 | #define pr_fmt(fmt) "%s:%d: " fmt, __func__, __LINE__ |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 13 | |
| 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 Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 27 | #include <media/videobuf2-v4l2.h> |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 28 | #include <media/v4l2-mem2mem.h> |
| 29 | |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 30 | #include "sde_rotator_inline.h" |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 31 | #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 Kwong | bfda8b98 | 2017-08-01 14:54:34 -0400 | [diff] [blame] | 49 | /* Timeout (msec) waiting for ctx open */ |
| 50 | #define SDE_ROTATOR_CTX_OPEN_TIMEOUT 500 |
| 51 | |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 52 | /* 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 59 | |
Benjamin Chan | f8d9a46 | 2016-11-08 21:38:10 -0500 | [diff] [blame] | 60 | static void sde_rotator_submit_handler(struct kthread_work *work); |
| 61 | static void sde_rotator_retire_handler(struct kthread_work *work); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 62 | #ifdef CONFIG_COMPAT |
| 63 | static 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 | */ |
| 71 | static 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 78 | * sde_rotator_get_flags_from_ctx - Get low-level command flag |
| 79 | * @ctx: Pointer to rotator context. |
| 80 | */ |
| 81 | static 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 Kulkarni | 298c823 | 2016-09-26 22:32:10 -0700 | [diff] [blame] | 97 | if (ctx->secure_camera) |
| 98 | ret_flags |= SDE_ROTATION_SECURE_CAMERA; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 99 | 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 | */ |
| 111 | static 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 Kwong | 09a36ef | 2016-11-10 01:39:16 -0500 | [diff] [blame] | 130 | |
| 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 149 | } |
| 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 | */ |
| 156 | static 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 Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 164 | item->wb_idx = (ctx->fh.prio >= V4L2_PRIORITY_DEFAULT) ? 0 : 1; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 165 | 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 | */ |
| 200 | static 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; |
| 223 | error_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 | */ |
| 233 | static 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 256 | * @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 | */ |
| 261 | static int sde_rotator_queue_setup(struct vb2_queue *q, |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 262 | unsigned int *num_buffers, unsigned int *num_planes, |
Alan Kwong | 6ce448d | 2016-11-24 18:45:20 -0800 | [diff] [blame] | 263 | unsigned int sizes[], struct device *alloc_devs[]) |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 264 | { |
| 265 | struct sde_rotator_ctx *ctx = vb2_get_drv_priv(q); |
| 266 | int i; |
| 267 | |
| 268 | if (!num_buffers) |
| 269 | return -EINVAL; |
| 270 | |
Alan Kwong | 6ce448d | 2016-11-24 18:45:20 -0800 | [diff] [blame] | 271 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 280 | } |
| 281 | |
| 282 | *num_planes = 1; |
Alan Kwong | 6ce448d | 2016-11-24 18:45:20 -0800 | [diff] [blame] | 283 | alloc_devs[0] = (struct device *)ctx; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 284 | |
| 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 Kwong | 09a36ef | 2016-11-10 01:39:16 -0500 | [diff] [blame] | 293 | for (i = 0; i < ctx->nbuf_out; i++) { |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 294 | ctx->vbinfo_out[i].fd = -1; |
Alan Kwong | 09a36ef | 2016-11-10 01:39:16 -0500 | [diff] [blame] | 295 | ctx->vbinfo_out[i].comp_ratio.numer = 1; |
| 296 | ctx->vbinfo_out[i].comp_ratio.denom = 1; |
| 297 | } |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 298 | 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 Kwong | 09a36ef | 2016-11-10 01:39:16 -0500 | [diff] [blame] | 306 | for (i = 0; i < ctx->nbuf_cap; i++) { |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 307 | ctx->vbinfo_cap[i].fd = -1; |
Alan Kwong | 09a36ef | 2016-11-10 01:39:16 -0500 | [diff] [blame] | 308 | ctx->vbinfo_cap[i].comp_ratio.numer = 1; |
| 309 | ctx->vbinfo_cap[i].comp_ratio.denom = 1; |
| 310 | } |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 311 | 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 | */ |
| 323 | static void sde_rotator_buf_queue(struct vb2_buffer *vb) |
| 324 | { |
| 325 | struct sde_rotator_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); |
Alan Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 326 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 327 | |
Alan Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 328 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 329 | } |
| 330 | |
| 331 | /* |
Alan Kwong | af52909 | 2016-11-03 14:18:41 -0400 | [diff] [blame] | 332 | * 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 | */ |
| 336 | static 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 365 | * 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 | */ |
| 369 | static 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 Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 383 | struct vb2_v4l2_buffer *buf; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 384 | |
Alan Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 385 | while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) { |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 386 | SDEDEV_DBG(rot_dev->dev, |
| 387 | "return vb t:%d i:%d\n", |
Alan Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 388 | buf->vb2_buf.type, |
| 389 | buf->vb2_buf.index); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 390 | v4l2_m2m_buf_done(buf, state); |
| 391 | } |
| 392 | } else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { |
Alan Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 393 | struct vb2_v4l2_buffer *buf; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 394 | |
Alan Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 395 | while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) { |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 396 | SDEDEV_DBG(rot_dev->dev, |
| 397 | "return vb t:%d i:%d\n", |
Alan Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 398 | buf->vb2_buf.type, |
| 399 | buf->vb2_buf.index); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 400 | 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 | */ |
| 412 | static 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 416 | |
| 417 | SDEDEV_DBG(rot_dev->dev, "start streaming s:%d t:%d\n", |
| 418 | ctx->session_id, q->type); |
| 419 | |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 420 | if (!list_empty(&ctx->pending_list)) { |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 421 | SDEDEV_ERR(rot_dev->dev, |
| 422 | "command pending error s:%d t:%d p:%d\n", |
| 423 | ctx->session_id, q->type, |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 424 | !list_empty(&ctx->pending_list)); |
| 425 | return -EINVAL; |
| 426 | } |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 427 | |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 428 | ctx->abort_pending = 0; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 429 | |
| 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 | */ |
| 440 | static 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 Shekhar | 4e29b94 | 2017-04-04 17:37:54 +0530 | [diff] [blame] | 444 | struct sde_rotator_request *request; |
| 445 | struct list_head *curr, *next; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 446 | 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 Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 451 | !list_empty(&ctx->pending_list)); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 452 | ctx->abort_pending = 1; |
| 453 | mutex_unlock(q->lock); |
| 454 | ret = wait_event_timeout(ctx->wait_queue, |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 455 | list_empty(&ctx->pending_list), |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 456 | msecs_to_jiffies(rot_dev->streamoff_timeout)); |
| 457 | mutex_lock(q->lock); |
Benjamin Chan | d0a22cf | 2017-03-01 17:40:20 -0500 | [diff] [blame] | 458 | if (!ret) { |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 459 | SDEDEV_ERR(rot_dev->dev, |
| 460 | "timeout to stream off s:%d t:%d p:%d\n", |
| 461 | ctx->session_id, q->type, |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 462 | !list_empty(&ctx->pending_list)); |
Alan Kwong | de85fcd | 2017-07-31 18:18:49 -0400 | [diff] [blame] | 463 | SDEROT_EVTLOG(ctx->session_id, q->type, |
| 464 | !list_empty(&ctx->pending_list), |
| 465 | SDE_ROT_EVTLOG_ERROR); |
Benjamin Chan | d0a22cf | 2017-03-01 17:40:20 -0500 | [diff] [blame] | 466 | 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 Shekhar | 4e29b94 | 2017-04-04 17:37:54 +0530 | [diff] [blame] | 469 | 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 Chan | f8d9a46 | 2016-11-08 21:38:10 -0500 | [diff] [blame] | 476 | kthread_cancel_work_sync(&request->submit_work); |
| 477 | kthread_cancel_work_sync(&request->retire_work); |
Jayant Shekhar | 4e29b94 | 2017-04-04 17:37:54 +0530 | [diff] [blame] | 478 | 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 Chan | d0a22cf | 2017-03-01 17:40:20 -0500 | [diff] [blame] | 484 | } |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 485 | |
| 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 Chan | 834d21d | 2017-06-15 18:18:54 -0400 | [diff] [blame] | 495 | if (vbinfo->fence) { |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 496 | /* 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 Kwong | 6ce448d | 2016-11-24 18:45:20 -0800 | [diff] [blame] | 523 | static const struct vb2_ops sde_rotator_vb2_q_ops = { |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 524 | .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 Kwong | af52909 | 2016-11-03 14:18:41 -0400 | [diff] [blame] | 530 | .buf_finish = sde_rotator_buf_finish, |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 531 | }; |
| 532 | |
| 533 | /* |
| 534 | * sde_rotator_get_userptr - Map and get buffer handler for user pointer buffer. |
Alan Kwong | 6ce448d | 2016-11-24 18:45:20 -0800 | [diff] [blame] | 535 | * @dev: device allocated in buf_setup. |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 536 | * @vaddr: Virtual addr passed from userpsace (in our case ion fd) |
| 537 | * @size: Size of the buffer |
Alan Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 538 | * @dma_dir: DMA data direction of the given buffer. |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 539 | */ |
Alan Kwong | 6ce448d | 2016-11-24 18:45:20 -0800 | [diff] [blame] | 540 | static void *sde_rotator_get_userptr(struct device *dev, |
Alan Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 541 | unsigned long vaddr, unsigned long size, |
| 542 | enum dma_data_direction dma_dir) |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 543 | { |
Alan Kwong | 6ce448d | 2016-11-24 18:45:20 -0800 | [diff] [blame] | 544 | struct sde_rotator_ctx *ctx = (struct sde_rotator_ctx *)dev; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 545 | struct sde_rotator_device *rot_dev = ctx->rot_dev; |
| 546 | struct sde_rotator_buf_handle *buf; |
Abhijit Kulkarni | 298c823 | 2016-09-26 22:32:10 -0700 | [diff] [blame] | 547 | struct ion_client *iclient = rot_dev->mdata->iclient; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 548 | |
| 549 | buf = kzalloc(sizeof(*buf), GFP_KERNEL); |
| 550 | if (!buf) |
| 551 | return ERR_PTR(-ENOMEM); |
| 552 | |
| 553 | buf->fd = vaddr; |
Abhijit Kulkarni | 298c823 | 2016-09-26 22:32:10 -0700 | [diff] [blame] | 554 | buf->secure = ctx->secure || ctx->secure_camera; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 555 | buf->ctx = ctx; |
| 556 | buf->rot_dev = rot_dev; |
Abhijit Kulkarni | 298c823 | 2016-09-26 22:32:10 -0700 | [diff] [blame] | 557 | if (ctx->secure_camera) { |
Alan Kwong | 6ce448d | 2016-11-24 18:45:20 -0800 | [diff] [blame] | 558 | buf->handle = ion_import_dma_buf_fd(iclient, |
Abhijit Kulkarni | 298c823 | 2016-09-26 22:32:10 -0700 | [diff] [blame] | 559 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 563 | buf->fd, PTR_ERR(buf->buffer)); |
Abhijit Kulkarni | 298c823 | 2016-09-26 22:32:10 -0700 | [diff] [blame] | 564 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 582 | } |
| 583 | |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 584 | return buf; |
Abhijit Kulkarni | 298c823 | 2016-09-26 22:32:10 -0700 | [diff] [blame] | 585 | error_buf_get: |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 586 | 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 | */ |
| 594 | static 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. */ |
| 620 | static 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 | */ |
| 631 | static int sde_rotator_s_ctx_ctrl(struct sde_rotator_ctx *ctx, |
| 632 | s32 *ctx_ctrl, struct v4l2_ctrl *ctrl) |
| 633 | { |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 634 | *ctx_ctrl = ctrl->val; |
Benjamin Chan | dbe1311 | 2016-09-26 12:10:06 -0400 | [diff] [blame] | 635 | return 0; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 636 | } |
| 637 | |
| 638 | /* |
| 639 | * sde_rotator_s_ctrl - Set control. |
| 640 | * @ctrl: Pointer to v4l2 control structure. |
| 641 | */ |
| 642 | static 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 Kulkarni | 298c823 | 2016-09-26 22:32:10 -0700 | [diff] [blame] | 672 | case V4L2_CID_SDE_ROTATOR_SECURE_CAMERA: |
| 673 | ret = sde_rotator_s_ctx_ctrl(ctx, &ctx->secure_camera, ctrl); |
| 674 | break; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 675 | 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 | */ |
| 687 | static 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 | */ |
| 694 | static 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 Kulkarni | 298c823 | 2016-09-26 22:32:10 -0700 | [diff] [blame] | 705 | static 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 716 | /* |
| 717 | * sde_rotator_ctx_show - show context state. |
| 718 | */ |
| 719 | static 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 Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 736 | SPRINT("priority=%d\n", ctx->fh.prio); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 737 | 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 Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 767 | SPRINT("command_pending=%d\n", !list_empty(&ctx->pending_list)); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 768 | 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 | |
| 775 | static struct kobj_attribute sde_rotator_ctx_attr = |
| 776 | __ATTR(state, 0664, sde_rotator_ctx_show, NULL); |
| 777 | |
| 778 | static struct attribute *sde_rotator_fs_attrs[] = { |
| 779 | &sde_rotator_ctx_attr.attr, |
| 780 | NULL |
| 781 | }; |
| 782 | |
| 783 | static 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 | */ |
| 790 | static 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 | */ |
| 804 | static 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 | |
| 815 | static const struct sysfs_ops sde_rotator_fs_ops = { |
| 816 | .show = sde_rotator_fs_show, |
| 817 | .store = sde_rotator_fs_store, |
| 818 | }; |
| 819 | |
| 820 | static 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 | */ |
| 830 | static 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 Kwong | 6ce448d | 2016-11-24 18:45:20 -0800 | [diff] [blame] | 845 | src_vq->dev = ctx->rot_dev->dev; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 846 | |
| 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 Kwong | 6ce448d | 2016-11-24 18:45:20 -0800 | [diff] [blame] | 863 | src_vq->dev = ctx->rot_dev->dev; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 864 | |
| 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 Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 876 | * 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 880 | */ |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 881 | struct sde_rotator_ctx *sde_rotator_ctx_open( |
| 882 | struct sde_rotator_device *rot_dev, struct file *file) |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 883 | { |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 884 | struct video_device *video = file ? video_devdata(file) : NULL; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 885 | struct sde_rotator_ctx *ctx; |
| 886 | struct v4l2_ctrl_handler *ctrl_handler; |
| 887 | char name[32]; |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 888 | int i, ret; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 889 | |
| 890 | if (atomic_read(&rot_dev->mgr->device_suspended)) |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 891 | return ERR_PTR(-EPERM); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 892 | |
| 893 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); |
| 894 | if (!ctx) |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 895 | return ERR_PTR(-ENOMEM); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 896 | |
| 897 | if (mutex_lock_interruptible(&rot_dev->lock)) { |
| 898 | ret = -ERESTARTSYS; |
| 899 | goto error_lock; |
| 900 | } |
| 901 | |
Alan Kwong | bfda8b98 | 2017-08-01 14:54:34 -0400 | [diff] [blame] | 902 | /* 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 925 | ctx->rot_dev = rot_dev; |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 926 | ctx->file = file; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 927 | |
| 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 936 | ctx->secure = 0; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 937 | 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 Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 951 | 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 Chan | f8d9a46 | 2016-11-08 21:38:10 -0500 | [diff] [blame] | 958 | kthread_init_work(&request->submit_work, |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 959 | sde_rotator_submit_handler); |
Benjamin Chan | f8d9a46 | 2016-11-08 21:38:10 -0500 | [diff] [blame] | 960 | kthread_init_work(&request->retire_work, |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 961 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 966 | |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 967 | if (ctx->file) { |
| 968 | v4l2_fh_init(&ctx->fh, video); |
| 969 | file->private_data = &ctx->fh; |
| 970 | v4l2_fh_add(&ctx->fh); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 971 | |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 972 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 978 | } |
| 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 Chan | f8d9a46 | 2016-11-08 21:38:10 -0500 | [diff] [blame] | 997 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1002 | ret = -EPERM; |
Benjamin Chan | f8d9a46 | 2016-11-08 21:38:10 -0500 | [diff] [blame] | 1003 | ctx->work_queue.rot_thread = NULL; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1004 | goto error_alloc_workqueue; |
| 1005 | } |
Benjamin Chan | f8d9a46 | 2016-11-08 21:38:10 -0500 | [diff] [blame] | 1006 | SDEDEV_DBG(ctx->rot_dev->dev, "kthread name=%s\n", name); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1007 | |
| 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 Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1023 | if (ctx->file) { |
Alan Kwong | bfda8b98 | 2017-08-01 14:54:34 -0400 | [diff] [blame] | 1024 | /* Create control */ |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1025 | ctrl_handler = &ctx->ctrl_handler; |
| 1026 | v4l2_ctrl_handler_init(ctrl_handler, 4); |
| 1027 | v4l2_ctrl_new_std(ctrl_handler, |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1028 | &sde_rotator_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0); |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1029 | v4l2_ctrl_new_std(ctrl_handler, |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1030 | &sde_rotator_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1031 | v4l2_ctrl_new_std(ctrl_handler, |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1032 | &sde_rotator_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0); |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1033 | v4l2_ctrl_new_custom(ctrl_handler, |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1034 | &sde_rotator_ctrl_secure, NULL); |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1035 | v4l2_ctrl_new_custom(ctrl_handler, |
Abhijit Kulkarni | 298c823 | 2016-09-26 22:32:10 -0700 | [diff] [blame] | 1036 | &sde_rotator_ctrl_secure_camera, NULL); |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1037 | 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 Kwong | bfda8b98 | 2017-08-01 14:54:34 -0400 | [diff] [blame] | 1044 | } 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1050 | } |
Alan Kwong | bfda8b98 | 2017-08-01 14:54:34 -0400 | [diff] [blame] | 1051 | |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1052 | 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 Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1058 | return ctx; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1059 | error_ctrl_handler: |
| 1060 | error_open_session: |
| 1061 | sde_rot_mgr_unlock(rot_dev->mgr); |
| 1062 | sde_rotator_destroy_timeline(ctx->work_queue.timeline); |
Benjamin Chan | f8d9a46 | 2016-11-08 21:38:10 -0500 | [diff] [blame] | 1063 | kthread_flush_worker(&ctx->work_queue.rot_kw); |
| 1064 | kthread_stop(ctx->work_queue.rot_thread); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1065 | error_alloc_workqueue: |
| 1066 | sysfs_remove_group(&ctx->kobj, &sde_rotator_fs_attr_group); |
| 1067 | error_create_sysfs: |
| 1068 | kobject_put(&ctx->kobj); |
| 1069 | error_kobj_init: |
| 1070 | error_m2m_init: |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1071 | if (ctx->file) { |
| 1072 | v4l2_fh_del(&ctx->fh); |
| 1073 | v4l2_fh_exit(&ctx->fh); |
| 1074 | } |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1075 | mutex_unlock(&rot_dev->lock); |
| 1076 | error_lock: |
| 1077 | kfree(ctx); |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1078 | return ERR_PTR(ret); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1079 | } |
| 1080 | |
| 1081 | /* |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1082 | * 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1086 | */ |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1087 | static int sde_rotator_ctx_release(struct sde_rotator_ctx *ctx, |
| 1088 | struct file *file) |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1089 | { |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1090 | struct sde_rotator_device *rot_dev = ctx->rot_dev; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1091 | u32 session_id = ctx->session_id; |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 1092 | struct list_head *curr, *next; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1093 | |
| 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 Kwong | bfda8b98 | 2017-08-01 14:54:34 -0400 | [diff] [blame] | 1098 | 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 Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1104 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1112 | mutex_unlock(&rot_dev->lock); |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 1113 | 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 Chan | f8d9a46 | 2016-11-08 21:38:10 -0500 | [diff] [blame] | 1120 | kthread_cancel_work_sync(&request->submit_work); |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 1121 | } |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1122 | 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 Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 1126 | 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 Chan | f8d9a46 | 2016-11-08 21:38:10 -0500 | [diff] [blame] | 1133 | kthread_cancel_work_sync(&request->retire_work); |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 1134 | } |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1135 | 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 Chan | f8d9a46 | 2016-11-08 21:38:10 -0500 | [diff] [blame] | 1138 | kthread_flush_worker(&ctx->work_queue.rot_kw); |
| 1139 | kthread_stop(ctx->work_queue.rot_thread); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1140 | sysfs_remove_group(&ctx->kobj, &sde_rotator_fs_attr_group); |
| 1141 | kobject_put(&ctx->kobj); |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1142 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1147 | kfree(ctx->vbinfo_out); |
| 1148 | kfree(ctx->vbinfo_cap); |
| 1149 | kfree(ctx); |
Alan Kwong | bfda8b98 | 2017-08-01 14:54:34 -0400 | [diff] [blame] | 1150 | wake_up_interruptible(&rot_dev->open_wq); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1151 | 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 Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 1157 | * 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 | */ |
| 1161 | static void sde_rotator_update_retire_sequence( |
| 1162 | struct sde_rotator_request *request) |
| 1163 | { |
| 1164 | struct sde_rotator_ctx *ctx; |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 1165 | |
| 1166 | if (!request || !request->ctx) { |
| 1167 | SDEROT_ERR("invalid parameters\n"); |
| 1168 | return; |
| 1169 | } |
| 1170 | |
| 1171 | ctx = request->ctx; |
Alan Kwong | 3ddf48c | 2017-10-06 10:45:41 -0400 | [diff] [blame] | 1172 | ctx->retired_sequence_id = request->sequence_id; |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 1173 | |
| 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 | */ |
| 1185 | static 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 Kwong | 3ddf48c | 2017-10-06 10:45:41 -0400 | [diff] [blame] | 1197 | request->sequence_id = 0; |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1198 | request->committed = false; |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 1199 | 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 Kwong | 49311e8 | 2017-11-20 18:11:29 -0500 | [diff] [blame] | 1204 | wake_up(&ctx->wait_queue); |
| 1205 | |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 1206 | SDEROT_DBG("retire request s:%d.%d\n", |
| 1207 | ctx->session_id, ctx->retired_sequence_id); |
| 1208 | } |
| 1209 | |
| 1210 | /* |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1211 | * sde_rotator_is_request_retired - Return true if given request already expired |
| 1212 | * @request: Pointer to rotator request |
| 1213 | */ |
| 1214 | static bool sde_rotator_is_request_retired(struct sde_rotator_request *request) |
| 1215 | { |
| 1216 | struct sde_rotator_ctx *ctx; |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1217 | u32 sequence_id; |
| 1218 | s32 retire_delta; |
| 1219 | |
Alan Kwong | 3ddf48c | 2017-10-06 10:45:41 -0400 | [diff] [blame] | 1220 | if (!request || !request->ctx) |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1221 | return true; |
| 1222 | |
| 1223 | ctx = request->ctx; |
Alan Kwong | 3ddf48c | 2017-10-06 10:45:41 -0400 | [diff] [blame] | 1224 | sequence_id = request->sequence_id; |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1225 | |
| 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 | */ |
| 1239 | void *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 | |
| 1289 | activate_error: |
| 1290 | llcc_slice_putd(ctx->slice); |
| 1291 | ctx->slice = NULL; |
| 1292 | slice_getd_error: |
| 1293 | sde_rotator_ctx_release(ctx, NULL); |
| 1294 | rotator_open_error: |
| 1295 | return ERR_PTR(rc); |
| 1296 | } |
| 1297 | EXPORT_SYMBOL(sde_rotator_inline_open); |
| 1298 | |
| 1299 | int 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 | } |
| 1328 | EXPORT_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 | */ |
| 1337 | int sde_rotator_inline_get_dst_pixfmt(struct platform_device *pdev, |
| 1338 | u32 src_pixfmt, u32 *dst_pixfmt) |
| 1339 | { |
Alan Kwong | d12a481 | 2017-11-30 16:12:57 -0500 | [diff] [blame] | 1340 | 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 Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1357 | } |
| 1358 | EXPORT_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 | */ |
| 1367 | int 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 | } |
| 1390 | EXPORT_SYMBOL(sde_rotator_inline_get_downscale_caps); |
| 1391 | |
| 1392 | /* |
Alan Kwong | b6c049c | 2017-03-31 12:50:27 -0700 | [diff] [blame] | 1393 | * sde_rotator_inline_get_maxlinewidth - get maximum line width of rotator |
| 1394 | * @pdev: Pointer to platform device |
| 1395 | * return: maximum line width |
| 1396 | */ |
| 1397 | int 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 | } |
| 1419 | EXPORT_SYMBOL(sde_rotator_inline_get_maxlinewidth); |
| 1420 | |
| 1421 | /* |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1422 | * 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 | */ |
| 1428 | int 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 Kwong | 4b41616 | 2017-08-11 21:03:10 -0400 | [diff] [blame] | 1447 | pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, input, |
| 1448 | SDE_ROTATOR_MODE_SBUF); |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1449 | 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 | } |
| 1458 | EXPORT_SYMBOL(sde_rotator_inline_get_pixfmt_caps); |
| 1459 | |
| 1460 | /* |
Clarence Ip | d59419e | 2017-11-15 16:42:45 -0500 | [diff] [blame] | 1461 | * _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 | */ |
| 1467 | static 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 Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1516 | * 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 | */ |
| 1522 | int 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 Kwong | 871fc48 | 2017-09-20 11:17:28 -0400 | [diff] [blame] | 1529 | struct sde_rotation_config rotcfg; |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1530 | ktime_t *ts; |
| 1531 | u32 flags = 0; |
Alan Kwong | 871fc48 | 2017-09-20 11:17:28 -0400 | [diff] [blame] | 1532 | int i, ret = 0; |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1533 | |
| 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 Ip | d59419e | 2017-11-15 16:42:45 -0500 | [diff] [blame] | 1542 | if (!rot_dev || !rot_dev->mgr) { |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1543 | SDEROT_ERR("invalid rotator device\n"); |
| 1544 | return -EINVAL; |
| 1545 | } |
| 1546 | |
| 1547 | SDEROT_DBG( |
Alan Kwong | 1513d3d | 2017-08-27 21:20:01 -0400 | [diff] [blame] | 1548 | "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 Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1549 | 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 Kwong | 1513d3d | 2017-08-27 21:20:01 -0400 | [diff] [blame] | 1560 | cmd->clkrate, cmd->data_bw, cmd->prefill_bw, |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1561 | cmd->dst_writeback, cmd->video_mode, cmd_type); |
Alan Kwong | f366a01 | 2017-02-10 20:54:46 -0800 | [diff] [blame] | 1562 | 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 Kwong | f366a01 | 2017-02-10 20:54:46 -0800 | [diff] [blame] | 1565 | cmd->src_pixfmt, |
Alan Kwong | f366a01 | 2017-02-10 20:54:46 -0800 | [diff] [blame] | 1566 | cmd->dst_rect_w, cmd->dst_rect_h, |
| 1567 | cmd->dst_pixfmt, |
Alan Kwong | 1513d3d | 2017-08-27 21:20:01 -0400 | [diff] [blame] | 1568 | cmd->fps, cmd->clkrate, cmd->data_bw, cmd->prefill_bw, |
Alan Kwong | de85fcd | 2017-07-31 18:18:49 -0400 | [diff] [blame] | 1569 | (cmd->rot90 << 0) | (cmd->hflip << 1) | (cmd->vflip << 2) | |
| 1570 | (cmd->secure << 3) | (cmd->dst_writeback << 4) | |
Alan Kwong | 1513d3d | 2017-08-27 21:20:01 -0400 | [diff] [blame] | 1571 | (cmd->video_mode << 5) | |
| 1572 | (cmd_type << 24)); |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1573 | |
Clarence Ip | d59419e | 2017-11-15 16:42:45 -0500 | [diff] [blame] | 1574 | mutex_lock(&rot_dev->lock); |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1575 | 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 Ip | b25c65c | 2017-05-17 12:09:23 -0400 | [diff] [blame] | 1585 | ts = stats->ts[stats->count % SDE_ROTATOR_NUM_EVENTS]; |
| 1586 | if (cmd_type == SDE_ROTATOR_INLINE_CMD_COMMIT) |
| 1587 | stats->count++; |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1588 | |
| 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 Kwong | f366a01 | 2017-02-10 20:54:46 -0800 | [diff] [blame] | 1598 | flags |= SDE_ROTATION_EXT_PERF; |
| 1599 | |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1600 | /* 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 Kwong | 498d59f | 2017-02-11 18:56:34 -0800 | [diff] [blame] | 1605 | item.prefill_bw = cmd->prefill_bw; |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1606 | 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 Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1655 | |
Alan Kwong | 871fc48 | 2017-09-20 11:17:28 -0400 | [diff] [blame] | 1656 | /* initialize session configuration */ |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1657 | memset(&rotcfg, 0, sizeof(struct sde_rotation_config)); |
| 1658 | rotcfg.flags = flags; |
| 1659 | rotcfg.frame_rate = cmd->fps; |
Alan Kwong | f366a01 | 2017-02-10 20:54:46 -0800 | [diff] [blame] | 1660 | rotcfg.clk_rate = cmd->clkrate; |
| 1661 | rotcfg.data_bw = cmd->data_bw; |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1662 | 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 Kwong | 871fc48 | 2017-09-20 11:17:28 -0400 | [diff] [blame] | 1674 | } |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1675 | |
Alan Kwong | 871fc48 | 2017-09-20 11:17:28 -0400 | [diff] [blame] | 1676 | if (cmd_type == SDE_ROTATOR_INLINE_CMD_VALIDATE) { |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1677 | |
Alan Kwong | 871fc48 | 2017-09-20 11:17:28 -0400 | [diff] [blame] | 1678 | ret = sde_rotator_session_validate(rot_dev->mgr, |
| 1679 | ctx->private, &rotcfg); |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1680 | if (ret) { |
Alan Kwong | 871fc48 | 2017-09-20 11:17:28 -0400 | [diff] [blame] | 1681 | SDEROT_WARN("fail session validation s:%d\n", |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1682 | ctx->session_id); |
Alan Kwong | 871fc48 | 2017-09-20 11:17:28 -0400 | [diff] [blame] | 1683 | goto error_session_validate; |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1684 | } |
| 1685 | |
| 1686 | devm_kfree(rot_dev->dev, req); |
| 1687 | req = NULL; |
| 1688 | |
| 1689 | } else if (cmd_type == SDE_ROTATOR_INLINE_CMD_COMMIT) { |
| 1690 | |
Alan Kwong | 871fc48 | 2017-09-20 11:17:28 -0400 | [diff] [blame] | 1691 | 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 Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1703 | 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 Kwong | 3ddf48c | 2017-10-06 10:45:41 -0400 | [diff] [blame] | 1713 | request->sequence_id = req->entries[0].item.sequence_id; |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1714 | |
| 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 Chan | f8d9a46 | 2016-11-08 21:38:10 -0500 | [diff] [blame] | 1728 | req->retire_kw = &ctx->work_queue.rot_kw; |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1729 | 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 Ip | 3ce07c0 | 2017-08-11 16:21:45 -0400 | [diff] [blame] | 1758 | sde_rotator_req_reset_start(rot_dev->mgr, req); |
Clarence Ip | 618de0a | 2017-05-17 12:10:47 -0400 | [diff] [blame] | 1759 | |
Clarence Ip | 3ce07c0 | 2017-08-11 16:21:45 -0400 | [diff] [blame] | 1760 | sde_rotator_queue_request(rot_dev->mgr, ctx->private, req); |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1761 | |
| 1762 | request->committed = true; |
| 1763 | |
| 1764 | /* save request in private handle */ |
| 1765 | cmd->priv_handle = request; |
| 1766 | |
Clarence Ip | b25c65c | 2017-05-17 12:09:23 -0400 | [diff] [blame] | 1767 | } 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 Ip | 3ce07c0 | 2017-08-11 16:21:45 -0400 | [diff] [blame] | 1775 | sde_rotator_req_set_start(rot_dev->mgr, request->req); |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1776 | } 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 Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1784 | |
Clarence Ip | d59419e | 2017-11-15 16:42:45 -0500 | [diff] [blame] | 1785 | /* 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 Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1788 | |
Clarence Ip | 3407900 | 2017-11-09 16:15:33 -0500 | [diff] [blame] | 1789 | cmd->priv_handle = NULL; |
Clarence Ip | 19339b3 | 2017-10-14 20:59:00 -0400 | [diff] [blame] | 1790 | } 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 Ip | 3407900 | 2017-11-09 16:15:33 -0500 | [diff] [blame] | 1798 | if (!sde_rotator_is_request_retired(request)) |
| 1799 | sde_rotator_abort_inline_request(rot_dev->mgr, |
| 1800 | ctx->private, request->req); |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1801 | } |
| 1802 | |
| 1803 | sde_rot_mgr_unlock(rot_dev->mgr); |
Clarence Ip | d59419e | 2017-11-15 16:42:45 -0500 | [diff] [blame] | 1804 | mutex_unlock(&rot_dev->lock); |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1805 | return 0; |
| 1806 | |
| 1807 | error_handle_request: |
| 1808 | sde_rotator_update_retire_sequence(request); |
| 1809 | sde_rotator_retire_request(request); |
| 1810 | error_retired_list: |
Alan Kwong | 871fc48 | 2017-09-20 11:17:28 -0400 | [diff] [blame] | 1811 | error_session_validate: |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1812 | error_session_config: |
| 1813 | devm_kfree(rot_dev->dev, req); |
| 1814 | error_invalid_handle: |
| 1815 | error_init_request: |
| 1816 | sde_rot_mgr_unlock(rot_dev->mgr); |
Clarence Ip | d59419e | 2017-11-15 16:42:45 -0500 | [diff] [blame] | 1817 | mutex_unlock(&rot_dev->lock); |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1818 | return ret; |
| 1819 | } |
| 1820 | EXPORT_SYMBOL(sde_rotator_inline_commit); |
| 1821 | |
Alan Kwong | de85fcd | 2017-07-31 18:18:49 -0400 | [diff] [blame] | 1822 | void sde_rotator_inline_reg_dump(struct platform_device *pdev) |
| 1823 | { |
Clarence Ip | cd14029 | 2017-09-22 16:24:08 -0400 | [diff] [blame] | 1824 | 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 Kwong | de85fcd | 2017-07-31 18:18:49 -0400 | [diff] [blame] | 1840 | } |
| 1841 | EXPORT_SYMBOL(sde_rotator_inline_reg_dump); |
| 1842 | |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 1843 | /* |
| 1844 | * sde_rotator_open - Rotator device open method. |
| 1845 | * @file: Pointer to file struct. |
| 1846 | */ |
| 1847 | static 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 | */ |
| 1866 | static 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1875 | * sde_rotator_poll - rotator device pool method. |
| 1876 | * @file: Pointer to file struct. |
| 1877 | * @wait: Pointer to poll table struct. |
| 1878 | */ |
| 1879 | static 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 Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 1888 | ret = v4l2_m2m_poll(file, ctx->fh.m2m_ctx, wait); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1889 | mutex_unlock(&rot_dev->lock); |
| 1890 | return ret; |
| 1891 | } |
| 1892 | |
| 1893 | /* rotator device file operations callbacks */ |
| 1894 | static 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 | */ |
| 1911 | static 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 Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 1917 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1920 | |
| 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 | */ |
| 1930 | static int sde_rotator_enum_fmt_vid_cap(struct file *file, |
| 1931 | void *fh, struct v4l2_fmtdesc *f) |
| 1932 | { |
Alan Kwong | da16e44 | 2016-08-14 20:47:18 -0400 | [diff] [blame] | 1933 | 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 Kwong | 2c7cc25 | 2016-12-28 12:21:00 -0800 | [diff] [blame] | 1936 | u32 i, index, pixfmt; |
| 1937 | bool found = false; |
Alan Kwong | da16e44 | 2016-08-14 20:47:18 -0400 | [diff] [blame] | 1938 | |
Alan Kwong | 2c7cc25 | 2016-12-28 12:21:00 -0800 | [diff] [blame] | 1939 | for (i = 0, index = 0; index <= f->index; i++) { |
Alan Kwong | 4b41616 | 2017-08-11 21:03:10 -0400 | [diff] [blame] | 1940 | pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, false, |
| 1941 | SDE_ROTATOR_MODE_OFFLINE); |
Alan Kwong | 2c7cc25 | 2016-12-28 12:21:00 -0800 | [diff] [blame] | 1942 | if (!pixfmt) |
| 1943 | return -EINVAL; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1944 | |
Alan Kwong | 2c7cc25 | 2016-12-28 12:21:00 -0800 | [diff] [blame] | 1945 | 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 Kwong | da16e44 | 2016-08-14 20:47:18 -0400 | [diff] [blame] | 1961 | return -EINVAL; |
| 1962 | |
| 1963 | f->pixelformat = pixfmt; |
| 1964 | strlcpy(f->description, fmt->description, sizeof(f->description)); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1965 | |
| 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 | */ |
| 1975 | static int sde_rotator_enum_fmt_vid_out(struct file *file, |
| 1976 | void *fh, struct v4l2_fmtdesc *f) |
| 1977 | { |
Alan Kwong | da16e44 | 2016-08-14 20:47:18 -0400 | [diff] [blame] | 1978 | 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 Kwong | 2c7cc25 | 2016-12-28 12:21:00 -0800 | [diff] [blame] | 1981 | u32 i, index, pixfmt; |
| 1982 | bool found = false; |
Alan Kwong | da16e44 | 2016-08-14 20:47:18 -0400 | [diff] [blame] | 1983 | |
Alan Kwong | 2c7cc25 | 2016-12-28 12:21:00 -0800 | [diff] [blame] | 1984 | for (i = 0, index = 0; index <= f->index; i++) { |
Alan Kwong | 4b41616 | 2017-08-11 21:03:10 -0400 | [diff] [blame] | 1985 | pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, true, |
| 1986 | SDE_ROTATOR_MODE_OFFLINE); |
Alan Kwong | 2c7cc25 | 2016-12-28 12:21:00 -0800 | [diff] [blame] | 1987 | if (!pixfmt) |
| 1988 | return -EINVAL; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 1989 | |
Alan Kwong | 2c7cc25 | 2016-12-28 12:21:00 -0800 | [diff] [blame] | 1990 | 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 Kwong | da16e44 | 2016-08-14 20:47:18 -0400 | [diff] [blame] | 2006 | return -EINVAL; |
| 2007 | |
| 2008 | f->pixelformat = pixfmt; |
| 2009 | strlcpy(f->description, fmt->description, sizeof(f->description)); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2010 | |
| 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 | */ |
| 2020 | static 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 | */ |
| 2036 | static 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 | */ |
| 2052 | static 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2058 | int ret; |
| 2059 | |
Benjamin Chan | b1be8db | 2016-10-06 17:36:48 -0400 | [diff] [blame] | 2060 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2067 | 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 Chan | 59a0605 | 2017-01-12 18:06:03 -0500 | [diff] [blame] | 2072 | config.flags |= SDE_ROTATION_VERIFY_INPUT_ONLY; |
| 2073 | ret = sde_rotator_verify_config_output(rot_dev->mgr, &config); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2074 | 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 Chan | 59a0605 | 2017-01-12 18:06:03 -0500 | [diff] [blame] | 2090 | return ret; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2091 | } |
| 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 | */ |
| 2099 | static 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2105 | int ret; |
| 2106 | |
Benjamin Chan | b1be8db | 2016-10-06 17:36:48 -0400 | [diff] [blame] | 2107 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2114 | 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 Chan | 59a0605 | 2017-01-12 18:06:03 -0500 | [diff] [blame] | 2120 | ret = sde_rotator_verify_config_input(rot_dev->mgr, &config); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2121 | 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 Chan | 59a0605 | 2017-01-12 18:06:03 -0500 | [diff] [blame] | 2137 | return ret; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2138 | } |
| 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 | */ |
| 2146 | static 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2151 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2172 | 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 | */ |
| 2181 | static 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 | */ |
| 2216 | static 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 Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 2221 | return v4l2_m2m_reqbufs(file, ctx->fh.m2m_ctx, req); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2222 | } |
| 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 | */ |
| 2230 | static 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 Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 2261 | ret = v4l2_m2m_qbuf(file, ctx->fh.m2m_ctx, buf); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2262 | 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 Chan | fa08237 | 2017-09-19 17:19:28 -0400 | [diff] [blame] | 2265 | SDEROT_EVTLOG(buf->type, buf->bytesused, buf->length, buf->m.fd, ret); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2266 | |
| 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 | */ |
| 2276 | static 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 Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 2282 | ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2283 | |
| 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 Chan | 834d21d | 2017-06-15 18:18:54 -0400 | [diff] [blame] | 2296 | if (ctx->vbinfo_cap[idx].fence) { |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2297 | /* 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 | */ |
| 2328 | static 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 Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 2333 | return v4l2_m2m_querybuf(file, ctx->fh.m2m_ctx, buf); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2334 | } |
| 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 | */ |
| 2342 | static 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 Kwong | 360f01b | 2016-12-22 08:34:43 -0800 | [diff] [blame] | 2346 | struct sde_rotator_device *rot_dev = ctx->rot_dev; |
| 2347 | struct sde_rotation_config config; |
| 2348 | struct vb2_queue *vq; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2349 | 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 Kwong | 360f01b | 2016-12-22 08:34:43 -0800 | [diff] [blame] | 2354 | 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 Chan | 59a0605 | 2017-01-12 18:06:03 -0500 | [diff] [blame] | 2368 | config.flags &= ~SDE_ROTATION_VERIFY_INPUT_ONLY; |
Alan Kwong | 360f01b | 2016-12-22 08:34:43 -0800 | [diff] [blame] | 2369 | 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 Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 2378 | ctx->rotcfg = config; |
Alan Kwong | 360f01b | 2016-12-22 08:34:43 -0800 | [diff] [blame] | 2379 | } |
| 2380 | |
Alan Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 2381 | ret = v4l2_m2m_streamon(file, ctx->fh.m2m_ctx, buf_type); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2382 | 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 | */ |
| 2395 | static 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 Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 2404 | ret = v4l2_m2m_streamoff(file, ctx->fh.m2m_ctx, buf_type); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2405 | 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 | */ |
| 2418 | static 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 Chan | fa08237 | 2017-09-19 17:19:28 -0400 | [diff] [blame] | 2448 | SDEROT_EVTLOG(format->fmt.pix.width, format->fmt.pix.height, a->type); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2449 | 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 | */ |
| 2458 | static 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 | */ |
| 2482 | static 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2487 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2559 | 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 | */ |
| 2568 | static 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 | */ |
| 2592 | static 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2610 | * 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 | */ |
| 2617 | static 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 Kwong | 09a36ef | 2016-11-10 01:39:16 -0500 | [diff] [blame] | 2624 | struct msm_sde_rotator_comp_ratio *comp_ratio = arg; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2625 | struct sde_rotator_vbinfo *vbinfo; |
Benjamin Chan | 834d21d | 2017-06-15 18:18:54 -0400 | [diff] [blame] | 2626 | int ret; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2627 | |
| 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 Chan | 834d21d | 2017-06-15 18:18:54 -0400 | [diff] [blame] | 2685 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2691 | SDEDEV_ERR(rot_dev->dev, |
Benjamin Chan | 834d21d | 2017-06-15 18:18:54 -0400 | [diff] [blame] | 2692 | "fail get fence fd s:%d\n", |
| 2693 | ctx->session_id); |
| 2694 | return ret; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2695 | } |
Benjamin Chan | 834d21d | 2017-06-15 18:18:54 -0400 | [diff] [blame] | 2696 | |
| 2697 | /** |
Benjamin Chan | 834d21d | 2017-06-15 18:18:54 -0400 | [diff] [blame] | 2698 | * 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2709 | } |
| 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 Kwong | 09a36ef | 2016-11-10 01:39:16 -0500 | [diff] [blame] | 2717 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2763 | 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 | */ |
| 2778 | static long sde_rotator_compat_ioctl32(struct file *file, |
| 2779 | unsigned int cmd, unsigned long arg) |
| 2780 | { |
Benjamin Chan | 87b81d5 | 2017-03-21 14:21:41 -0400 | [diff] [blame] | 2781 | struct video_device *vdev = video_devdata(file); |
| 2782 | struct sde_rotator_ctx *ctx = |
| 2783 | sde_rotator_ctx_from_fh(file->private_data); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2784 | long ret; |
| 2785 | |
Benjamin Chan | 87b81d5 | 2017-03-21 14:21:41 -0400 | [diff] [blame] | 2786 | mutex_lock(vdev->lock); |
| 2787 | |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2788 | 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 Chan | 87b81d5 | 2017-03-21 14:21:41 -0400 | [diff] [blame] | 2796 | goto ioctl32_error; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2797 | |
| 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 Chan | 87b81d5 | 2017-03-21 14:21:41 -0400 | [diff] [blame] | 2803 | goto ioctl32_error; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2804 | |
| 2805 | break; |
| 2806 | } |
Alan Kwong | 09a36ef | 2016-11-10 01:39:16 -0500 | [diff] [blame] | 2807 | 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 Chan | 87b81d5 | 2017-03-21 14:21:41 -0400 | [diff] [blame] | 2814 | goto ioctl32_error; |
Alan Kwong | 09a36ef | 2016-11-10 01:39:16 -0500 | [diff] [blame] | 2815 | |
| 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 Chan | 87b81d5 | 2017-03-21 14:21:41 -0400 | [diff] [blame] | 2821 | goto ioctl32_error; |
Alan Kwong | 09a36ef | 2016-11-10 01:39:16 -0500 | [diff] [blame] | 2822 | |
| 2823 | break; |
| 2824 | } |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2825 | default: |
Benjamin Chan | 87b81d5 | 2017-03-21 14:21:41 -0400 | [diff] [blame] | 2826 | SDEDEV_ERR(ctx->rot_dev->dev, "invalid ioctl32 type:%x\n", cmd); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2827 | ret = -ENOIOCTLCMD; |
| 2828 | break; |
| 2829 | |
| 2830 | } |
| 2831 | |
Benjamin Chan | 87b81d5 | 2017-03-21 14:21:41 -0400 | [diff] [blame] | 2832 | mutex_unlock(vdev->lock); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2833 | return ret; |
Benjamin Chan | 87b81d5 | 2017-03-21 14:21:41 -0400 | [diff] [blame] | 2834 | |
| 2835 | ioctl32_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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2839 | } |
| 2840 | #endif |
| 2841 | |
Alan Kwong | 915ac41 | 2017-10-12 11:49:55 -0400 | [diff] [blame] | 2842 | static int sde_rotator_ctrl_subscribe_event(struct v4l2_fh *fh, |
| 2843 | const struct v4l2_event_subscription *sub) |
| 2844 | { |
| 2845 | return -EINVAL; |
| 2846 | } |
| 2847 | |
| 2848 | static int sde_rotator_event_unsubscribe(struct v4l2_fh *fh, |
| 2849 | const struct v4l2_event_subscription *sub) |
| 2850 | { |
| 2851 | return -EINVAL; |
| 2852 | } |
| 2853 | |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2854 | /* V4l2 ioctl handlers */ |
| 2855 | static 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2876 | .vidioc_default = sde_rotator_private_ioctl, |
| 2877 | .vidioc_log_status = v4l2_ctrl_log_status, |
Alan Kwong | 915ac41 | 2017-10-12 11:49:55 -0400 | [diff] [blame] | 2878 | .vidioc_subscribe_event = sde_rotator_ctrl_subscribe_event, |
| 2879 | .vidioc_unsubscribe_event = sde_rotator_event_unsubscribe, |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2880 | }; |
| 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 Chan | f8d9a46 | 2016-11-08 21:38:10 -0500 | [diff] [blame] | 2888 | static void sde_rotator_retire_handler(struct kthread_work *work) |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2889 | { |
Alan Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 2890 | struct vb2_v4l2_buffer *src_buf; |
| 2891 | struct vb2_v4l2_buffer *dst_buf; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2892 | struct sde_rotator_ctx *ctx; |
| 2893 | struct sde_rotator_device *rot_dev; |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 2894 | struct sde_rotator_request *request; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2895 | |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 2896 | request = container_of(work, struct sde_rotator_request, retire_work); |
| 2897 | ctx = request->ctx; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2898 | |
| 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 Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 2912 | sde_rotator_update_retire_sequence(request); |
| 2913 | sde_rotator_retire_request(request); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2914 | mutex_unlock(&rot_dev->lock); |
| 2915 | return; |
| 2916 | } |
| 2917 | |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 2918 | if (!ctx->file) { |
| 2919 | sde_rotator_update_retire_sequence(request); |
| 2920 | } else if (rot_dev->early_submit) { |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 2921 | if (IS_ERR_OR_NULL(request->req)) { |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2922 | /* 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 Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 2929 | v4l2_m2m_try_schedule(ctx->fh.m2m_ctx); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2930 | } else { |
| 2931 | /* no pending request. acknowledge the usual way. */ |
Alan Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 2932 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2934 | |
| 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 Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 2942 | sde_rotator_update_retire_sequence(request); |
| 2943 | sde_rotator_retire_request(request); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2944 | v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); |
| 2945 | v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); |
Alan Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 2946 | v4l2_m2m_job_finish(rot_dev->m2m_dev, ctx->fh.m2m_ctx); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2947 | } |
| 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 Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 2956 | * @request: Pointer to rotator request |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2957 | */ |
| 2958 | static int sde_rotator_process_buffers(struct sde_rotator_ctx *ctx, |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 2959 | struct vb2_buffer *src_buf, struct vb2_buffer *dst_buf, |
| 2960 | struct sde_rotator_request *request) |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2961 | { |
| 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 Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 2988 | vbinfo_out = &ctx->vbinfo_out[src_buf->index]; |
| 2989 | vbinfo_cap = &ctx->vbinfo_cap[dst_buf->index]; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2990 | |
| 2991 | SDEDEV_DBG(rot_dev->dev, |
Alan Kwong | 09a36ef | 2016-11-10 01:39:16 -0500 | [diff] [blame] | 2992 | "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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 2993 | 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 Kwong | 09a36ef | 2016-11-10 01:39:16 -0500 | [diff] [blame] | 2998 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3001 | |
| 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 Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 3013 | ctx->fh.prio, |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3014 | (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 Kwong | de85fcd | 2017-07-31 18:18:49 -0400 | [diff] [blame] | 3043 | SDEROT_EVTLOG(ctx->session_id, vbinfo_cap->fence_ts, |
| 3044 | vbinfo_out->fd, ret, |
| 3045 | SDE_ROT_EVTLOG_ERROR); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3046 | 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 Kulkarni | 298c823 | 2016-09-26 22:32:10 -0700 | [diff] [blame] | 3058 | item.input.planes[0].handle = src_handle->handle; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3059 | 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 Kwong | 09a36ef | 2016-11-10 01:39:16 -0500 | [diff] [blame] | 3063 | item.input.comp_ratio = vbinfo_out->comp_ratio; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3064 | item.output.planes[0].buffer = dst_handle->buffer; |
Abhijit Kulkarni | 298c823 | 2016-09-26 22:32:10 -0700 | [diff] [blame] | 3065 | item.output.planes[0].handle = dst_handle->handle; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3066 | 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 Kwong | 09a36ef | 2016-11-10 01:39:16 -0500 | [diff] [blame] | 3070 | item.output.comp_ratio = vbinfo_cap->comp_ratio; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3071 | 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 Chan | f8d9a46 | 2016-11-08 21:38:10 -0500 | [diff] [blame] | 3081 | req->retire_kw = &ctx->work_queue.rot_kw; |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3082 | req->retire_work = &request->retire_work; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3083 | |
| 3084 | ret = sde_rotator_handle_request_common( |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3085 | rot_dev->mgr, ctx->private, req); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3086 | 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 Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3092 | request->req = req; |
Alan Kwong | 3ddf48c | 2017-10-06 10:45:41 -0400 | [diff] [blame] | 3093 | request->sequence_id = item.sequence_id; |
| 3094 | request->committed = true; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3095 | |
| 3096 | return 0; |
| 3097 | error_handle_request: |
| 3098 | devm_kfree(rot_dev->dev, req); |
| 3099 | error_init_request: |
| 3100 | error_fence_wait: |
| 3101 | error_null_buffer: |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3102 | request->req = NULL; |
Alan Kwong | 3ddf48c | 2017-10-06 10:45:41 -0400 | [diff] [blame] | 3103 | request->sequence_id = 0; |
| 3104 | request->committed = false; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3105 | 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 Chan | f8d9a46 | 2016-11-08 21:38:10 -0500 | [diff] [blame] | 3114 | static void sde_rotator_submit_handler(struct kthread_work *work) |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3115 | { |
| 3116 | struct sde_rotator_ctx *ctx; |
| 3117 | struct sde_rotator_device *rot_dev; |
Alan Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 3118 | struct vb2_v4l2_buffer *src_buf; |
| 3119 | struct vb2_v4l2_buffer *dst_buf; |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3120 | struct sde_rotator_request *request; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3121 | int ret; |
| 3122 | |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3123 | request = container_of(work, struct sde_rotator_request, submit_work); |
| 3124 | ctx = request->ctx; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3125 | |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3126 | if (!ctx || !ctx->rot_dev) { |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3127 | 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 Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3138 | sde_rotator_update_retire_sequence(request); |
| 3139 | sde_rotator_retire_request(request); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3140 | mutex_unlock(&rot_dev->lock); |
| 3141 | return; |
| 3142 | } |
| 3143 | |
| 3144 | /* submit new request */ |
Alan Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 3145 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3147 | sde_rot_mgr_lock(rot_dev->mgr); |
Alan Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 3148 | ret = sde_rotator_process_buffers(ctx, &src_buf->vb2_buf, |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3149 | &dst_buf->vb2_buf, request); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3150 | 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 Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 3156 | v4l2_m2m_try_schedule(ctx->fh.m2m_ctx); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3157 | } |
| 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 | */ |
| 3166 | static void sde_rotator_device_run(void *priv) |
| 3167 | { |
| 3168 | struct sde_rotator_ctx *ctx = priv; |
| 3169 | struct sde_rotator_device *rot_dev; |
Alan Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 3170 | struct vb2_v4l2_buffer *src_buf; |
| 3171 | struct vb2_v4l2_buffer *dst_buf; |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3172 | struct sde_rotator_request *request; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3173 | 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 Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3184 | request = list_first_entry_or_null(&ctx->pending_list, |
| 3185 | struct sde_rotator_request, list); |
| 3186 | |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3187 | /* pending request mode, check for completion */ |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3188 | if (!request || IS_ERR_OR_NULL(request->req)) { |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3189 | /* 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 Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3196 | |
| 3197 | } else if (!atomic_read(&request->req->pending_count)) { |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3198 | /* pending request completed. signal done. */ |
| 3199 | int failed_count = |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3200 | atomic_read(&request->req->failed_count); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3201 | 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 Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3207 | sde_rotator_req_finish(rot_dev->mgr, ctx->private, |
| 3208 | request->req); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3209 | 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 Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 3222 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3224 | 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 Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3232 | sde_rotator_update_retire_sequence(request); |
| 3233 | sde_rotator_retire_request(request); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3234 | v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); |
| 3235 | v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); |
Alan Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 3236 | v4l2_m2m_job_finish(rot_dev->m2m_dev, ctx->fh.m2m_ctx); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3237 | } 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 Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3245 | sde_rotator_req_finish(rot_dev->mgr, ctx->private, |
| 3246 | request->req); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3247 | sde_rot_mgr_unlock(rot_dev->mgr); |
| 3248 | |
| 3249 | goto error_process_buffers; |
| 3250 | } |
| 3251 | } else { |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3252 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3260 | |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3261 | 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 Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 3267 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3269 | if (!src_buf || !dst_buf) { |
| 3270 | SDEDEV_ERR(rot_dev->dev, |
Alan Kwong | 6bc6462 | 2017-02-04 17:36:03 -0800 | [diff] [blame] | 3271 | "null buffer in device run s:%d sb:%pK db:%pK\n", |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3272 | ctx->session_id, |
| 3273 | src_buf, dst_buf); |
| 3274 | goto error_empty_buffer; |
| 3275 | } |
| 3276 | |
| 3277 | sde_rot_mgr_lock(rot_dev->mgr); |
Alan Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 3278 | ret = sde_rotator_process_buffers(ctx, &src_buf->vb2_buf, |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3279 | &dst_buf->vb2_buf, request); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3280 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3285 | 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; |
| 3292 | error_process_buffers: |
| 3293 | error_empty_buffer: |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3294 | error_retired_list: |
| 3295 | sde_rotator_update_retire_sequence(request); |
| 3296 | sde_rotator_retire_request(request); |
Alan Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 3297 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3299 | 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 Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 3304 | v4l2_m2m_job_finish(rot_dev->m2m_dev, ctx->fh.m2m_ctx); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3305 | } |
| 3306 | |
| 3307 | /* |
| 3308 | * sde_rotator_job_abort - rotator m2m job abort callback |
| 3309 | * @priv: Pointer rotator context. |
| 3310 | */ |
| 3311 | static 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 Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 3324 | v4l2_m2m_job_finish(rot_dev->m2m_dev, ctx->fh.m2m_ctx); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3325 | } |
| 3326 | |
| 3327 | /* |
| 3328 | * sde_rotator_job_ready - rotator m2m job ready callback |
| 3329 | * @priv: Pointer rotator context. |
| 3330 | */ |
| 3331 | static int sde_rotator_job_ready(void *priv) |
| 3332 | { |
| 3333 | struct sde_rotator_ctx *ctx = priv; |
| 3334 | struct sde_rotator_device *rot_dev; |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3335 | struct sde_rotator_request *request; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3336 | 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 Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3346 | request = list_first_entry_or_null(&ctx->pending_list, |
| 3347 | struct sde_rotator_request, list); |
| 3348 | |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3349 | if (!rot_dev->early_submit) { |
| 3350 | /* always ready in normal mode. */ |
| 3351 | ret = 1; |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3352 | } else if (request && IS_ERR_OR_NULL(request->req)) { |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3353 | /* 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 Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3358 | } else if (list_empty(&ctx->pending_list)) { |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3359 | /* 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 Kwong | 3428f67 | 2016-04-18 12:32:06 -0400 | [diff] [blame] | 3363 | v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx), |
| 3364 | v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx), |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3365 | !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 Chan | f8d9a46 | 2016-11-08 21:38:10 -0500 | [diff] [blame] | 3379 | kthread_queue_work(&ctx->work_queue.rot_kw, |
Alan Kwong | f94a255 | 2016-12-28 09:41:22 -0800 | [diff] [blame] | 3380 | &request->submit_work); |
| 3381 | } |
| 3382 | } else if (request && !atomic_read(&request->req->pending_count)) { |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3383 | /* 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 */ |
| 3394 | static 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 */ |
| 3401 | static 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 | */ |
| 3413 | static 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 | */ |
| 3429 | static 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 Chan | dbe1311 | 2016-09-26 12:10:06 -0400 | [diff] [blame] | 3446 | rot_dev->min_rot_clk = 0; |
| 3447 | rot_dev->min_bw = 0; |
| 3448 | rot_dev->min_overhead_us = 0; |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3449 | rot_dev->drvdata = sde_rotator_get_drv_data(&pdev->dev); |
Alan Kwong | bfda8b98 | 2017-08-01 14:54:34 -0400 | [diff] [blame] | 3450 | rot_dev->open_timeout = SDE_ROTATOR_CTX_OPEN_TIMEOUT; |
| 3451 | init_waitqueue_head(&rot_dev->open_wq); |
Adrian Salido-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3452 | |
| 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 Chan | c4949de | 2017-06-21 16:53:15 -0400 | [diff] [blame] | 3465 | 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3469 | 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; |
| 3519 | error_video_register: |
| 3520 | video_device_release(vdev); |
| 3521 | error_alloc_video_device: |
| 3522 | v4l2_device_unregister(&rot_dev->v4l2_dev); |
| 3523 | error_v4l2_register: |
| 3524 | v4l2_m2m_release(rot_dev->m2m_dev); |
| 3525 | error_m2m_init: |
| 3526 | sde_rotator_core_destroy(rot_dev->mgr); |
| 3527 | error_rotator_core_init: |
| 3528 | sde_rotator_base_destroy(rot_dev->mdata); |
| 3529 | error_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 | */ |
| 3538 | static 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 | |
| 3559 | static 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 */ |
| 3567 | static 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-Moreno | 5c15038 | 2016-04-06 09:29:37 -0700 | [diff] [blame] | 3574 | .of_match_table = sde_rotator_dt_match, |
| 3575 | .pm = &sde_rotator_pm_ops, |
| 3576 | }, |
| 3577 | }; |
| 3578 | |
| 3579 | static int __init sde_rotator_init_module(void) |
| 3580 | { |
| 3581 | return platform_driver_register(&rotator_driver); |
| 3582 | } |
| 3583 | |
| 3584 | static void __exit sde_rotator_exit_module(void) |
| 3585 | { |
| 3586 | platform_driver_unregister(&rotator_driver); |
| 3587 | } |
| 3588 | |
| 3589 | module_init(sde_rotator_init_module); |
| 3590 | module_exit(sde_rotator_exit_module); |
| 3591 | MODULE_DESCRIPTION("MSM SDE ROTATOR driver"); |