1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Rockchip Video Decoder driver |
4 | * |
5 | * Copyright (C) 2019 Collabora, Ltd. |
6 | * |
7 | * Based on rkvdec driver by Google LLC. (Tomasz Figa <tfiga@chromium.org>) |
8 | * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. |
9 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. |
10 | */ |
11 | |
12 | #include <linux/clk.h> |
13 | #include <linux/interrupt.h> |
14 | #include <linux/module.h> |
15 | #include <linux/of.h> |
16 | #include <linux/platform_device.h> |
17 | #include <linux/pm.h> |
18 | #include <linux/pm_runtime.h> |
19 | #include <linux/slab.h> |
20 | #include <linux/videodev2.h> |
21 | #include <linux/workqueue.h> |
22 | #include <media/v4l2-event.h> |
23 | #include <media/v4l2-mem2mem.h> |
24 | #include <media/videobuf2-core.h> |
25 | #include <media/videobuf2-vmalloc.h> |
26 | |
27 | #include "rkvdec.h" |
28 | #include "rkvdec-regs.h" |
29 | |
30 | static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) |
31 | { |
32 | struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl); |
33 | const struct rkvdec_coded_fmt_desc *desc = ctx->coded_fmt_desc; |
34 | |
35 | if (desc->ops->try_ctrl) |
36 | return desc->ops->try_ctrl(ctx, ctrl); |
37 | |
38 | return 0; |
39 | } |
40 | |
41 | static const struct v4l2_ctrl_ops rkvdec_ctrl_ops = { |
42 | .try_ctrl = rkvdec_try_ctrl, |
43 | }; |
44 | |
45 | static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = { |
46 | { |
47 | .cfg.id = V4L2_CID_STATELESS_H264_DECODE_PARAMS, |
48 | }, |
49 | { |
50 | .cfg.id = V4L2_CID_STATELESS_H264_SPS, |
51 | .cfg.ops = &rkvdec_ctrl_ops, |
52 | }, |
53 | { |
54 | .cfg.id = V4L2_CID_STATELESS_H264_PPS, |
55 | }, |
56 | { |
57 | .cfg.id = V4L2_CID_STATELESS_H264_SCALING_MATRIX, |
58 | }, |
59 | { |
60 | .cfg.id = V4L2_CID_STATELESS_H264_DECODE_MODE, |
61 | .cfg.min = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, |
62 | .cfg.max = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, |
63 | .cfg.def = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, |
64 | }, |
65 | { |
66 | .cfg.id = V4L2_CID_STATELESS_H264_START_CODE, |
67 | .cfg.min = V4L2_STATELESS_H264_START_CODE_ANNEX_B, |
68 | .cfg.def = V4L2_STATELESS_H264_START_CODE_ANNEX_B, |
69 | .cfg.max = V4L2_STATELESS_H264_START_CODE_ANNEX_B, |
70 | }, |
71 | { |
72 | .cfg.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, |
73 | .cfg.min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, |
74 | .cfg.max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, |
75 | .cfg.menu_skip_mask = |
76 | BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED), |
77 | .cfg.def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN, |
78 | }, |
79 | { |
80 | .cfg.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, |
81 | .cfg.min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, |
82 | .cfg.max = V4L2_MPEG_VIDEO_H264_LEVEL_5_1, |
83 | }, |
84 | }; |
85 | |
86 | static const struct rkvdec_ctrls rkvdec_h264_ctrls = { |
87 | .ctrls = rkvdec_h264_ctrl_descs, |
88 | .num_ctrls = ARRAY_SIZE(rkvdec_h264_ctrl_descs), |
89 | }; |
90 | |
91 | static const u32 rkvdec_h264_vp9_decoded_fmts[] = { |
92 | V4L2_PIX_FMT_NV12, |
93 | }; |
94 | |
95 | static const struct rkvdec_ctrl_desc rkvdec_vp9_ctrl_descs[] = { |
96 | { |
97 | .cfg.id = V4L2_CID_STATELESS_VP9_FRAME, |
98 | }, |
99 | { |
100 | .cfg.id = V4L2_CID_STATELESS_VP9_COMPRESSED_HDR, |
101 | }, |
102 | { |
103 | .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_PROFILE, |
104 | .cfg.min = V4L2_MPEG_VIDEO_VP9_PROFILE_0, |
105 | .cfg.max = V4L2_MPEG_VIDEO_VP9_PROFILE_0, |
106 | .cfg.def = V4L2_MPEG_VIDEO_VP9_PROFILE_0, |
107 | }, |
108 | }; |
109 | |
110 | static const struct rkvdec_ctrls rkvdec_vp9_ctrls = { |
111 | .ctrls = rkvdec_vp9_ctrl_descs, |
112 | .num_ctrls = ARRAY_SIZE(rkvdec_vp9_ctrl_descs), |
113 | }; |
114 | |
115 | static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = { |
116 | { |
117 | .fourcc = V4L2_PIX_FMT_H264_SLICE, |
118 | .frmsize = { |
119 | .min_width = 48, |
120 | .max_width = 4096, |
121 | .step_width = 16, |
122 | .min_height = 48, |
123 | .max_height = 2560, |
124 | .step_height = 16, |
125 | }, |
126 | .ctrls = &rkvdec_h264_ctrls, |
127 | .ops = &rkvdec_h264_fmt_ops, |
128 | .num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_vp9_decoded_fmts), |
129 | .decoded_fmts = rkvdec_h264_vp9_decoded_fmts, |
130 | .subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF, |
131 | }, |
132 | { |
133 | .fourcc = V4L2_PIX_FMT_VP9_FRAME, |
134 | .frmsize = { |
135 | .min_width = 64, |
136 | .max_width = 4096, |
137 | .step_width = 64, |
138 | .min_height = 64, |
139 | .max_height = 2304, |
140 | .step_height = 64, |
141 | }, |
142 | .ctrls = &rkvdec_vp9_ctrls, |
143 | .ops = &rkvdec_vp9_fmt_ops, |
144 | .num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_vp9_decoded_fmts), |
145 | .decoded_fmts = rkvdec_h264_vp9_decoded_fmts, |
146 | } |
147 | }; |
148 | |
149 | static const struct rkvdec_coded_fmt_desc * |
150 | rkvdec_find_coded_fmt_desc(u32 fourcc) |
151 | { |
152 | unsigned int i; |
153 | |
154 | for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) { |
155 | if (rkvdec_coded_fmts[i].fourcc == fourcc) |
156 | return &rkvdec_coded_fmts[i]; |
157 | } |
158 | |
159 | return NULL; |
160 | } |
161 | |
162 | static void rkvdec_reset_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f, |
163 | u32 fourcc) |
164 | { |
165 | memset(f, 0, sizeof(*f)); |
166 | f->fmt.pix_mp.pixelformat = fourcc; |
167 | f->fmt.pix_mp.field = V4L2_FIELD_NONE; |
168 | f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709; |
169 | f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; |
170 | f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; |
171 | f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; |
172 | } |
173 | |
174 | static void rkvdec_reset_coded_fmt(struct rkvdec_ctx *ctx) |
175 | { |
176 | struct v4l2_format *f = &ctx->coded_fmt; |
177 | |
178 | ctx->coded_fmt_desc = &rkvdec_coded_fmts[0]; |
179 | rkvdec_reset_fmt(ctx, f, fourcc: ctx->coded_fmt_desc->fourcc); |
180 | |
181 | f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
182 | f->fmt.pix_mp.width = ctx->coded_fmt_desc->frmsize.min_width; |
183 | f->fmt.pix_mp.height = ctx->coded_fmt_desc->frmsize.min_height; |
184 | |
185 | if (ctx->coded_fmt_desc->ops->adjust_fmt) |
186 | ctx->coded_fmt_desc->ops->adjust_fmt(ctx, f); |
187 | } |
188 | |
189 | static void rkvdec_reset_decoded_fmt(struct rkvdec_ctx *ctx) |
190 | { |
191 | struct v4l2_format *f = &ctx->decoded_fmt; |
192 | |
193 | rkvdec_reset_fmt(ctx, f, fourcc: ctx->coded_fmt_desc->decoded_fmts[0]); |
194 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
195 | v4l2_fill_pixfmt_mp(pixfmt: &f->fmt.pix_mp, |
196 | pixelformat: ctx->coded_fmt_desc->decoded_fmts[0], |
197 | width: ctx->coded_fmt.fmt.pix_mp.width, |
198 | height: ctx->coded_fmt.fmt.pix_mp.height); |
199 | f->fmt.pix_mp.plane_fmt[0].sizeimage += 128 * |
200 | DIV_ROUND_UP(f->fmt.pix_mp.width, 16) * |
201 | DIV_ROUND_UP(f->fmt.pix_mp.height, 16); |
202 | } |
203 | |
204 | static int rkvdec_enum_framesizes(struct file *file, void *priv, |
205 | struct v4l2_frmsizeenum *fsize) |
206 | { |
207 | const struct rkvdec_coded_fmt_desc *fmt; |
208 | |
209 | if (fsize->index != 0) |
210 | return -EINVAL; |
211 | |
212 | fmt = rkvdec_find_coded_fmt_desc(fourcc: fsize->pixel_format); |
213 | if (!fmt) |
214 | return -EINVAL; |
215 | |
216 | fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; |
217 | fsize->stepwise = fmt->frmsize; |
218 | return 0; |
219 | } |
220 | |
221 | static int rkvdec_querycap(struct file *file, void *priv, |
222 | struct v4l2_capability *cap) |
223 | { |
224 | struct rkvdec_dev *rkvdec = video_drvdata(file); |
225 | struct video_device *vdev = video_devdata(file); |
226 | |
227 | strscpy(cap->driver, rkvdec->dev->driver->name, |
228 | sizeof(cap->driver)); |
229 | strscpy(cap->card, vdev->name, sizeof(cap->card)); |
230 | snprintf(buf: cap->bus_info, size: sizeof(cap->bus_info), fmt: "platform:%s" , |
231 | rkvdec->dev->driver->name); |
232 | return 0; |
233 | } |
234 | |
235 | static int rkvdec_try_capture_fmt(struct file *file, void *priv, |
236 | struct v4l2_format *f) |
237 | { |
238 | struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; |
239 | struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(fh: priv); |
240 | const struct rkvdec_coded_fmt_desc *coded_desc; |
241 | unsigned int i; |
242 | |
243 | /* |
244 | * The codec context should point to a coded format desc, if the format |
245 | * on the coded end has not been set yet, it should point to the |
246 | * default value. |
247 | */ |
248 | coded_desc = ctx->coded_fmt_desc; |
249 | if (WARN_ON(!coded_desc)) |
250 | return -EINVAL; |
251 | |
252 | for (i = 0; i < coded_desc->num_decoded_fmts; i++) { |
253 | if (coded_desc->decoded_fmts[i] == pix_mp->pixelformat) |
254 | break; |
255 | } |
256 | |
257 | if (i == coded_desc->num_decoded_fmts) |
258 | pix_mp->pixelformat = coded_desc->decoded_fmts[0]; |
259 | |
260 | /* Always apply the frmsize constraint of the coded end. */ |
261 | pix_mp->width = max(pix_mp->width, ctx->coded_fmt.fmt.pix_mp.width); |
262 | pix_mp->height = max(pix_mp->height, ctx->coded_fmt.fmt.pix_mp.height); |
263 | v4l2_apply_frmsize_constraints(width: &pix_mp->width, |
264 | height: &pix_mp->height, |
265 | frmsize: &coded_desc->frmsize); |
266 | |
267 | v4l2_fill_pixfmt_mp(pixfmt: pix_mp, pixelformat: pix_mp->pixelformat, |
268 | width: pix_mp->width, height: pix_mp->height); |
269 | pix_mp->plane_fmt[0].sizeimage += |
270 | 128 * |
271 | DIV_ROUND_UP(pix_mp->width, 16) * |
272 | DIV_ROUND_UP(pix_mp->height, 16); |
273 | pix_mp->field = V4L2_FIELD_NONE; |
274 | |
275 | return 0; |
276 | } |
277 | |
278 | static int rkvdec_try_output_fmt(struct file *file, void *priv, |
279 | struct v4l2_format *f) |
280 | { |
281 | struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; |
282 | struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(fh: priv); |
283 | const struct rkvdec_coded_fmt_desc *desc; |
284 | |
285 | desc = rkvdec_find_coded_fmt_desc(fourcc: pix_mp->pixelformat); |
286 | if (!desc) { |
287 | pix_mp->pixelformat = rkvdec_coded_fmts[0].fourcc; |
288 | desc = &rkvdec_coded_fmts[0]; |
289 | } |
290 | |
291 | v4l2_apply_frmsize_constraints(width: &pix_mp->width, |
292 | height: &pix_mp->height, |
293 | frmsize: &desc->frmsize); |
294 | |
295 | pix_mp->field = V4L2_FIELD_NONE; |
296 | /* All coded formats are considered single planar for now. */ |
297 | pix_mp->num_planes = 1; |
298 | |
299 | if (desc->ops->adjust_fmt) { |
300 | int ret; |
301 | |
302 | ret = desc->ops->adjust_fmt(ctx, f); |
303 | if (ret) |
304 | return ret; |
305 | } |
306 | |
307 | return 0; |
308 | } |
309 | |
310 | static int rkvdec_s_capture_fmt(struct file *file, void *priv, |
311 | struct v4l2_format *f) |
312 | { |
313 | struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(fh: priv); |
314 | struct vb2_queue *vq; |
315 | int ret; |
316 | |
317 | /* Change not allowed if queue is busy */ |
318 | vq = v4l2_m2m_get_vq(m2m_ctx: ctx->fh.m2m_ctx, |
319 | type: V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); |
320 | if (vb2_is_busy(q: vq)) |
321 | return -EBUSY; |
322 | |
323 | ret = rkvdec_try_capture_fmt(file, priv, f); |
324 | if (ret) |
325 | return ret; |
326 | |
327 | ctx->decoded_fmt = *f; |
328 | return 0; |
329 | } |
330 | |
331 | static int rkvdec_s_output_fmt(struct file *file, void *priv, |
332 | struct v4l2_format *f) |
333 | { |
334 | struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(fh: priv); |
335 | struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; |
336 | const struct rkvdec_coded_fmt_desc *desc; |
337 | struct v4l2_format *cap_fmt; |
338 | struct vb2_queue *peer_vq, *vq; |
339 | int ret; |
340 | |
341 | /* |
342 | * In order to support dynamic resolution change, the decoder admits |
343 | * a resolution change, as long as the pixelformat remains. Can't be |
344 | * done if streaming. |
345 | */ |
346 | vq = v4l2_m2m_get_vq(m2m_ctx, type: V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); |
347 | if (vb2_is_streaming(q: vq) || |
348 | (vb2_is_busy(q: vq) && |
349 | f->fmt.pix_mp.pixelformat != ctx->coded_fmt.fmt.pix_mp.pixelformat)) |
350 | return -EBUSY; |
351 | |
352 | /* |
353 | * Since format change on the OUTPUT queue will reset the CAPTURE |
354 | * queue, we can't allow doing so when the CAPTURE queue has buffers |
355 | * allocated. |
356 | */ |
357 | peer_vq = v4l2_m2m_get_vq(m2m_ctx, type: V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); |
358 | if (vb2_is_busy(q: peer_vq)) |
359 | return -EBUSY; |
360 | |
361 | ret = rkvdec_try_output_fmt(file, priv, f); |
362 | if (ret) |
363 | return ret; |
364 | |
365 | desc = rkvdec_find_coded_fmt_desc(fourcc: f->fmt.pix_mp.pixelformat); |
366 | if (!desc) |
367 | return -EINVAL; |
368 | ctx->coded_fmt_desc = desc; |
369 | ctx->coded_fmt = *f; |
370 | |
371 | /* |
372 | * Current decoded format might have become invalid with newly |
373 | * selected codec, so reset it to default just to be safe and |
374 | * keep internal driver state sane. User is mandated to set |
375 | * the decoded format again after we return, so we don't need |
376 | * anything smarter. |
377 | * |
378 | * Note that this will propagates any size changes to the decoded format. |
379 | */ |
380 | rkvdec_reset_decoded_fmt(ctx); |
381 | |
382 | /* Propagate colorspace information to capture. */ |
383 | cap_fmt = &ctx->decoded_fmt; |
384 | cap_fmt->fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace; |
385 | cap_fmt->fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func; |
386 | cap_fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; |
387 | cap_fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization; |
388 | |
389 | /* Enable format specific queue features */ |
390 | vq->subsystem_flags |= desc->subsystem_flags; |
391 | |
392 | return 0; |
393 | } |
394 | |
395 | static int rkvdec_g_output_fmt(struct file *file, void *priv, |
396 | struct v4l2_format *f) |
397 | { |
398 | struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(fh: priv); |
399 | |
400 | *f = ctx->coded_fmt; |
401 | return 0; |
402 | } |
403 | |
404 | static int rkvdec_g_capture_fmt(struct file *file, void *priv, |
405 | struct v4l2_format *f) |
406 | { |
407 | struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(fh: priv); |
408 | |
409 | *f = ctx->decoded_fmt; |
410 | return 0; |
411 | } |
412 | |
413 | static int rkvdec_enum_output_fmt(struct file *file, void *priv, |
414 | struct v4l2_fmtdesc *f) |
415 | { |
416 | if (f->index >= ARRAY_SIZE(rkvdec_coded_fmts)) |
417 | return -EINVAL; |
418 | |
419 | f->pixelformat = rkvdec_coded_fmts[f->index].fourcc; |
420 | return 0; |
421 | } |
422 | |
423 | static int rkvdec_enum_capture_fmt(struct file *file, void *priv, |
424 | struct v4l2_fmtdesc *f) |
425 | { |
426 | struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(fh: priv); |
427 | |
428 | if (WARN_ON(!ctx->coded_fmt_desc)) |
429 | return -EINVAL; |
430 | |
431 | if (f->index >= ctx->coded_fmt_desc->num_decoded_fmts) |
432 | return -EINVAL; |
433 | |
434 | f->pixelformat = ctx->coded_fmt_desc->decoded_fmts[f->index]; |
435 | return 0; |
436 | } |
437 | |
438 | static const struct v4l2_ioctl_ops rkvdec_ioctl_ops = { |
439 | .vidioc_querycap = rkvdec_querycap, |
440 | .vidioc_enum_framesizes = rkvdec_enum_framesizes, |
441 | |
442 | .vidioc_try_fmt_vid_cap_mplane = rkvdec_try_capture_fmt, |
443 | .vidioc_try_fmt_vid_out_mplane = rkvdec_try_output_fmt, |
444 | .vidioc_s_fmt_vid_out_mplane = rkvdec_s_output_fmt, |
445 | .vidioc_s_fmt_vid_cap_mplane = rkvdec_s_capture_fmt, |
446 | .vidioc_g_fmt_vid_out_mplane = rkvdec_g_output_fmt, |
447 | .vidioc_g_fmt_vid_cap_mplane = rkvdec_g_capture_fmt, |
448 | .vidioc_enum_fmt_vid_out = rkvdec_enum_output_fmt, |
449 | .vidioc_enum_fmt_vid_cap = rkvdec_enum_capture_fmt, |
450 | |
451 | .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, |
452 | .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, |
453 | .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, |
454 | .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, |
455 | .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, |
456 | .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, |
457 | .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, |
458 | |
459 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, |
460 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, |
461 | |
462 | .vidioc_streamon = v4l2_m2m_ioctl_streamon, |
463 | .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, |
464 | |
465 | .vidioc_decoder_cmd = v4l2_m2m_ioctl_stateless_decoder_cmd, |
466 | .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_stateless_try_decoder_cmd, |
467 | }; |
468 | |
469 | static int rkvdec_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, |
470 | unsigned int *num_planes, unsigned int sizes[], |
471 | struct device *alloc_devs[]) |
472 | { |
473 | struct rkvdec_ctx *ctx = vb2_get_drv_priv(q: vq); |
474 | struct v4l2_format *f; |
475 | unsigned int i; |
476 | |
477 | if (V4L2_TYPE_IS_OUTPUT(vq->type)) |
478 | f = &ctx->coded_fmt; |
479 | else |
480 | f = &ctx->decoded_fmt; |
481 | |
482 | if (*num_planes) { |
483 | if (*num_planes != f->fmt.pix_mp.num_planes) |
484 | return -EINVAL; |
485 | |
486 | for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { |
487 | if (sizes[i] < f->fmt.pix_mp.plane_fmt[i].sizeimage) |
488 | return -EINVAL; |
489 | } |
490 | } else { |
491 | *num_planes = f->fmt.pix_mp.num_planes; |
492 | for (i = 0; i < f->fmt.pix_mp.num_planes; i++) |
493 | sizes[i] = f->fmt.pix_mp.plane_fmt[i].sizeimage; |
494 | } |
495 | |
496 | return 0; |
497 | } |
498 | |
499 | static int rkvdec_buf_prepare(struct vb2_buffer *vb) |
500 | { |
501 | struct vb2_queue *vq = vb->vb2_queue; |
502 | struct rkvdec_ctx *ctx = vb2_get_drv_priv(q: vq); |
503 | struct v4l2_format *f; |
504 | unsigned int i; |
505 | |
506 | if (V4L2_TYPE_IS_OUTPUT(vq->type)) |
507 | f = &ctx->coded_fmt; |
508 | else |
509 | f = &ctx->decoded_fmt; |
510 | |
511 | for (i = 0; i < f->fmt.pix_mp.num_planes; ++i) { |
512 | u32 sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage; |
513 | |
514 | if (vb2_plane_size(vb, plane_no: i) < sizeimage) |
515 | return -EINVAL; |
516 | } |
517 | |
518 | /* |
519 | * Buffer's bytesused must be written by driver for CAPTURE buffers. |
520 | * (for OUTPUT buffers, if userspace passes 0 bytesused, v4l2-core sets |
521 | * it to buffer length). |
522 | */ |
523 | if (V4L2_TYPE_IS_CAPTURE(vq->type)) |
524 | vb2_set_plane_payload(vb, plane_no: 0, size: f->fmt.pix_mp.plane_fmt[0].sizeimage); |
525 | |
526 | return 0; |
527 | } |
528 | |
529 | static void rkvdec_buf_queue(struct vb2_buffer *vb) |
530 | { |
531 | struct rkvdec_ctx *ctx = vb2_get_drv_priv(q: vb->vb2_queue); |
532 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
533 | |
534 | v4l2_m2m_buf_queue(m2m_ctx: ctx->fh.m2m_ctx, vbuf); |
535 | } |
536 | |
537 | static int rkvdec_buf_out_validate(struct vb2_buffer *vb) |
538 | { |
539 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
540 | |
541 | vbuf->field = V4L2_FIELD_NONE; |
542 | return 0; |
543 | } |
544 | |
545 | static void rkvdec_buf_request_complete(struct vb2_buffer *vb) |
546 | { |
547 | struct rkvdec_ctx *ctx = vb2_get_drv_priv(q: vb->vb2_queue); |
548 | |
549 | v4l2_ctrl_request_complete(req: vb->req_obj.req, parent: &ctx->ctrl_hdl); |
550 | } |
551 | |
552 | static int rkvdec_start_streaming(struct vb2_queue *q, unsigned int count) |
553 | { |
554 | struct rkvdec_ctx *ctx = vb2_get_drv_priv(q); |
555 | const struct rkvdec_coded_fmt_desc *desc; |
556 | int ret; |
557 | |
558 | if (V4L2_TYPE_IS_CAPTURE(q->type)) |
559 | return 0; |
560 | |
561 | desc = ctx->coded_fmt_desc; |
562 | if (WARN_ON(!desc)) |
563 | return -EINVAL; |
564 | |
565 | if (desc->ops->start) { |
566 | ret = desc->ops->start(ctx); |
567 | if (ret) |
568 | return ret; |
569 | } |
570 | |
571 | return 0; |
572 | } |
573 | |
574 | static void rkvdec_queue_cleanup(struct vb2_queue *vq, u32 state) |
575 | { |
576 | struct rkvdec_ctx *ctx = vb2_get_drv_priv(q: vq); |
577 | |
578 | while (true) { |
579 | struct vb2_v4l2_buffer *vbuf; |
580 | |
581 | if (V4L2_TYPE_IS_OUTPUT(vq->type)) |
582 | vbuf = v4l2_m2m_src_buf_remove(m2m_ctx: ctx->fh.m2m_ctx); |
583 | else |
584 | vbuf = v4l2_m2m_dst_buf_remove(m2m_ctx: ctx->fh.m2m_ctx); |
585 | |
586 | if (!vbuf) |
587 | break; |
588 | |
589 | v4l2_ctrl_request_complete(req: vbuf->vb2_buf.req_obj.req, |
590 | parent: &ctx->ctrl_hdl); |
591 | v4l2_m2m_buf_done(buf: vbuf, state); |
592 | } |
593 | } |
594 | |
595 | static void rkvdec_stop_streaming(struct vb2_queue *q) |
596 | { |
597 | struct rkvdec_ctx *ctx = vb2_get_drv_priv(q); |
598 | |
599 | if (V4L2_TYPE_IS_OUTPUT(q->type)) { |
600 | const struct rkvdec_coded_fmt_desc *desc = ctx->coded_fmt_desc; |
601 | |
602 | if (WARN_ON(!desc)) |
603 | return; |
604 | |
605 | if (desc->ops->stop) |
606 | desc->ops->stop(ctx); |
607 | } |
608 | |
609 | rkvdec_queue_cleanup(vq: q, state: VB2_BUF_STATE_ERROR); |
610 | } |
611 | |
612 | static const struct vb2_ops rkvdec_queue_ops = { |
613 | .queue_setup = rkvdec_queue_setup, |
614 | .buf_prepare = rkvdec_buf_prepare, |
615 | .buf_queue = rkvdec_buf_queue, |
616 | .buf_out_validate = rkvdec_buf_out_validate, |
617 | .buf_request_complete = rkvdec_buf_request_complete, |
618 | .start_streaming = rkvdec_start_streaming, |
619 | .stop_streaming = rkvdec_stop_streaming, |
620 | .wait_prepare = vb2_ops_wait_prepare, |
621 | .wait_finish = vb2_ops_wait_finish, |
622 | }; |
623 | |
624 | static int rkvdec_request_validate(struct media_request *req) |
625 | { |
626 | unsigned int count; |
627 | |
628 | count = vb2_request_buffer_cnt(req); |
629 | if (!count) |
630 | return -ENOENT; |
631 | else if (count > 1) |
632 | return -EINVAL; |
633 | |
634 | return vb2_request_validate(req); |
635 | } |
636 | |
637 | static const struct media_device_ops rkvdec_media_ops = { |
638 | .req_validate = rkvdec_request_validate, |
639 | .req_queue = v4l2_m2m_request_queue, |
640 | }; |
641 | |
642 | static void rkvdec_job_finish_no_pm(struct rkvdec_ctx *ctx, |
643 | enum vb2_buffer_state result) |
644 | { |
645 | if (ctx->coded_fmt_desc->ops->done) { |
646 | struct vb2_v4l2_buffer *src_buf, *dst_buf; |
647 | |
648 | src_buf = v4l2_m2m_next_src_buf(m2m_ctx: ctx->fh.m2m_ctx); |
649 | dst_buf = v4l2_m2m_next_dst_buf(m2m_ctx: ctx->fh.m2m_ctx); |
650 | ctx->coded_fmt_desc->ops->done(ctx, src_buf, dst_buf, result); |
651 | } |
652 | |
653 | v4l2_m2m_buf_done_and_job_finish(m2m_dev: ctx->dev->m2m_dev, m2m_ctx: ctx->fh.m2m_ctx, |
654 | state: result); |
655 | } |
656 | |
657 | static void rkvdec_job_finish(struct rkvdec_ctx *ctx, |
658 | enum vb2_buffer_state result) |
659 | { |
660 | struct rkvdec_dev *rkvdec = ctx->dev; |
661 | |
662 | pm_runtime_mark_last_busy(dev: rkvdec->dev); |
663 | pm_runtime_put_autosuspend(dev: rkvdec->dev); |
664 | rkvdec_job_finish_no_pm(ctx, result); |
665 | } |
666 | |
667 | void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run) |
668 | { |
669 | struct media_request *src_req; |
670 | |
671 | memset(run, 0, sizeof(*run)); |
672 | |
673 | run->bufs.src = v4l2_m2m_next_src_buf(m2m_ctx: ctx->fh.m2m_ctx); |
674 | run->bufs.dst = v4l2_m2m_next_dst_buf(m2m_ctx: ctx->fh.m2m_ctx); |
675 | |
676 | /* Apply request(s) controls if needed. */ |
677 | src_req = run->bufs.src->vb2_buf.req_obj.req; |
678 | if (src_req) |
679 | v4l2_ctrl_request_setup(req: src_req, parent: &ctx->ctrl_hdl); |
680 | |
681 | v4l2_m2m_buf_copy_metadata(out_vb: run->bufs.src, cap_vb: run->bufs.dst, copy_frame_flags: true); |
682 | } |
683 | |
684 | void rkvdec_run_postamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run) |
685 | { |
686 | struct media_request *src_req = run->bufs.src->vb2_buf.req_obj.req; |
687 | |
688 | if (src_req) |
689 | v4l2_ctrl_request_complete(req: src_req, parent: &ctx->ctrl_hdl); |
690 | } |
691 | |
692 | static void rkvdec_device_run(void *priv) |
693 | { |
694 | struct rkvdec_ctx *ctx = priv; |
695 | struct rkvdec_dev *rkvdec = ctx->dev; |
696 | const struct rkvdec_coded_fmt_desc *desc = ctx->coded_fmt_desc; |
697 | int ret; |
698 | |
699 | if (WARN_ON(!desc)) |
700 | return; |
701 | |
702 | ret = pm_runtime_resume_and_get(dev: rkvdec->dev); |
703 | if (ret < 0) { |
704 | rkvdec_job_finish_no_pm(ctx, result: VB2_BUF_STATE_ERROR); |
705 | return; |
706 | } |
707 | |
708 | ret = desc->ops->run(ctx); |
709 | if (ret) |
710 | rkvdec_job_finish(ctx, result: VB2_BUF_STATE_ERROR); |
711 | } |
712 | |
713 | static const struct v4l2_m2m_ops rkvdec_m2m_ops = { |
714 | .device_run = rkvdec_device_run, |
715 | }; |
716 | |
717 | static int rkvdec_queue_init(void *priv, |
718 | struct vb2_queue *src_vq, |
719 | struct vb2_queue *dst_vq) |
720 | { |
721 | struct rkvdec_ctx *ctx = priv; |
722 | struct rkvdec_dev *rkvdec = ctx->dev; |
723 | int ret; |
724 | |
725 | src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
726 | src_vq->io_modes = VB2_MMAP | VB2_DMABUF; |
727 | src_vq->drv_priv = ctx; |
728 | src_vq->ops = &rkvdec_queue_ops; |
729 | src_vq->mem_ops = &vb2_dma_contig_memops; |
730 | |
731 | /* |
732 | * Driver does mostly sequential access, so sacrifice TLB efficiency |
733 | * for faster allocation. Also, no CPU access on the source queue, |
734 | * so no kernel mapping needed. |
735 | */ |
736 | src_vq->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES | |
737 | DMA_ATTR_NO_KERNEL_MAPPING; |
738 | src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); |
739 | src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
740 | src_vq->lock = &rkvdec->vdev_lock; |
741 | src_vq->dev = rkvdec->v4l2_dev.dev; |
742 | src_vq->supports_requests = true; |
743 | src_vq->requires_requests = true; |
744 | |
745 | ret = vb2_queue_init(q: src_vq); |
746 | if (ret) |
747 | return ret; |
748 | |
749 | dst_vq->bidirectional = true; |
750 | dst_vq->mem_ops = &vb2_dma_contig_memops; |
751 | dst_vq->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES | |
752 | DMA_ATTR_NO_KERNEL_MAPPING; |
753 | dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
754 | dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; |
755 | dst_vq->drv_priv = ctx; |
756 | dst_vq->ops = &rkvdec_queue_ops; |
757 | dst_vq->buf_struct_size = sizeof(struct rkvdec_decoded_buffer); |
758 | dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
759 | dst_vq->lock = &rkvdec->vdev_lock; |
760 | dst_vq->dev = rkvdec->v4l2_dev.dev; |
761 | |
762 | return vb2_queue_init(q: dst_vq); |
763 | } |
764 | |
765 | static int rkvdec_add_ctrls(struct rkvdec_ctx *ctx, |
766 | const struct rkvdec_ctrls *ctrls) |
767 | { |
768 | unsigned int i; |
769 | |
770 | for (i = 0; i < ctrls->num_ctrls; i++) { |
771 | const struct v4l2_ctrl_config *cfg = &ctrls->ctrls[i].cfg; |
772 | |
773 | v4l2_ctrl_new_custom(hdl: &ctx->ctrl_hdl, cfg, priv: ctx); |
774 | if (ctx->ctrl_hdl.error) |
775 | return ctx->ctrl_hdl.error; |
776 | } |
777 | |
778 | return 0; |
779 | } |
780 | |
781 | static int rkvdec_init_ctrls(struct rkvdec_ctx *ctx) |
782 | { |
783 | unsigned int i, nctrls = 0; |
784 | int ret; |
785 | |
786 | for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) |
787 | nctrls += rkvdec_coded_fmts[i].ctrls->num_ctrls; |
788 | |
789 | v4l2_ctrl_handler_init(&ctx->ctrl_hdl, nctrls); |
790 | |
791 | for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) { |
792 | ret = rkvdec_add_ctrls(ctx, ctrls: rkvdec_coded_fmts[i].ctrls); |
793 | if (ret) |
794 | goto err_free_handler; |
795 | } |
796 | |
797 | ret = v4l2_ctrl_handler_setup(hdl: &ctx->ctrl_hdl); |
798 | if (ret) |
799 | goto err_free_handler; |
800 | |
801 | ctx->fh.ctrl_handler = &ctx->ctrl_hdl; |
802 | return 0; |
803 | |
804 | err_free_handler: |
805 | v4l2_ctrl_handler_free(hdl: &ctx->ctrl_hdl); |
806 | return ret; |
807 | } |
808 | |
809 | static int rkvdec_open(struct file *filp) |
810 | { |
811 | struct rkvdec_dev *rkvdec = video_drvdata(file: filp); |
812 | struct rkvdec_ctx *ctx; |
813 | int ret; |
814 | |
815 | ctx = kzalloc(size: sizeof(*ctx), GFP_KERNEL); |
816 | if (!ctx) |
817 | return -ENOMEM; |
818 | |
819 | ctx->dev = rkvdec; |
820 | rkvdec_reset_coded_fmt(ctx); |
821 | rkvdec_reset_decoded_fmt(ctx); |
822 | v4l2_fh_init(fh: &ctx->fh, vdev: video_devdata(file: filp)); |
823 | |
824 | ret = rkvdec_init_ctrls(ctx); |
825 | if (ret) |
826 | goto err_free_ctx; |
827 | |
828 | ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(m2m_dev: rkvdec->m2m_dev, drv_priv: ctx, |
829 | queue_init: rkvdec_queue_init); |
830 | if (IS_ERR(ptr: ctx->fh.m2m_ctx)) { |
831 | ret = PTR_ERR(ptr: ctx->fh.m2m_ctx); |
832 | goto err_cleanup_ctrls; |
833 | } |
834 | |
835 | filp->private_data = &ctx->fh; |
836 | v4l2_fh_add(fh: &ctx->fh); |
837 | |
838 | return 0; |
839 | |
840 | err_cleanup_ctrls: |
841 | v4l2_ctrl_handler_free(hdl: &ctx->ctrl_hdl); |
842 | |
843 | err_free_ctx: |
844 | kfree(objp: ctx); |
845 | return ret; |
846 | } |
847 | |
848 | static int rkvdec_release(struct file *filp) |
849 | { |
850 | struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(fh: filp->private_data); |
851 | |
852 | v4l2_fh_del(fh: &ctx->fh); |
853 | v4l2_m2m_ctx_release(m2m_ctx: ctx->fh.m2m_ctx); |
854 | v4l2_ctrl_handler_free(hdl: &ctx->ctrl_hdl); |
855 | v4l2_fh_exit(fh: &ctx->fh); |
856 | kfree(objp: ctx); |
857 | |
858 | return 0; |
859 | } |
860 | |
861 | static const struct v4l2_file_operations rkvdec_fops = { |
862 | .owner = THIS_MODULE, |
863 | .open = rkvdec_open, |
864 | .release = rkvdec_release, |
865 | .poll = v4l2_m2m_fop_poll, |
866 | .unlocked_ioctl = video_ioctl2, |
867 | .mmap = v4l2_m2m_fop_mmap, |
868 | }; |
869 | |
870 | static int rkvdec_v4l2_init(struct rkvdec_dev *rkvdec) |
871 | { |
872 | int ret; |
873 | |
874 | ret = v4l2_device_register(dev: rkvdec->dev, v4l2_dev: &rkvdec->v4l2_dev); |
875 | if (ret) { |
876 | dev_err(rkvdec->dev, "Failed to register V4L2 device\n" ); |
877 | return ret; |
878 | } |
879 | |
880 | rkvdec->m2m_dev = v4l2_m2m_init(m2m_ops: &rkvdec_m2m_ops); |
881 | if (IS_ERR(ptr: rkvdec->m2m_dev)) { |
882 | v4l2_err(&rkvdec->v4l2_dev, "Failed to init mem2mem device\n" ); |
883 | ret = PTR_ERR(ptr: rkvdec->m2m_dev); |
884 | goto err_unregister_v4l2; |
885 | } |
886 | |
887 | rkvdec->mdev.dev = rkvdec->dev; |
888 | strscpy(rkvdec->mdev.model, "rkvdec" , sizeof(rkvdec->mdev.model)); |
889 | strscpy(rkvdec->mdev.bus_info, "platform:rkvdec" , |
890 | sizeof(rkvdec->mdev.bus_info)); |
891 | media_device_init(mdev: &rkvdec->mdev); |
892 | rkvdec->mdev.ops = &rkvdec_media_ops; |
893 | rkvdec->v4l2_dev.mdev = &rkvdec->mdev; |
894 | |
895 | rkvdec->vdev.lock = &rkvdec->vdev_lock; |
896 | rkvdec->vdev.v4l2_dev = &rkvdec->v4l2_dev; |
897 | rkvdec->vdev.fops = &rkvdec_fops; |
898 | rkvdec->vdev.release = video_device_release_empty; |
899 | rkvdec->vdev.vfl_dir = VFL_DIR_M2M; |
900 | rkvdec->vdev.device_caps = V4L2_CAP_STREAMING | |
901 | V4L2_CAP_VIDEO_M2M_MPLANE; |
902 | rkvdec->vdev.ioctl_ops = &rkvdec_ioctl_ops; |
903 | video_set_drvdata(vdev: &rkvdec->vdev, data: rkvdec); |
904 | strscpy(rkvdec->vdev.name, "rkvdec" , sizeof(rkvdec->vdev.name)); |
905 | |
906 | ret = video_register_device(vdev: &rkvdec->vdev, type: VFL_TYPE_VIDEO, nr: -1); |
907 | if (ret) { |
908 | v4l2_err(&rkvdec->v4l2_dev, "Failed to register video device\n" ); |
909 | goto err_cleanup_mc; |
910 | } |
911 | |
912 | ret = v4l2_m2m_register_media_controller(m2m_dev: rkvdec->m2m_dev, vdev: &rkvdec->vdev, |
913 | MEDIA_ENT_F_PROC_VIDEO_DECODER); |
914 | if (ret) { |
915 | v4l2_err(&rkvdec->v4l2_dev, |
916 | "Failed to initialize V4L2 M2M media controller\n" ); |
917 | goto err_unregister_vdev; |
918 | } |
919 | |
920 | ret = media_device_register(&rkvdec->mdev); |
921 | if (ret) { |
922 | v4l2_err(&rkvdec->v4l2_dev, "Failed to register media device\n" ); |
923 | goto err_unregister_mc; |
924 | } |
925 | |
926 | return 0; |
927 | |
928 | err_unregister_mc: |
929 | v4l2_m2m_unregister_media_controller(m2m_dev: rkvdec->m2m_dev); |
930 | |
931 | err_unregister_vdev: |
932 | video_unregister_device(vdev: &rkvdec->vdev); |
933 | |
934 | err_cleanup_mc: |
935 | media_device_cleanup(mdev: &rkvdec->mdev); |
936 | v4l2_m2m_release(m2m_dev: rkvdec->m2m_dev); |
937 | |
938 | err_unregister_v4l2: |
939 | v4l2_device_unregister(v4l2_dev: &rkvdec->v4l2_dev); |
940 | return ret; |
941 | } |
942 | |
943 | static void rkvdec_v4l2_cleanup(struct rkvdec_dev *rkvdec) |
944 | { |
945 | media_device_unregister(mdev: &rkvdec->mdev); |
946 | v4l2_m2m_unregister_media_controller(m2m_dev: rkvdec->m2m_dev); |
947 | video_unregister_device(vdev: &rkvdec->vdev); |
948 | media_device_cleanup(mdev: &rkvdec->mdev); |
949 | v4l2_m2m_release(m2m_dev: rkvdec->m2m_dev); |
950 | v4l2_device_unregister(v4l2_dev: &rkvdec->v4l2_dev); |
951 | } |
952 | |
953 | static irqreturn_t rkvdec_irq_handler(int irq, void *priv) |
954 | { |
955 | struct rkvdec_dev *rkvdec = priv; |
956 | enum vb2_buffer_state state; |
957 | u32 status; |
958 | |
959 | status = readl(addr: rkvdec->regs + RKVDEC_REG_INTERRUPT); |
960 | state = (status & RKVDEC_RDY_STA) ? |
961 | VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; |
962 | |
963 | writel(val: 0, addr: rkvdec->regs + RKVDEC_REG_INTERRUPT); |
964 | if (cancel_delayed_work(dwork: &rkvdec->watchdog_work)) { |
965 | struct rkvdec_ctx *ctx; |
966 | |
967 | ctx = v4l2_m2m_get_curr_priv(m2m_dev: rkvdec->m2m_dev); |
968 | rkvdec_job_finish(ctx, result: state); |
969 | } |
970 | |
971 | return IRQ_HANDLED; |
972 | } |
973 | |
974 | static void rkvdec_watchdog_func(struct work_struct *work) |
975 | { |
976 | struct rkvdec_dev *rkvdec; |
977 | struct rkvdec_ctx *ctx; |
978 | |
979 | rkvdec = container_of(to_delayed_work(work), struct rkvdec_dev, |
980 | watchdog_work); |
981 | ctx = v4l2_m2m_get_curr_priv(m2m_dev: rkvdec->m2m_dev); |
982 | if (ctx) { |
983 | dev_err(rkvdec->dev, "Frame processing timed out!\n" ); |
984 | writel(RKVDEC_IRQ_DIS, addr: rkvdec->regs + RKVDEC_REG_INTERRUPT); |
985 | writel(val: 0, addr: rkvdec->regs + RKVDEC_REG_SYSCTRL); |
986 | rkvdec_job_finish(ctx, result: VB2_BUF_STATE_ERROR); |
987 | } |
988 | } |
989 | |
990 | static const struct of_device_id of_rkvdec_match[] = { |
991 | { .compatible = "rockchip,rk3399-vdec" }, |
992 | { /* sentinel */ } |
993 | }; |
994 | MODULE_DEVICE_TABLE(of, of_rkvdec_match); |
995 | |
996 | static const char * const rkvdec_clk_names[] = { |
997 | "axi" , "ahb" , "cabac" , "core" |
998 | }; |
999 | |
1000 | static int rkvdec_probe(struct platform_device *pdev) |
1001 | { |
1002 | struct rkvdec_dev *rkvdec; |
1003 | unsigned int i; |
1004 | int ret, irq; |
1005 | |
1006 | rkvdec = devm_kzalloc(dev: &pdev->dev, size: sizeof(*rkvdec), GFP_KERNEL); |
1007 | if (!rkvdec) |
1008 | return -ENOMEM; |
1009 | |
1010 | platform_set_drvdata(pdev, data: rkvdec); |
1011 | rkvdec->dev = &pdev->dev; |
1012 | mutex_init(&rkvdec->vdev_lock); |
1013 | INIT_DELAYED_WORK(&rkvdec->watchdog_work, rkvdec_watchdog_func); |
1014 | |
1015 | rkvdec->clocks = devm_kcalloc(dev: &pdev->dev, ARRAY_SIZE(rkvdec_clk_names), |
1016 | size: sizeof(*rkvdec->clocks), GFP_KERNEL); |
1017 | if (!rkvdec->clocks) |
1018 | return -ENOMEM; |
1019 | |
1020 | for (i = 0; i < ARRAY_SIZE(rkvdec_clk_names); i++) |
1021 | rkvdec->clocks[i].id = rkvdec_clk_names[i]; |
1022 | |
1023 | ret = devm_clk_bulk_get(dev: &pdev->dev, ARRAY_SIZE(rkvdec_clk_names), |
1024 | clks: rkvdec->clocks); |
1025 | if (ret) |
1026 | return ret; |
1027 | |
1028 | rkvdec->regs = devm_platform_ioremap_resource(pdev, index: 0); |
1029 | if (IS_ERR(ptr: rkvdec->regs)) |
1030 | return PTR_ERR(ptr: rkvdec->regs); |
1031 | |
1032 | ret = dma_set_coherent_mask(dev: &pdev->dev, DMA_BIT_MASK(32)); |
1033 | if (ret) { |
1034 | dev_err(&pdev->dev, "Could not set DMA coherent mask.\n" ); |
1035 | return ret; |
1036 | } |
1037 | |
1038 | vb2_dma_contig_set_max_seg_size(dev: &pdev->dev, DMA_BIT_MASK(32)); |
1039 | |
1040 | irq = platform_get_irq(pdev, 0); |
1041 | if (irq <= 0) |
1042 | return -ENXIO; |
1043 | |
1044 | ret = devm_request_threaded_irq(dev: &pdev->dev, irq, NULL, |
1045 | thread_fn: rkvdec_irq_handler, IRQF_ONESHOT, |
1046 | devname: dev_name(dev: &pdev->dev), dev_id: rkvdec); |
1047 | if (ret) { |
1048 | dev_err(&pdev->dev, "Could not request vdec IRQ\n" ); |
1049 | return ret; |
1050 | } |
1051 | |
1052 | pm_runtime_set_autosuspend_delay(dev: &pdev->dev, delay: 100); |
1053 | pm_runtime_use_autosuspend(dev: &pdev->dev); |
1054 | pm_runtime_enable(dev: &pdev->dev); |
1055 | |
1056 | ret = rkvdec_v4l2_init(rkvdec); |
1057 | if (ret) |
1058 | goto err_disable_runtime_pm; |
1059 | |
1060 | return 0; |
1061 | |
1062 | err_disable_runtime_pm: |
1063 | pm_runtime_dont_use_autosuspend(dev: &pdev->dev); |
1064 | pm_runtime_disable(dev: &pdev->dev); |
1065 | return ret; |
1066 | } |
1067 | |
1068 | static void rkvdec_remove(struct platform_device *pdev) |
1069 | { |
1070 | struct rkvdec_dev *rkvdec = platform_get_drvdata(pdev); |
1071 | |
1072 | cancel_delayed_work_sync(dwork: &rkvdec->watchdog_work); |
1073 | |
1074 | rkvdec_v4l2_cleanup(rkvdec); |
1075 | pm_runtime_disable(dev: &pdev->dev); |
1076 | pm_runtime_dont_use_autosuspend(dev: &pdev->dev); |
1077 | } |
1078 | |
1079 | #ifdef CONFIG_PM |
1080 | static int rkvdec_runtime_resume(struct device *dev) |
1081 | { |
1082 | struct rkvdec_dev *rkvdec = dev_get_drvdata(dev); |
1083 | |
1084 | return clk_bulk_prepare_enable(ARRAY_SIZE(rkvdec_clk_names), |
1085 | clks: rkvdec->clocks); |
1086 | } |
1087 | |
1088 | static int rkvdec_runtime_suspend(struct device *dev) |
1089 | { |
1090 | struct rkvdec_dev *rkvdec = dev_get_drvdata(dev); |
1091 | |
1092 | clk_bulk_disable_unprepare(ARRAY_SIZE(rkvdec_clk_names), |
1093 | clks: rkvdec->clocks); |
1094 | return 0; |
1095 | } |
1096 | #endif |
1097 | |
1098 | static const struct dev_pm_ops rkvdec_pm_ops = { |
1099 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, |
1100 | pm_runtime_force_resume) |
1101 | SET_RUNTIME_PM_OPS(rkvdec_runtime_suspend, rkvdec_runtime_resume, NULL) |
1102 | }; |
1103 | |
1104 | static struct platform_driver rkvdec_driver = { |
1105 | .probe = rkvdec_probe, |
1106 | .remove_new = rkvdec_remove, |
1107 | .driver = { |
1108 | .name = "rkvdec" , |
1109 | .of_match_table = of_rkvdec_match, |
1110 | .pm = &rkvdec_pm_ops, |
1111 | }, |
1112 | }; |
1113 | module_platform_driver(rkvdec_driver); |
1114 | |
1115 | MODULE_AUTHOR("Boris Brezillon <boris.brezillon@collabora.com>" ); |
1116 | MODULE_DESCRIPTION("Rockchip Video Decoder driver" ); |
1117 | MODULE_LICENSE("GPL v2" ); |
1118 | |