]>
Commit | Line | Data |
---|---|---|
57b2c062 JCT |
1 | /* |
2 | * Copyright (C) STMicroelectronics SA 2015 | |
3 | * Authors: Yannick Fertre <yannick.fertre@st.com> | |
4 | * Hugues Fruchet <hugues.fruchet@st.com> | |
5 | * License terms: GNU General Public License (GPL), version 2 | |
6 | */ | |
7 | ||
8 | #include <linux/module.h> | |
9 | #include <linux/platform_device.h> | |
10 | #include <linux/slab.h> | |
11 | #include <media/v4l2-event.h> | |
12 | #include <media/v4l2-ioctl.h> | |
13 | #include <media/videobuf2-dma-contig.h> | |
14 | ||
15 | #include "hva.h" | |
16 | #include "hva-hw.h" | |
17 | ||
57b2c062 JCT |
18 | #define MIN_FRAMES 1 |
19 | #define MIN_STREAMS 1 | |
20 | ||
21 | #define HVA_MIN_WIDTH 32 | |
22 | #define HVA_MAX_WIDTH 1920 | |
23 | #define HVA_MIN_HEIGHT 32 | |
24 | #define HVA_MAX_HEIGHT 1920 | |
25 | ||
26 | /* HVA requires a 16x16 pixels alignment for frames */ | |
27 | #define HVA_WIDTH_ALIGNMENT 16 | |
28 | #define HVA_HEIGHT_ALIGNMENT 16 | |
29 | ||
30 | #define HVA_DEFAULT_WIDTH HVA_MIN_WIDTH | |
31 | #define HVA_DEFAULT_HEIGHT HVA_MIN_HEIGHT | |
32 | #define HVA_DEFAULT_FRAME_NUM 1 | |
33 | #define HVA_DEFAULT_FRAME_DEN 30 | |
34 | ||
35 | #define to_type_str(type) (type == V4L2_BUF_TYPE_VIDEO_OUTPUT ? \ | |
36 | "frame" : "stream") | |
37 | ||
38 | #define fh_to_ctx(f) (container_of(f, struct hva_ctx, fh)) | |
39 | ||
40 | /* registry of available encoders */ | |
19de16c0 | 41 | static const struct hva_enc *hva_encoders[] = { |
ba4616b7 JCT |
42 | &nv12h264enc, |
43 | &nv21h264enc, | |
57b2c062 JCT |
44 | }; |
45 | ||
46 | static inline int frame_size(u32 w, u32 h, u32 fmt) | |
47 | { | |
48 | switch (fmt) { | |
49 | case V4L2_PIX_FMT_NV12: | |
50 | case V4L2_PIX_FMT_NV21: | |
51 | return (w * h * 3) / 2; | |
52 | default: | |
53 | return 0; | |
54 | } | |
55 | } | |
56 | ||
57 | static inline int frame_stride(u32 w, u32 fmt) | |
58 | { | |
59 | switch (fmt) { | |
60 | case V4L2_PIX_FMT_NV12: | |
61 | case V4L2_PIX_FMT_NV21: | |
62 | return w; | |
63 | default: | |
64 | return 0; | |
65 | } | |
66 | } | |
67 | ||
68 | static inline int frame_alignment(u32 fmt) | |
69 | { | |
70 | switch (fmt) { | |
71 | case V4L2_PIX_FMT_NV12: | |
72 | case V4L2_PIX_FMT_NV21: | |
73 | /* multiple of 2 */ | |
74 | return 2; | |
75 | default: | |
76 | return 1; | |
77 | } | |
78 | } | |
79 | ||
80 | static inline int estimated_stream_size(u32 w, u32 h) | |
81 | { | |
82 | /* | |
83 | * HVA only encodes in YUV420 format, whatever the frame format. | |
84 | * A compression ratio of 2 is assumed: thus, the maximum size | |
85 | * of a stream is estimated to ((width x height x 3 / 2) / 2) | |
86 | */ | |
87 | return (w * h * 3) / 4; | |
88 | } | |
89 | ||
90 | static void set_default_params(struct hva_ctx *ctx) | |
91 | { | |
92 | struct hva_frameinfo *frameinfo = &ctx->frameinfo; | |
93 | struct hva_streaminfo *streaminfo = &ctx->streaminfo; | |
94 | ||
95 | frameinfo->pixelformat = V4L2_PIX_FMT_NV12; | |
96 | frameinfo->width = HVA_DEFAULT_WIDTH; | |
97 | frameinfo->height = HVA_DEFAULT_HEIGHT; | |
98 | frameinfo->aligned_width = ALIGN(frameinfo->width, | |
99 | HVA_WIDTH_ALIGNMENT); | |
100 | frameinfo->aligned_height = ALIGN(frameinfo->height, | |
101 | HVA_HEIGHT_ALIGNMENT); | |
102 | frameinfo->size = frame_size(frameinfo->aligned_width, | |
103 | frameinfo->aligned_height, | |
104 | frameinfo->pixelformat); | |
105 | ||
106 | streaminfo->streamformat = V4L2_PIX_FMT_H264; | |
107 | streaminfo->width = HVA_DEFAULT_WIDTH; | |
108 | streaminfo->height = HVA_DEFAULT_HEIGHT; | |
109 | ||
110 | ctx->colorspace = V4L2_COLORSPACE_REC709; | |
111 | ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT; | |
112 | ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; | |
113 | ctx->quantization = V4L2_QUANTIZATION_DEFAULT; | |
114 | ||
115 | ctx->max_stream_size = estimated_stream_size(streaminfo->width, | |
116 | streaminfo->height); | |
117 | } | |
118 | ||
119 | static const struct hva_enc *hva_find_encoder(struct hva_ctx *ctx, | |
120 | u32 pixelformat, | |
121 | u32 streamformat) | |
122 | { | |
123 | struct hva_dev *hva = ctx_to_hdev(ctx); | |
124 | const struct hva_enc *enc; | |
125 | unsigned int i; | |
126 | ||
127 | for (i = 0; i < hva->nb_of_encoders; i++) { | |
128 | enc = hva->encoders[i]; | |
129 | if ((enc->pixelformat == pixelformat) && | |
130 | (enc->streamformat == streamformat)) | |
131 | return enc; | |
132 | } | |
133 | ||
134 | return NULL; | |
135 | } | |
136 | ||
137 | static void register_format(u32 format, u32 formats[], u32 *nb_of_formats) | |
138 | { | |
139 | u32 i; | |
140 | bool found = false; | |
141 | ||
142 | for (i = 0; i < *nb_of_formats; i++) { | |
143 | if (format == formats[i]) { | |
144 | found = true; | |
145 | break; | |
146 | } | |
147 | } | |
148 | ||
149 | if (!found) | |
150 | formats[(*nb_of_formats)++] = format; | |
151 | } | |
152 | ||
153 | static void register_formats(struct hva_dev *hva) | |
154 | { | |
155 | unsigned int i; | |
156 | ||
157 | for (i = 0; i < hva->nb_of_encoders; i++) { | |
158 | register_format(hva->encoders[i]->pixelformat, | |
159 | hva->pixelformats, | |
160 | &hva->nb_of_pixelformats); | |
161 | ||
162 | register_format(hva->encoders[i]->streamformat, | |
163 | hva->streamformats, | |
164 | &hva->nb_of_streamformats); | |
165 | } | |
166 | } | |
167 | ||
168 | static void register_encoders(struct hva_dev *hva) | |
169 | { | |
170 | struct device *dev = hva_to_dev(hva); | |
171 | unsigned int i; | |
172 | ||
173 | for (i = 0; i < ARRAY_SIZE(hva_encoders); i++) { | |
174 | if (hva->nb_of_encoders >= HVA_MAX_ENCODERS) { | |
175 | dev_dbg(dev, | |
176 | "%s failed to register %s encoder (%d maximum reached)\n", | |
177 | HVA_PREFIX, hva_encoders[i]->name, | |
178 | HVA_MAX_ENCODERS); | |
179 | return; | |
180 | } | |
181 | ||
182 | hva->encoders[hva->nb_of_encoders++] = hva_encoders[i]; | |
183 | dev_info(dev, "%s %s encoder registered\n", HVA_PREFIX, | |
184 | hva_encoders[i]->name); | |
185 | } | |
186 | } | |
187 | ||
188 | static int hva_open_encoder(struct hva_ctx *ctx, u32 streamformat, | |
189 | u32 pixelformat, struct hva_enc **penc) | |
190 | { | |
191 | struct hva_dev *hva = ctx_to_hdev(ctx); | |
192 | struct device *dev = ctx_to_dev(ctx); | |
193 | struct hva_enc *enc; | |
194 | int ret; | |
195 | ||
196 | /* find an encoder which can deal with these formats */ | |
197 | enc = (struct hva_enc *)hva_find_encoder(ctx, pixelformat, | |
198 | streamformat); | |
199 | if (!enc) { | |
200 | dev_err(dev, "%s no encoder found matching %4.4s => %4.4s\n", | |
201 | ctx->name, (char *)&pixelformat, (char *)&streamformat); | |
202 | return -EINVAL; | |
203 | } | |
204 | ||
205 | dev_dbg(dev, "%s one encoder matching %4.4s => %4.4s\n", | |
206 | ctx->name, (char *)&pixelformat, (char *)&streamformat); | |
207 | ||
208 | /* update instance name */ | |
209 | snprintf(ctx->name, sizeof(ctx->name), "[%3d:%4.4s]", | |
210 | hva->instance_id, (char *)&streamformat); | |
211 | ||
212 | /* open encoder instance */ | |
213 | ret = enc->open(ctx); | |
214 | if (ret) { | |
215 | dev_err(dev, "%s failed to open encoder instance (%d)\n", | |
216 | ctx->name, ret); | |
217 | return ret; | |
218 | } | |
219 | ||
220 | dev_dbg(dev, "%s %s encoder opened\n", ctx->name, enc->name); | |
221 | ||
222 | *penc = enc; | |
223 | ||
224 | return ret; | |
225 | } | |
226 | ||
e7b3a2b2 | 227 | static void hva_dbg_summary(struct hva_ctx *ctx) |
f7e1a6db JCT |
228 | { |
229 | struct device *dev = ctx_to_dev(ctx); | |
230 | struct hva_streaminfo *stream = &ctx->streaminfo; | |
231 | struct hva_frameinfo *frame = &ctx->frameinfo; | |
232 | ||
233 | if (!(ctx->flags & HVA_FLAG_STREAMINFO)) | |
234 | return; | |
235 | ||
236 | dev_dbg(dev, "%s %4.4s %dx%d > %4.4s %dx%d %s %s: %d frames encoded, %d system errors, %d encoding errors, %d frame errors\n", | |
237 | ctx->name, | |
238 | (char *)&frame->pixelformat, | |
239 | frame->aligned_width, frame->aligned_height, | |
240 | (char *)&stream->streamformat, | |
241 | stream->width, stream->height, | |
242 | stream->profile, stream->level, | |
243 | ctx->encoded_frames, | |
244 | ctx->sys_errors, | |
245 | ctx->encode_errors, | |
246 | ctx->frame_errors); | |
247 | } | |
248 | ||
57b2c062 JCT |
249 | /* |
250 | * V4L2 ioctl operations | |
251 | */ | |
252 | ||
253 | static int hva_querycap(struct file *file, void *priv, | |
254 | struct v4l2_capability *cap) | |
255 | { | |
256 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | |
257 | struct hva_dev *hva = ctx_to_hdev(ctx); | |
258 | ||
259 | strlcpy(cap->driver, HVA_NAME, sizeof(cap->driver)); | |
260 | strlcpy(cap->card, hva->vdev->name, sizeof(cap->card)); | |
261 | snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", | |
262 | hva->pdev->name); | |
263 | ||
264 | return 0; | |
265 | } | |
266 | ||
267 | static int hva_enum_fmt_stream(struct file *file, void *priv, | |
268 | struct v4l2_fmtdesc *f) | |
269 | { | |
270 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | |
271 | struct hva_dev *hva = ctx_to_hdev(ctx); | |
272 | ||
273 | if (unlikely(f->index >= hva->nb_of_streamformats)) | |
274 | return -EINVAL; | |
275 | ||
276 | f->pixelformat = hva->streamformats[f->index]; | |
277 | ||
278 | return 0; | |
279 | } | |
280 | ||
281 | static int hva_enum_fmt_frame(struct file *file, void *priv, | |
282 | struct v4l2_fmtdesc *f) | |
283 | { | |
284 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | |
285 | struct hva_dev *hva = ctx_to_hdev(ctx); | |
286 | ||
287 | if (unlikely(f->index >= hva->nb_of_pixelformats)) | |
288 | return -EINVAL; | |
289 | ||
290 | f->pixelformat = hva->pixelformats[f->index]; | |
291 | ||
292 | return 0; | |
293 | } | |
294 | ||
295 | static int hva_g_fmt_stream(struct file *file, void *fh, struct v4l2_format *f) | |
296 | { | |
297 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | |
298 | struct hva_streaminfo *streaminfo = &ctx->streaminfo; | |
299 | ||
300 | f->fmt.pix.width = streaminfo->width; | |
301 | f->fmt.pix.height = streaminfo->height; | |
302 | f->fmt.pix.field = V4L2_FIELD_NONE; | |
303 | f->fmt.pix.colorspace = ctx->colorspace; | |
304 | f->fmt.pix.xfer_func = ctx->xfer_func; | |
305 | f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; | |
306 | f->fmt.pix.quantization = ctx->quantization; | |
307 | f->fmt.pix.pixelformat = streaminfo->streamformat; | |
308 | f->fmt.pix.bytesperline = 0; | |
309 | f->fmt.pix.sizeimage = ctx->max_stream_size; | |
310 | ||
311 | return 0; | |
312 | } | |
313 | ||
314 | static int hva_g_fmt_frame(struct file *file, void *fh, struct v4l2_format *f) | |
315 | { | |
316 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | |
317 | struct hva_frameinfo *frameinfo = &ctx->frameinfo; | |
318 | ||
319 | f->fmt.pix.width = frameinfo->width; | |
320 | f->fmt.pix.height = frameinfo->height; | |
321 | f->fmt.pix.field = V4L2_FIELD_NONE; | |
322 | f->fmt.pix.colorspace = ctx->colorspace; | |
323 | f->fmt.pix.xfer_func = ctx->xfer_func; | |
324 | f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; | |
325 | f->fmt.pix.quantization = ctx->quantization; | |
326 | f->fmt.pix.pixelformat = frameinfo->pixelformat; | |
327 | f->fmt.pix.bytesperline = frame_stride(frameinfo->aligned_width, | |
328 | frameinfo->pixelformat); | |
329 | f->fmt.pix.sizeimage = frameinfo->size; | |
330 | ||
331 | return 0; | |
332 | } | |
333 | ||
334 | static int hva_try_fmt_stream(struct file *file, void *priv, | |
335 | struct v4l2_format *f) | |
336 | { | |
337 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | |
338 | struct device *dev = ctx_to_dev(ctx); | |
339 | struct v4l2_pix_format *pix = &f->fmt.pix; | |
340 | u32 streamformat = pix->pixelformat; | |
341 | const struct hva_enc *enc; | |
342 | u32 width, height; | |
343 | u32 stream_size; | |
344 | ||
345 | enc = hva_find_encoder(ctx, ctx->frameinfo.pixelformat, streamformat); | |
346 | if (!enc) { | |
347 | dev_dbg(dev, | |
348 | "%s V4L2 TRY_FMT (CAPTURE): unsupported format %.4s\n", | |
349 | ctx->name, (char *)&pix->pixelformat); | |
350 | return -EINVAL; | |
351 | } | |
352 | ||
353 | width = pix->width; | |
354 | height = pix->height; | |
355 | if (ctx->flags & HVA_FLAG_FRAMEINFO) { | |
356 | /* | |
357 | * if the frame resolution is already fixed, only allow the | |
358 | * same stream resolution | |
359 | */ | |
360 | pix->width = ctx->frameinfo.width; | |
361 | pix->height = ctx->frameinfo.height; | |
362 | if ((pix->width != width) || (pix->height != height)) | |
363 | dev_dbg(dev, | |
364 | "%s V4L2 TRY_FMT (CAPTURE): resolution updated %dx%d -> %dx%d to fit frame resolution\n", | |
365 | ctx->name, width, height, | |
366 | pix->width, pix->height); | |
367 | } else { | |
368 | /* adjust width & height */ | |
369 | v4l_bound_align_image(&pix->width, | |
370 | HVA_MIN_WIDTH, enc->max_width, | |
371 | 0, | |
372 | &pix->height, | |
373 | HVA_MIN_HEIGHT, enc->max_height, | |
374 | 0, | |
375 | 0); | |
376 | ||
377 | if ((pix->width != width) || (pix->height != height)) | |
378 | dev_dbg(dev, | |
379 | "%s V4L2 TRY_FMT (CAPTURE): resolution updated %dx%d -> %dx%d to fit min/max/alignment\n", | |
380 | ctx->name, width, height, | |
381 | pix->width, pix->height); | |
382 | } | |
383 | ||
384 | stream_size = estimated_stream_size(pix->width, pix->height); | |
385 | if (pix->sizeimage < stream_size) | |
386 | pix->sizeimage = stream_size; | |
387 | ||
388 | pix->bytesperline = 0; | |
389 | pix->colorspace = ctx->colorspace; | |
390 | pix->xfer_func = ctx->xfer_func; | |
391 | pix->ycbcr_enc = ctx->ycbcr_enc; | |
392 | pix->quantization = ctx->quantization; | |
393 | pix->field = V4L2_FIELD_NONE; | |
394 | ||
395 | return 0; | |
396 | } | |
397 | ||
398 | static int hva_try_fmt_frame(struct file *file, void *priv, | |
399 | struct v4l2_format *f) | |
400 | { | |
401 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | |
402 | struct device *dev = ctx_to_dev(ctx); | |
403 | struct v4l2_pix_format *pix = &f->fmt.pix; | |
404 | u32 pixelformat = pix->pixelformat; | |
405 | const struct hva_enc *enc; | |
406 | u32 width, height; | |
407 | ||
408 | enc = hva_find_encoder(ctx, pixelformat, ctx->streaminfo.streamformat); | |
409 | if (!enc) { | |
410 | dev_dbg(dev, | |
411 | "%s V4L2 TRY_FMT (OUTPUT): unsupported format %.4s\n", | |
412 | ctx->name, (char *)&pixelformat); | |
413 | return -EINVAL; | |
414 | } | |
415 | ||
416 | /* adjust width & height */ | |
417 | width = pix->width; | |
418 | height = pix->height; | |
419 | v4l_bound_align_image(&pix->width, | |
420 | HVA_MIN_WIDTH, HVA_MAX_WIDTH, | |
421 | frame_alignment(pixelformat) - 1, | |
422 | &pix->height, | |
423 | HVA_MIN_HEIGHT, HVA_MAX_HEIGHT, | |
424 | frame_alignment(pixelformat) - 1, | |
425 | 0); | |
426 | ||
427 | if ((pix->width != width) || (pix->height != height)) | |
428 | dev_dbg(dev, | |
429 | "%s V4L2 TRY_FMT (OUTPUT): resolution updated %dx%d -> %dx%d to fit min/max/alignment\n", | |
430 | ctx->name, width, height, pix->width, pix->height); | |
431 | ||
432 | width = ALIGN(pix->width, HVA_WIDTH_ALIGNMENT); | |
433 | height = ALIGN(pix->height, HVA_HEIGHT_ALIGNMENT); | |
434 | ||
435 | if (!pix->colorspace) { | |
436 | pix->colorspace = V4L2_COLORSPACE_REC709; | |
437 | pix->xfer_func = V4L2_XFER_FUNC_DEFAULT; | |
438 | pix->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; | |
439 | pix->quantization = V4L2_QUANTIZATION_DEFAULT; | |
440 | } | |
441 | ||
442 | pix->bytesperline = frame_stride(width, pixelformat); | |
443 | pix->sizeimage = frame_size(width, height, pixelformat); | |
444 | pix->field = V4L2_FIELD_NONE; | |
445 | ||
446 | return 0; | |
447 | } | |
448 | ||
449 | static int hva_s_fmt_stream(struct file *file, void *fh, struct v4l2_format *f) | |
450 | { | |
451 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | |
452 | struct device *dev = ctx_to_dev(ctx); | |
453 | struct vb2_queue *vq; | |
454 | int ret; | |
455 | ||
456 | ret = hva_try_fmt_stream(file, fh, f); | |
457 | if (ret) { | |
458 | dev_dbg(dev, "%s V4L2 S_FMT (CAPTURE): unsupported format %.4s\n", | |
459 | ctx->name, (char *)&f->fmt.pix.pixelformat); | |
460 | return ret; | |
461 | } | |
462 | ||
463 | vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); | |
464 | if (vb2_is_streaming(vq)) { | |
465 | dev_dbg(dev, "%s V4L2 S_FMT (CAPTURE): queue busy\n", | |
466 | ctx->name); | |
467 | return -EBUSY; | |
468 | } | |
469 | ||
470 | ctx->max_stream_size = f->fmt.pix.sizeimage; | |
471 | ctx->streaminfo.width = f->fmt.pix.width; | |
472 | ctx->streaminfo.height = f->fmt.pix.height; | |
473 | ctx->streaminfo.streamformat = f->fmt.pix.pixelformat; | |
474 | ctx->flags |= HVA_FLAG_STREAMINFO; | |
475 | ||
476 | return 0; | |
477 | } | |
478 | ||
479 | static int hva_s_fmt_frame(struct file *file, void *fh, struct v4l2_format *f) | |
480 | { | |
481 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | |
482 | struct device *dev = ctx_to_dev(ctx); | |
483 | struct v4l2_pix_format *pix = &f->fmt.pix; | |
484 | struct vb2_queue *vq; | |
485 | int ret; | |
486 | ||
487 | ret = hva_try_fmt_frame(file, fh, f); | |
488 | if (ret) { | |
489 | dev_dbg(dev, "%s V4L2 S_FMT (OUTPUT): unsupported format %.4s\n", | |
490 | ctx->name, (char *)&pix->pixelformat); | |
491 | return ret; | |
492 | } | |
493 | ||
494 | vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); | |
495 | if (vb2_is_streaming(vq)) { | |
496 | dev_dbg(dev, "%s V4L2 S_FMT (OUTPUT): queue busy\n", ctx->name); | |
497 | return -EBUSY; | |
498 | } | |
499 | ||
500 | ctx->colorspace = pix->colorspace; | |
501 | ctx->xfer_func = pix->xfer_func; | |
502 | ctx->ycbcr_enc = pix->ycbcr_enc; | |
503 | ctx->quantization = pix->quantization; | |
504 | ||
505 | ctx->frameinfo.aligned_width = ALIGN(pix->width, HVA_WIDTH_ALIGNMENT); | |
506 | ctx->frameinfo.aligned_height = ALIGN(pix->height, | |
507 | HVA_HEIGHT_ALIGNMENT); | |
508 | ctx->frameinfo.size = pix->sizeimage; | |
509 | ctx->frameinfo.pixelformat = pix->pixelformat; | |
510 | ctx->frameinfo.width = pix->width; | |
511 | ctx->frameinfo.height = pix->height; | |
512 | ctx->flags |= HVA_FLAG_FRAMEINFO; | |
513 | ||
514 | return 0; | |
515 | } | |
516 | ||
517 | static int hva_g_parm(struct file *file, void *fh, struct v4l2_streamparm *sp) | |
518 | { | |
519 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | |
520 | struct v4l2_fract *time_per_frame = &ctx->ctrls.time_per_frame; | |
521 | ||
522 | if (sp->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) | |
523 | return -EINVAL; | |
524 | ||
525 | sp->parm.output.capability = V4L2_CAP_TIMEPERFRAME; | |
526 | sp->parm.output.timeperframe.numerator = time_per_frame->numerator; | |
527 | sp->parm.output.timeperframe.denominator = | |
528 | time_per_frame->denominator; | |
529 | ||
530 | return 0; | |
531 | } | |
532 | ||
533 | static int hva_s_parm(struct file *file, void *fh, struct v4l2_streamparm *sp) | |
534 | { | |
535 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | |
536 | struct v4l2_fract *time_per_frame = &ctx->ctrls.time_per_frame; | |
537 | ||
538 | if (sp->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) | |
539 | return -EINVAL; | |
540 | ||
541 | if (!sp->parm.output.timeperframe.numerator || | |
542 | !sp->parm.output.timeperframe.denominator) | |
543 | return hva_g_parm(file, fh, sp); | |
544 | ||
545 | sp->parm.output.capability = V4L2_CAP_TIMEPERFRAME; | |
546 | time_per_frame->numerator = sp->parm.output.timeperframe.numerator; | |
547 | time_per_frame->denominator = | |
548 | sp->parm.output.timeperframe.denominator; | |
549 | ||
550 | return 0; | |
551 | } | |
552 | ||
553 | static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | |
554 | { | |
555 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | |
556 | struct device *dev = ctx_to_dev(ctx); | |
557 | ||
558 | if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { | |
559 | /* | |
560 | * depending on the targeted compressed video format, the | |
561 | * capture buffer might contain headers (e.g. H.264 SPS/PPS) | |
562 | * filled in by the driver client; the size of these data is | |
563 | * copied from the bytesused field of the V4L2 buffer in the | |
564 | * payload field of the hva stream buffer | |
565 | */ | |
566 | struct vb2_queue *vq; | |
567 | struct hva_stream *stream; | |
568 | ||
569 | vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, buf->type); | |
570 | ||
571 | if (buf->index >= vq->num_buffers) { | |
572 | dev_dbg(dev, "%s buffer index %d out of range (%d)\n", | |
573 | ctx->name, buf->index, vq->num_buffers); | |
574 | return -EINVAL; | |
575 | } | |
576 | ||
577 | stream = (struct hva_stream *)vq->bufs[buf->index]; | |
578 | stream->bytesused = buf->bytesused; | |
579 | } | |
580 | ||
581 | return v4l2_m2m_qbuf(file, ctx->fh.m2m_ctx, buf); | |
582 | } | |
583 | ||
584 | /* V4L2 ioctl ops */ | |
585 | static const struct v4l2_ioctl_ops hva_ioctl_ops = { | |
586 | .vidioc_querycap = hva_querycap, | |
587 | .vidioc_enum_fmt_vid_cap = hva_enum_fmt_stream, | |
588 | .vidioc_enum_fmt_vid_out = hva_enum_fmt_frame, | |
589 | .vidioc_g_fmt_vid_cap = hva_g_fmt_stream, | |
590 | .vidioc_g_fmt_vid_out = hva_g_fmt_frame, | |
591 | .vidioc_try_fmt_vid_cap = hva_try_fmt_stream, | |
592 | .vidioc_try_fmt_vid_out = hva_try_fmt_frame, | |
593 | .vidioc_s_fmt_vid_cap = hva_s_fmt_stream, | |
594 | .vidioc_s_fmt_vid_out = hva_s_fmt_frame, | |
595 | .vidioc_g_parm = hva_g_parm, | |
596 | .vidioc_s_parm = hva_s_parm, | |
597 | .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, | |
598 | .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, | |
599 | .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, | |
600 | .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, | |
601 | .vidioc_qbuf = hva_qbuf, | |
602 | .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, | |
603 | .vidioc_streamon = v4l2_m2m_ioctl_streamon, | |
604 | .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, | |
605 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | |
606 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | |
607 | }; | |
608 | ||
609 | /* | |
610 | * V4L2 control operations | |
611 | */ | |
612 | ||
613 | static int hva_s_ctrl(struct v4l2_ctrl *ctrl) | |
614 | { | |
615 | struct hva_ctx *ctx = container_of(ctrl->handler, struct hva_ctx, | |
616 | ctrl_handler); | |
617 | struct device *dev = ctx_to_dev(ctx); | |
618 | ||
619 | dev_dbg(dev, "%s S_CTRL: id = %d, val = %d\n", ctx->name, | |
620 | ctrl->id, ctrl->val); | |
621 | ||
622 | switch (ctrl->id) { | |
623 | case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: | |
624 | ctx->ctrls.bitrate_mode = ctrl->val; | |
625 | break; | |
626 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | |
627 | ctx->ctrls.gop_size = ctrl->val; | |
628 | break; | |
629 | case V4L2_CID_MPEG_VIDEO_BITRATE: | |
630 | ctx->ctrls.bitrate = ctrl->val; | |
631 | break; | |
632 | case V4L2_CID_MPEG_VIDEO_ASPECT: | |
633 | ctx->ctrls.aspect = ctrl->val; | |
634 | break; | |
ba4616b7 JCT |
635 | case V4L2_CID_MPEG_VIDEO_H264_PROFILE: |
636 | ctx->ctrls.profile = ctrl->val; | |
f7e1a6db JCT |
637 | snprintf(ctx->streaminfo.profile, |
638 | sizeof(ctx->streaminfo.profile), | |
639 | "%s profile", | |
640 | v4l2_ctrl_get_menu(ctrl->id)[ctrl->val]); | |
ba4616b7 JCT |
641 | break; |
642 | case V4L2_CID_MPEG_VIDEO_H264_LEVEL: | |
643 | ctx->ctrls.level = ctrl->val; | |
f7e1a6db JCT |
644 | snprintf(ctx->streaminfo.level, |
645 | sizeof(ctx->streaminfo.level), | |
646 | "level %s", | |
647 | v4l2_ctrl_get_menu(ctrl->id)[ctrl->val]); | |
ba4616b7 JCT |
648 | break; |
649 | case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: | |
650 | ctx->ctrls.entropy_mode = ctrl->val; | |
651 | break; | |
652 | case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE: | |
653 | ctx->ctrls.cpb_size = ctrl->val; | |
654 | break; | |
655 | case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: | |
656 | ctx->ctrls.dct8x8 = ctrl->val; | |
657 | break; | |
658 | case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: | |
659 | ctx->ctrls.qpmin = ctrl->val; | |
660 | break; | |
661 | case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: | |
662 | ctx->ctrls.qpmax = ctrl->val; | |
663 | break; | |
664 | case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE: | |
665 | ctx->ctrls.vui_sar = ctrl->val; | |
666 | break; | |
667 | case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: | |
668 | ctx->ctrls.vui_sar_idc = ctrl->val; | |
669 | break; | |
670 | case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING: | |
671 | ctx->ctrls.sei_fp = ctrl->val; | |
672 | break; | |
673 | case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: | |
674 | ctx->ctrls.sei_fp_type = ctrl->val; | |
675 | break; | |
57b2c062 JCT |
676 | default: |
677 | dev_dbg(dev, "%s S_CTRL: invalid control (id = %d)\n", | |
678 | ctx->name, ctrl->id); | |
679 | return -EINVAL; | |
680 | } | |
681 | ||
682 | return 0; | |
683 | } | |
684 | ||
685 | /* V4L2 control ops */ | |
686 | static const struct v4l2_ctrl_ops hva_ctrl_ops = { | |
687 | .s_ctrl = hva_s_ctrl, | |
688 | }; | |
689 | ||
690 | static int hva_ctrls_setup(struct hva_ctx *ctx) | |
691 | { | |
692 | struct device *dev = ctx_to_dev(ctx); | |
693 | u64 mask; | |
ba4616b7 JCT |
694 | enum v4l2_mpeg_video_h264_sei_fp_arrangement_type sei_fp_type = |
695 | V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TOP_BOTTOM; | |
57b2c062 | 696 | |
ba4616b7 | 697 | v4l2_ctrl_handler_init(&ctx->ctrl_handler, 15); |
57b2c062 JCT |
698 | |
699 | v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &hva_ctrl_ops, | |
700 | V4L2_CID_MPEG_VIDEO_BITRATE_MODE, | |
701 | V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, | |
702 | 0, | |
703 | V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); | |
704 | ||
705 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &hva_ctrl_ops, | |
706 | V4L2_CID_MPEG_VIDEO_GOP_SIZE, | |
707 | 1, 60, 1, 16); | |
708 | ||
709 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &hva_ctrl_ops, | |
710 | V4L2_CID_MPEG_VIDEO_BITRATE, | |
711 | 1000, 60000000, 1000, 20000000); | |
712 | ||
713 | mask = ~(1 << V4L2_MPEG_VIDEO_ASPECT_1x1); | |
714 | v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &hva_ctrl_ops, | |
715 | V4L2_CID_MPEG_VIDEO_ASPECT, | |
716 | V4L2_MPEG_VIDEO_ASPECT_1x1, | |
717 | mask, | |
718 | V4L2_MPEG_VIDEO_ASPECT_1x1); | |
719 | ||
ba4616b7 JCT |
720 | mask = ~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | |
721 | (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | | |
722 | (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) | | |
723 | (1 << V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH)); | |
724 | v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &hva_ctrl_ops, | |
725 | V4L2_CID_MPEG_VIDEO_H264_PROFILE, | |
726 | V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH, | |
727 | mask, | |
728 | V4L2_MPEG_VIDEO_H264_PROFILE_HIGH); | |
729 | ||
730 | v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &hva_ctrl_ops, | |
731 | V4L2_CID_MPEG_VIDEO_H264_LEVEL, | |
732 | V4L2_MPEG_VIDEO_H264_LEVEL_4_2, | |
733 | 0, | |
734 | V4L2_MPEG_VIDEO_H264_LEVEL_4_0); | |
735 | ||
736 | v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &hva_ctrl_ops, | |
737 | V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, | |
738 | V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, | |
739 | 0, | |
740 | V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC); | |
741 | ||
742 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &hva_ctrl_ops, | |
743 | V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE, | |
744 | 1, 10000, 1, 3000); | |
745 | ||
746 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &hva_ctrl_ops, | |
747 | V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, | |
748 | 0, 1, 1, 0); | |
749 | ||
750 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &hva_ctrl_ops, | |
751 | V4L2_CID_MPEG_VIDEO_H264_MIN_QP, | |
752 | 0, 51, 1, 5); | |
753 | ||
754 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &hva_ctrl_ops, | |
755 | V4L2_CID_MPEG_VIDEO_H264_MAX_QP, | |
756 | 0, 51, 1, 51); | |
757 | ||
758 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &hva_ctrl_ops, | |
759 | V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE, | |
760 | 0, 1, 1, 1); | |
761 | ||
762 | mask = ~(1 << V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1); | |
763 | v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &hva_ctrl_ops, | |
764 | V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC, | |
765 | V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1, | |
766 | mask, | |
767 | V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1); | |
768 | ||
769 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &hva_ctrl_ops, | |
770 | V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING, | |
771 | 0, 1, 1, 0); | |
772 | ||
773 | mask = ~(1 << sei_fp_type); | |
774 | v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &hva_ctrl_ops, | |
775 | V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE, | |
776 | sei_fp_type, | |
777 | mask, | |
778 | sei_fp_type); | |
779 | ||
57b2c062 JCT |
780 | if (ctx->ctrl_handler.error) { |
781 | int err = ctx->ctrl_handler.error; | |
782 | ||
783 | dev_dbg(dev, "%s controls setup failed (%d)\n", | |
784 | ctx->name, err); | |
785 | v4l2_ctrl_handler_free(&ctx->ctrl_handler); | |
786 | return err; | |
787 | } | |
788 | ||
789 | v4l2_ctrl_handler_setup(&ctx->ctrl_handler); | |
790 | ||
791 | /* set default time per frame */ | |
792 | ctx->ctrls.time_per_frame.numerator = HVA_DEFAULT_FRAME_NUM; | |
793 | ctx->ctrls.time_per_frame.denominator = HVA_DEFAULT_FRAME_DEN; | |
794 | ||
795 | return 0; | |
796 | } | |
797 | ||
798 | /* | |
799 | * mem-to-mem operations | |
800 | */ | |
801 | ||
802 | static void hva_run_work(struct work_struct *work) | |
803 | { | |
804 | struct hva_ctx *ctx = container_of(work, struct hva_ctx, run_work); | |
805 | struct vb2_v4l2_buffer *src_buf, *dst_buf; | |
806 | const struct hva_enc *enc = ctx->enc; | |
807 | struct hva_frame *frame; | |
808 | struct hva_stream *stream; | |
809 | int ret; | |
810 | ||
811 | /* protect instance against reentrancy */ | |
812 | mutex_lock(&ctx->lock); | |
813 | ||
c610b5a8 JCT |
814 | #ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS |
815 | hva_dbg_perf_begin(ctx); | |
816 | #endif | |
817 | ||
57b2c062 JCT |
818 | src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); |
819 | dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); | |
820 | ||
821 | frame = to_hva_frame(src_buf); | |
822 | stream = to_hva_stream(dst_buf); | |
823 | frame->vbuf.sequence = ctx->frame_num++; | |
824 | ||
825 | ret = enc->encode(ctx, frame, stream); | |
826 | ||
827 | vb2_set_plane_payload(&dst_buf->vb2_buf, 0, stream->bytesused); | |
828 | if (ret) { | |
829 | v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); | |
830 | v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); | |
831 | } else { | |
832 | /* propagate frame timestamp */ | |
833 | dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp; | |
834 | dst_buf->field = V4L2_FIELD_NONE; | |
835 | dst_buf->sequence = ctx->stream_num - 1; | |
836 | ||
f7e1a6db JCT |
837 | ctx->encoded_frames++; |
838 | ||
c610b5a8 JCT |
839 | #ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS |
840 | hva_dbg_perf_end(ctx, stream); | |
841 | #endif | |
842 | ||
57b2c062 JCT |
843 | v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); |
844 | v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); | |
845 | } | |
846 | ||
847 | mutex_unlock(&ctx->lock); | |
848 | ||
849 | v4l2_m2m_job_finish(ctx->hva_dev->m2m_dev, ctx->fh.m2m_ctx); | |
850 | } | |
851 | ||
852 | static void hva_device_run(void *priv) | |
853 | { | |
854 | struct hva_ctx *ctx = priv; | |
855 | struct hva_dev *hva = ctx_to_hdev(ctx); | |
856 | ||
857 | queue_work(hva->work_queue, &ctx->run_work); | |
858 | } | |
859 | ||
860 | static void hva_job_abort(void *priv) | |
861 | { | |
862 | struct hva_ctx *ctx = priv; | |
863 | struct device *dev = ctx_to_dev(ctx); | |
864 | ||
865 | dev_dbg(dev, "%s aborting job\n", ctx->name); | |
866 | ||
867 | ctx->aborting = true; | |
868 | } | |
869 | ||
870 | static int hva_job_ready(void *priv) | |
871 | { | |
872 | struct hva_ctx *ctx = priv; | |
873 | struct device *dev = ctx_to_dev(ctx); | |
874 | ||
875 | if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx)) { | |
876 | dev_dbg(dev, "%s job not ready: no frame buffers\n", | |
877 | ctx->name); | |
878 | return 0; | |
879 | } | |
880 | ||
881 | if (!v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) { | |
882 | dev_dbg(dev, "%s job not ready: no stream buffers\n", | |
883 | ctx->name); | |
884 | return 0; | |
885 | } | |
886 | ||
887 | if (ctx->aborting) { | |
888 | dev_dbg(dev, "%s job not ready: aborting\n", ctx->name); | |
889 | return 0; | |
890 | } | |
891 | ||
892 | return 1; | |
893 | } | |
894 | ||
895 | /* mem-to-mem ops */ | |
896 | static const struct v4l2_m2m_ops hva_m2m_ops = { | |
897 | .device_run = hva_device_run, | |
898 | .job_abort = hva_job_abort, | |
899 | .job_ready = hva_job_ready, | |
900 | }; | |
901 | ||
902 | /* | |
903 | * VB2 queue operations | |
904 | */ | |
905 | ||
906 | static int hva_queue_setup(struct vb2_queue *vq, | |
907 | unsigned int *num_buffers, unsigned int *num_planes, | |
908 | unsigned int sizes[], struct device *alloc_devs[]) | |
909 | { | |
910 | struct hva_ctx *ctx = vb2_get_drv_priv(vq); | |
911 | struct device *dev = ctx_to_dev(ctx); | |
912 | unsigned int size; | |
913 | ||
914 | dev_dbg(dev, "%s %s queue setup: num_buffers %d\n", ctx->name, | |
915 | to_type_str(vq->type), *num_buffers); | |
916 | ||
917 | size = vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT ? | |
918 | ctx->frameinfo.size : ctx->max_stream_size; | |
919 | ||
920 | if (*num_planes) | |
921 | return sizes[0] < size ? -EINVAL : 0; | |
922 | ||
923 | /* only one plane supported */ | |
924 | *num_planes = 1; | |
925 | sizes[0] = size; | |
926 | ||
927 | return 0; | |
928 | } | |
929 | ||
930 | static int hva_buf_prepare(struct vb2_buffer *vb) | |
931 | { | |
932 | struct hva_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | |
933 | struct device *dev = ctx_to_dev(ctx); | |
934 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | |
935 | ||
936 | if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | |
937 | struct hva_frame *frame = to_hva_frame(vbuf); | |
938 | ||
939 | if (vbuf->field == V4L2_FIELD_ANY) | |
940 | vbuf->field = V4L2_FIELD_NONE; | |
941 | if (vbuf->field != V4L2_FIELD_NONE) { | |
942 | dev_dbg(dev, | |
943 | "%s frame[%d] prepare: %d field not supported\n", | |
944 | ctx->name, vb->index, vbuf->field); | |
945 | return -EINVAL; | |
946 | } | |
947 | ||
948 | if (!frame->prepared) { | |
949 | /* get memory addresses */ | |
950 | frame->vaddr = vb2_plane_vaddr(&vbuf->vb2_buf, 0); | |
951 | frame->paddr = vb2_dma_contig_plane_dma_addr( | |
952 | &vbuf->vb2_buf, 0); | |
953 | frame->info = ctx->frameinfo; | |
954 | frame->prepared = true; | |
955 | ||
956 | dev_dbg(dev, | |
957 | "%s frame[%d] prepared; virt=%p, phy=%pad\n", | |
958 | ctx->name, vb->index, | |
959 | frame->vaddr, &frame->paddr); | |
960 | } | |
961 | } else { | |
962 | struct hva_stream *stream = to_hva_stream(vbuf); | |
963 | ||
964 | if (!stream->prepared) { | |
965 | /* get memory addresses */ | |
966 | stream->vaddr = vb2_plane_vaddr(&vbuf->vb2_buf, 0); | |
967 | stream->paddr = vb2_dma_contig_plane_dma_addr( | |
968 | &vbuf->vb2_buf, 0); | |
969 | stream->size = vb2_plane_size(&vbuf->vb2_buf, 0); | |
970 | stream->prepared = true; | |
971 | ||
972 | dev_dbg(dev, | |
973 | "%s stream[%d] prepared; virt=%p, phy=%pad\n", | |
974 | ctx->name, vb->index, | |
975 | stream->vaddr, &stream->paddr); | |
976 | } | |
977 | } | |
978 | ||
979 | return 0; | |
980 | } | |
981 | ||
982 | static void hva_buf_queue(struct vb2_buffer *vb) | |
983 | { | |
984 | struct hva_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | |
985 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | |
986 | ||
987 | if (ctx->fh.m2m_ctx) | |
988 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); | |
989 | } | |
990 | ||
991 | static int hva_start_streaming(struct vb2_queue *vq, unsigned int count) | |
992 | { | |
993 | struct hva_ctx *ctx = vb2_get_drv_priv(vq); | |
994 | struct hva_dev *hva = ctx_to_hdev(ctx); | |
995 | struct device *dev = ctx_to_dev(ctx); | |
996 | struct vb2_v4l2_buffer *vbuf; | |
997 | int ret; | |
998 | unsigned int i; | |
999 | bool found = false; | |
1000 | ||
1001 | dev_dbg(dev, "%s %s start streaming\n", ctx->name, | |
1002 | to_type_str(vq->type)); | |
1003 | ||
1004 | /* open encoder when both start_streaming have been called */ | |
1005 | if (V4L2_TYPE_IS_OUTPUT(vq->type)) { | |
1006 | if (!vb2_start_streaming_called(&ctx->fh.m2m_ctx->cap_q_ctx.q)) | |
1007 | return 0; | |
1008 | } else { | |
1009 | if (!vb2_start_streaming_called(&ctx->fh.m2m_ctx->out_q_ctx.q)) | |
1010 | return 0; | |
1011 | } | |
1012 | ||
1013 | /* store the instance context in the instances array */ | |
1014 | for (i = 0; i < HVA_MAX_INSTANCES; i++) { | |
1015 | if (!hva->instances[i]) { | |
1016 | hva->instances[i] = ctx; | |
1017 | /* save the context identifier in the context */ | |
1018 | ctx->id = i; | |
1019 | found = true; | |
1020 | break; | |
1021 | } | |
1022 | } | |
1023 | ||
1024 | if (!found) { | |
1025 | dev_err(dev, "%s maximum instances reached\n", ctx->name); | |
1026 | ret = -ENOMEM; | |
1027 | goto err; | |
1028 | } | |
1029 | ||
1030 | hva->nb_of_instances++; | |
1031 | ||
1032 | if (!ctx->enc) { | |
1033 | ret = hva_open_encoder(ctx, | |
1034 | ctx->streaminfo.streamformat, | |
1035 | ctx->frameinfo.pixelformat, | |
1036 | &ctx->enc); | |
1037 | if (ret < 0) | |
1038 | goto err_ctx; | |
1039 | } | |
1040 | ||
1041 | return 0; | |
1042 | ||
1043 | err_ctx: | |
1044 | hva->instances[ctx->id] = NULL; | |
1045 | hva->nb_of_instances--; | |
1046 | err: | |
1047 | if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | |
1048 | /* return of all pending buffers to vb2 (in queued state) */ | |
1049 | while ((vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) | |
1050 | v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_QUEUED); | |
1051 | } else { | |
1052 | /* return of all pending buffers to vb2 (in queued state) */ | |
1053 | while ((vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) | |
1054 | v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_QUEUED); | |
1055 | } | |
1056 | ||
f7e1a6db JCT |
1057 | ctx->sys_errors++; |
1058 | ||
57b2c062 JCT |
1059 | return ret; |
1060 | } | |
1061 | ||
1062 | static void hva_stop_streaming(struct vb2_queue *vq) | |
1063 | { | |
1064 | struct hva_ctx *ctx = vb2_get_drv_priv(vq); | |
1065 | struct hva_dev *hva = ctx_to_hdev(ctx); | |
1066 | struct device *dev = ctx_to_dev(ctx); | |
1067 | const struct hva_enc *enc = ctx->enc; | |
1068 | struct vb2_v4l2_buffer *vbuf; | |
1069 | ||
1070 | dev_dbg(dev, "%s %s stop streaming\n", ctx->name, | |
1071 | to_type_str(vq->type)); | |
1072 | ||
1073 | if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | |
1074 | /* return of all pending buffers to vb2 (in error state) */ | |
1075 | ctx->frame_num = 0; | |
1076 | while ((vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) | |
1077 | v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); | |
1078 | } else { | |
1079 | /* return of all pending buffers to vb2 (in error state) */ | |
1080 | ctx->stream_num = 0; | |
1081 | while ((vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) | |
1082 | v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); | |
1083 | } | |
1084 | ||
1085 | if ((V4L2_TYPE_IS_OUTPUT(vq->type) && | |
1086 | vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q)) || | |
1087 | (!V4L2_TYPE_IS_OUTPUT(vq->type) && | |
1088 | vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q))) { | |
1089 | dev_dbg(dev, "%s %s out=%d cap=%d\n", | |
1090 | ctx->name, to_type_str(vq->type), | |
1091 | vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q), | |
1092 | vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q)); | |
1093 | return; | |
1094 | } | |
1095 | ||
1096 | /* close encoder when both stop_streaming have been called */ | |
1097 | if (enc) { | |
1098 | dev_dbg(dev, "%s %s encoder closed\n", ctx->name, enc->name); | |
1099 | enc->close(ctx); | |
1100 | ctx->enc = NULL; | |
1101 | ||
1102 | /* clear instance context in instances array */ | |
1103 | hva->instances[ctx->id] = NULL; | |
1104 | hva->nb_of_instances--; | |
1105 | } | |
1106 | ||
1107 | ctx->aborting = false; | |
1108 | } | |
1109 | ||
1110 | /* VB2 queue ops */ | |
1111 | static const struct vb2_ops hva_qops = { | |
1112 | .queue_setup = hva_queue_setup, | |
1113 | .buf_prepare = hva_buf_prepare, | |
1114 | .buf_queue = hva_buf_queue, | |
1115 | .start_streaming = hva_start_streaming, | |
1116 | .stop_streaming = hva_stop_streaming, | |
1117 | .wait_prepare = vb2_ops_wait_prepare, | |
1118 | .wait_finish = vb2_ops_wait_finish, | |
1119 | }; | |
1120 | ||
1121 | /* | |
1122 | * V4L2 file operations | |
1123 | */ | |
1124 | ||
1125 | static int queue_init(struct hva_ctx *ctx, struct vb2_queue *vq) | |
1126 | { | |
1127 | vq->io_modes = VB2_MMAP | VB2_DMABUF; | |
1128 | vq->drv_priv = ctx; | |
1129 | vq->ops = &hva_qops; | |
1130 | vq->mem_ops = &vb2_dma_contig_memops; | |
1131 | vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; | |
1132 | vq->lock = &ctx->hva_dev->lock; | |
1133 | ||
1134 | return vb2_queue_init(vq); | |
1135 | } | |
1136 | ||
1137 | static int hva_queue_init(void *priv, struct vb2_queue *src_vq, | |
1138 | struct vb2_queue *dst_vq) | |
1139 | { | |
1140 | struct hva_ctx *ctx = priv; | |
1141 | int ret; | |
1142 | ||
1143 | src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | |
1144 | src_vq->buf_struct_size = sizeof(struct hva_frame); | |
1145 | src_vq->min_buffers_needed = MIN_FRAMES; | |
1146 | src_vq->dev = ctx->hva_dev->dev; | |
1147 | ||
1148 | ret = queue_init(ctx, src_vq); | |
1149 | if (ret) | |
1150 | return ret; | |
1151 | ||
1152 | dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
1153 | dst_vq->buf_struct_size = sizeof(struct hva_stream); | |
1154 | dst_vq->min_buffers_needed = MIN_STREAMS; | |
1155 | dst_vq->dev = ctx->hva_dev->dev; | |
1156 | ||
1157 | return queue_init(ctx, dst_vq); | |
1158 | } | |
1159 | ||
1160 | static int hva_open(struct file *file) | |
1161 | { | |
1162 | struct hva_dev *hva = video_drvdata(file); | |
1163 | struct device *dev = hva_to_dev(hva); | |
1164 | struct hva_ctx *ctx; | |
1165 | int ret; | |
1166 | ||
1167 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | |
1168 | if (!ctx) { | |
1169 | ret = -ENOMEM; | |
1170 | goto out; | |
1171 | } | |
1172 | ctx->hva_dev = hva; | |
1173 | ||
1174 | INIT_WORK(&ctx->run_work, hva_run_work); | |
1175 | v4l2_fh_init(&ctx->fh, video_devdata(file)); | |
1176 | file->private_data = &ctx->fh; | |
1177 | v4l2_fh_add(&ctx->fh); | |
1178 | ||
1179 | ret = hva_ctrls_setup(ctx); | |
1180 | if (ret) { | |
1181 | dev_err(dev, "%s [x:x] failed to setup controls\n", | |
1182 | HVA_PREFIX); | |
f7e1a6db | 1183 | ctx->sys_errors++; |
57b2c062 JCT |
1184 | goto err_fh; |
1185 | } | |
1186 | ctx->fh.ctrl_handler = &ctx->ctrl_handler; | |
1187 | ||
1188 | mutex_init(&ctx->lock); | |
1189 | ||
1190 | ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(hva->m2m_dev, ctx, | |
1191 | &hva_queue_init); | |
1192 | if (IS_ERR(ctx->fh.m2m_ctx)) { | |
1193 | ret = PTR_ERR(ctx->fh.m2m_ctx); | |
1194 | dev_err(dev, "%s failed to initialize m2m context (%d)\n", | |
1195 | HVA_PREFIX, ret); | |
f7e1a6db | 1196 | ctx->sys_errors++; |
57b2c062 JCT |
1197 | goto err_ctrls; |
1198 | } | |
1199 | ||
1200 | /* set the instance name */ | |
1201 | mutex_lock(&hva->lock); | |
1202 | hva->instance_id++; | |
1203 | snprintf(ctx->name, sizeof(ctx->name), "[%3d:----]", | |
1204 | hva->instance_id); | |
1205 | mutex_unlock(&hva->lock); | |
1206 | ||
1207 | /* default parameters for frame and stream */ | |
1208 | set_default_params(ctx); | |
1209 | ||
c610b5a8 JCT |
1210 | #ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS |
1211 | hva_dbg_ctx_create(ctx); | |
1212 | #endif | |
1213 | ||
57b2c062 JCT |
1214 | dev_info(dev, "%s encoder instance created\n", ctx->name); |
1215 | ||
1216 | return 0; | |
1217 | ||
1218 | err_ctrls: | |
1219 | v4l2_ctrl_handler_free(&ctx->ctrl_handler); | |
1220 | err_fh: | |
1221 | v4l2_fh_del(&ctx->fh); | |
1222 | v4l2_fh_exit(&ctx->fh); | |
1223 | kfree(ctx); | |
1224 | out: | |
1225 | return ret; | |
1226 | } | |
1227 | ||
1228 | static int hva_release(struct file *file) | |
1229 | { | |
1230 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | |
1231 | struct hva_dev *hva = ctx_to_hdev(ctx); | |
1232 | struct device *dev = ctx_to_dev(ctx); | |
1233 | const struct hva_enc *enc = ctx->enc; | |
1234 | ||
1235 | if (enc) { | |
1236 | dev_dbg(dev, "%s %s encoder closed\n", ctx->name, enc->name); | |
1237 | enc->close(ctx); | |
1238 | ctx->enc = NULL; | |
1239 | ||
1240 | /* clear instance context in instances array */ | |
1241 | hva->instances[ctx->id] = NULL; | |
1242 | hva->nb_of_instances--; | |
1243 | } | |
1244 | ||
f7e1a6db JCT |
1245 | /* trace a summary of instance before closing (debug purpose) */ |
1246 | hva_dbg_summary(ctx); | |
1247 | ||
57b2c062 JCT |
1248 | v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); |
1249 | ||
1250 | v4l2_ctrl_handler_free(&ctx->ctrl_handler); | |
1251 | ||
1252 | v4l2_fh_del(&ctx->fh); | |
1253 | v4l2_fh_exit(&ctx->fh); | |
1254 | ||
c610b5a8 JCT |
1255 | #ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS |
1256 | hva_dbg_ctx_remove(ctx); | |
1257 | #endif | |
1258 | ||
57b2c062 JCT |
1259 | dev_info(dev, "%s encoder instance released\n", ctx->name); |
1260 | ||
1261 | kfree(ctx); | |
1262 | ||
1263 | return 0; | |
1264 | } | |
1265 | ||
1266 | /* V4L2 file ops */ | |
1267 | static const struct v4l2_file_operations hva_fops = { | |
1268 | .owner = THIS_MODULE, | |
1269 | .open = hva_open, | |
1270 | .release = hva_release, | |
1271 | .unlocked_ioctl = video_ioctl2, | |
1272 | .mmap = v4l2_m2m_fop_mmap, | |
1273 | .poll = v4l2_m2m_fop_poll, | |
1274 | }; | |
1275 | ||
1276 | /* | |
1277 | * Platform device operations | |
1278 | */ | |
1279 | ||
1280 | static int hva_register_device(struct hva_dev *hva) | |
1281 | { | |
1282 | int ret; | |
1283 | struct video_device *vdev; | |
1284 | struct device *dev; | |
1285 | ||
1286 | if (!hva) | |
1287 | return -ENODEV; | |
1288 | dev = hva_to_dev(hva); | |
1289 | ||
1290 | hva->m2m_dev = v4l2_m2m_init(&hva_m2m_ops); | |
1291 | if (IS_ERR(hva->m2m_dev)) { | |
1292 | dev_err(dev, "%s failed to initialize v4l2-m2m device\n", | |
1293 | HVA_PREFIX); | |
1294 | ret = PTR_ERR(hva->m2m_dev); | |
1295 | goto err; | |
1296 | } | |
1297 | ||
1298 | vdev = video_device_alloc(); | |
1299 | if (!vdev) { | |
1300 | dev_err(dev, "%s failed to allocate video device\n", | |
1301 | HVA_PREFIX); | |
1302 | ret = -ENOMEM; | |
1303 | goto err_m2m_release; | |
1304 | } | |
1305 | ||
1306 | vdev->fops = &hva_fops; | |
1307 | vdev->ioctl_ops = &hva_ioctl_ops; | |
1308 | vdev->release = video_device_release; | |
1309 | vdev->lock = &hva->lock; | |
1310 | vdev->vfl_dir = VFL_DIR_M2M; | |
1311 | vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M; | |
1312 | vdev->v4l2_dev = &hva->v4l2_dev; | |
1313 | snprintf(vdev->name, sizeof(vdev->name), "%s%lx", HVA_NAME, | |
1314 | hva->ip_version); | |
1315 | ||
1316 | ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | |
1317 | if (ret) { | |
1318 | dev_err(dev, "%s failed to register video device\n", | |
1319 | HVA_PREFIX); | |
1320 | goto err_vdev_release; | |
1321 | } | |
1322 | ||
1323 | hva->vdev = vdev; | |
1324 | video_set_drvdata(vdev, hva); | |
1325 | return 0; | |
1326 | ||
1327 | err_vdev_release: | |
1328 | video_device_release(vdev); | |
1329 | err_m2m_release: | |
1330 | v4l2_m2m_release(hva->m2m_dev); | |
1331 | err: | |
1332 | return ret; | |
1333 | } | |
1334 | ||
1335 | static void hva_unregister_device(struct hva_dev *hva) | |
1336 | { | |
1337 | if (!hva) | |
1338 | return; | |
1339 | ||
1340 | if (hva->m2m_dev) | |
1341 | v4l2_m2m_release(hva->m2m_dev); | |
1342 | ||
1343 | video_unregister_device(hva->vdev); | |
1344 | } | |
1345 | ||
1346 | static int hva_probe(struct platform_device *pdev) | |
1347 | { | |
1348 | struct hva_dev *hva; | |
1349 | struct device *dev = &pdev->dev; | |
1350 | int ret; | |
1351 | ||
1352 | hva = devm_kzalloc(dev, sizeof(*hva), GFP_KERNEL); | |
1353 | if (!hva) { | |
1354 | ret = -ENOMEM; | |
1355 | goto err; | |
1356 | } | |
1357 | ||
1358 | hva->dev = dev; | |
1359 | hva->pdev = pdev; | |
1360 | platform_set_drvdata(pdev, hva); | |
1361 | ||
1362 | mutex_init(&hva->lock); | |
1363 | ||
1364 | /* probe hardware */ | |
1365 | ret = hva_hw_probe(pdev, hva); | |
1366 | if (ret) | |
1367 | goto err; | |
1368 | ||
1369 | /* register all available encoders */ | |
1370 | register_encoders(hva); | |
1371 | ||
1372 | /* register all supported formats */ | |
1373 | register_formats(hva); | |
1374 | ||
1375 | /* register on V4L2 */ | |
1376 | ret = v4l2_device_register(dev, &hva->v4l2_dev); | |
1377 | if (ret) { | |
1378 | dev_err(dev, "%s %s failed to register V4L2 device\n", | |
1379 | HVA_PREFIX, HVA_NAME); | |
1380 | goto err_hw; | |
1381 | } | |
1382 | ||
c610b5a8 JCT |
1383 | #ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS |
1384 | hva_debugfs_create(hva); | |
1385 | #endif | |
1386 | ||
57b2c062 JCT |
1387 | hva->work_queue = create_workqueue(HVA_NAME); |
1388 | if (!hva->work_queue) { | |
1389 | dev_err(dev, "%s %s failed to allocate work queue\n", | |
1390 | HVA_PREFIX, HVA_NAME); | |
1391 | ret = -ENOMEM; | |
1392 | goto err_v4l2; | |
1393 | } | |
1394 | ||
1395 | /* register device */ | |
1396 | ret = hva_register_device(hva); | |
1397 | if (ret) | |
1398 | goto err_work_queue; | |
1399 | ||
1400 | dev_info(dev, "%s %s registered as /dev/video%d\n", HVA_PREFIX, | |
1401 | HVA_NAME, hva->vdev->num); | |
1402 | ||
1403 | return 0; | |
1404 | ||
1405 | err_work_queue: | |
1406 | destroy_workqueue(hva->work_queue); | |
1407 | err_v4l2: | |
c610b5a8 JCT |
1408 | #ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS |
1409 | hva_debugfs_remove(hva); | |
1410 | #endif | |
57b2c062 JCT |
1411 | v4l2_device_unregister(&hva->v4l2_dev); |
1412 | err_hw: | |
1413 | hva_hw_remove(hva); | |
1414 | err: | |
1415 | return ret; | |
1416 | } | |
1417 | ||
1418 | static int hva_remove(struct platform_device *pdev) | |
1419 | { | |
1420 | struct hva_dev *hva = platform_get_drvdata(pdev); | |
1421 | struct device *dev = hva_to_dev(hva); | |
1422 | ||
1423 | hva_unregister_device(hva); | |
1424 | ||
1425 | destroy_workqueue(hva->work_queue); | |
1426 | ||
1427 | hva_hw_remove(hva); | |
1428 | ||
c610b5a8 JCT |
1429 | #ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS |
1430 | hva_debugfs_remove(hva); | |
1431 | #endif | |
1432 | ||
57b2c062 JCT |
1433 | v4l2_device_unregister(&hva->v4l2_dev); |
1434 | ||
1435 | dev_info(dev, "%s %s removed\n", HVA_PREFIX, pdev->name); | |
1436 | ||
1437 | return 0; | |
1438 | } | |
1439 | ||
1440 | /* PM ops */ | |
1441 | static const struct dev_pm_ops hva_pm_ops = { | |
1442 | .runtime_suspend = hva_hw_runtime_suspend, | |
1443 | .runtime_resume = hva_hw_runtime_resume, | |
1444 | }; | |
1445 | ||
1446 | static const struct of_device_id hva_match_types[] = { | |
1447 | { | |
1448 | .compatible = "st,st-hva", | |
1449 | }, | |
1450 | { /* end node */ } | |
1451 | }; | |
1452 | ||
1453 | MODULE_DEVICE_TABLE(of, hva_match_types); | |
1454 | ||
19de16c0 | 1455 | static struct platform_driver hva_driver = { |
57b2c062 JCT |
1456 | .probe = hva_probe, |
1457 | .remove = hva_remove, | |
1458 | .driver = { | |
1459 | .name = HVA_NAME, | |
1460 | .of_match_table = hva_match_types, | |
1461 | .pm = &hva_pm_ops, | |
1462 | }, | |
1463 | }; | |
1464 | ||
1465 | module_platform_driver(hva_driver); | |
1466 | ||
1467 | MODULE_LICENSE("GPL"); | |
1468 | MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>"); | |
1469 | MODULE_DESCRIPTION("STMicroelectronics HVA video encoder V4L2 driver"); |