1633 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Imagination E5010 JPEG Encoder driver.4 *5 * TODO: Add MMU and memory tiling support6 *7 * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/8 *9 * Author: David Huang <d-huang@ti.com>10 * Author: Devarsh Thakkar <devarsht@ti.com>11 */12 13#include <linux/clk.h>14#include <linux/dma-mapping.h>15#include <linux/err.h>16#include <linux/interrupt.h>17#include <linux/ioctl.h>18#include <linux/module.h>19#include <linux/of_device.h>20#include <linux/pm_runtime.h>21#include <media/jpeg.h>22#include <media/v4l2-common.h>23#include <media/v4l2-ctrls.h>24#include <media/v4l2-device.h>25#include <media/v4l2-event.h>26#include <media/v4l2-ioctl.h>27#include <media/v4l2-jpeg.h>28#include <media/v4l2-rect.h>29#include <media/v4l2-mem2mem.h>30#include <media/videobuf2-dma-contig.h>31#include <media/videobuf2-v4l2.h>32#include "e5010-jpeg-enc.h"33#include "e5010-jpeg-enc-hw.h"34 35/* forward declarations */36static const struct of_device_id e5010_of_match[];37 38static const struct v4l2_file_operations e5010_fops;39 40static const struct v4l2_ioctl_ops e5010_ioctl_ops;41 42static const struct vb2_ops e5010_video_ops;43 44static const struct v4l2_m2m_ops e5010_m2m_ops;45 46static struct e5010_fmt e5010_formats[] = {47 {48 .fourcc = V4L2_PIX_FMT_NV12,49 .num_planes = 1,50 .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,51 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,52 .chroma_order = CHROMA_ORDER_CB_CR,53 .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64,54 MIN_DIMENSION, MAX_DIMENSION, 8 },55 },56 {57 .fourcc = V4L2_PIX_FMT_NV12M,58 .num_planes = 2,59 .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,60 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,61 .chroma_order = CHROMA_ORDER_CB_CR,62 .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64,63 MIN_DIMENSION, MAX_DIMENSION, 8 },64 },65 {66 .fourcc = V4L2_PIX_FMT_NV21,67 .num_planes = 1,68 .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,69 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,70 .chroma_order = CHROMA_ORDER_CR_CB,71 .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64,72 MIN_DIMENSION, MAX_DIMENSION, 8 },73 },74 {75 .fourcc = V4L2_PIX_FMT_NV21M,76 .num_planes = 2,77 .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,78 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,79 .chroma_order = CHROMA_ORDER_CR_CB,80 .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64,81 MIN_DIMENSION, MAX_DIMENSION, 8 },82 },83 {84 .fourcc = V4L2_PIX_FMT_NV16,85 .num_planes = 1,86 .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,87 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,88 .chroma_order = CHROMA_ORDER_CB_CR,89 .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64,90 MIN_DIMENSION, MAX_DIMENSION, 8 },91 },92 {93 .fourcc = V4L2_PIX_FMT_NV16M,94 .num_planes = 2,95 .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,96 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,97 .chroma_order = CHROMA_ORDER_CB_CR,98 .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64,99 MIN_DIMENSION, MAX_DIMENSION, 8 },100 101 },102 {103 .fourcc = V4L2_PIX_FMT_NV61,104 .num_planes = 1,105 .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,106 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,107 .chroma_order = CHROMA_ORDER_CR_CB,108 .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64,109 MIN_DIMENSION, MAX_DIMENSION, 8 },110 },111 {112 .fourcc = V4L2_PIX_FMT_NV61M,113 .num_planes = 2,114 .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,115 .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,116 .chroma_order = CHROMA_ORDER_CR_CB,117 .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64,118 MIN_DIMENSION, MAX_DIMENSION, 8 },119 },120 {121 .fourcc = V4L2_PIX_FMT_JPEG,122 .num_planes = 1,123 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,124 .subsampling = 0,125 .chroma_order = 0,126 .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 16,127 MIN_DIMENSION, MAX_DIMENSION, 8 },128 },129};130 131static unsigned int debug;132module_param(debug, uint, 0644);133MODULE_PARM_DESC(debug, "debug level");134 135#define dprintk(dev, lvl, fmt, arg...) \136 v4l2_dbg(lvl, debug, &(dev)->v4l2_dev, "%s: " fmt, __func__, ## arg)137 138static const struct v4l2_event e5010_eos_event = {139 .type = V4L2_EVENT_EOS140};141 142static const char *type_name(enum v4l2_buf_type type)143{144 switch (type) {145 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:146 return "Output";147 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:148 return "Capture";149 default:150 return "Invalid";151 }152}153 154static struct e5010_q_data *get_queue(struct e5010_context *ctx, enum v4l2_buf_type type)155{156 return (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? &ctx->out_queue : &ctx->cap_queue;157}158 159static void calculate_qp_tables(struct e5010_context *ctx)160{161 long long luminosity, contrast;162 int quality, i;163 164 quality = 50 - ctx->quality;165 166 luminosity = LUMINOSITY * quality / 50;167 contrast = CONTRAST * quality / 50;168 169 if (quality > 0) {170 luminosity *= INCREASE;171 contrast *= INCREASE;172 }173 174 for (i = 0; i < V4L2_JPEG_PIXELS_IN_BLOCK; i++) {175 long long delta = v4l2_jpeg_ref_table_chroma_qt[i] * contrast + luminosity;176 int val = (int)(v4l2_jpeg_ref_table_chroma_qt[i] + delta);177 178 clamp(val, 1, 255);179 ctx->chroma_qp[i] = quality == -50 ? 1 : val;180 181 delta = v4l2_jpeg_ref_table_luma_qt[i] * contrast + luminosity;182 val = (int)(v4l2_jpeg_ref_table_luma_qt[i] + delta);183 clamp(val, 1, 255);184 ctx->luma_qp[i] = quality == -50 ? 1 : val;185 }186 187 ctx->update_qp = true;188}189 190static int update_qp_tables(struct e5010_context *ctx)191{192 struct e5010_dev *e5010 = ctx->e5010;193 int i, ret = 0;194 u32 lvalue, cvalue;195 196 lvalue = 0;197 cvalue = 0;198 199 for (i = 0; i < QP_TABLE_SIZE; i++) {200 lvalue |= ctx->luma_qp[i] << (8 * (i % 4));201 cvalue |= ctx->chroma_qp[i] << (8 * (i % 4));202 if (i % 4 == 3) {203 ret |= e5010_hw_set_qpvalue(e5010->core_base,204 JASPER_LUMA_QUANTIZATION_TABLE0_OFFSET205 + QP_TABLE_FIELD_OFFSET * ((i - 3) / 4),206 lvalue);207 ret |= e5010_hw_set_qpvalue(e5010->core_base,208 JASPER_CHROMA_QUANTIZATION_TABLE0_OFFSET209 + QP_TABLE_FIELD_OFFSET * ((i - 3) / 4),210 cvalue);211 lvalue = 0;212 cvalue = 0;213 }214 }215 216 return ret;217}218 219static int e5010_set_input_subsampling(void __iomem *core_base, int subsampling)220{221 switch (subsampling) {222 case V4L2_JPEG_CHROMA_SUBSAMPLING_420:223 return e5010_hw_set_input_subsampling(core_base, SUBSAMPLING_420);224 case V4L2_JPEG_CHROMA_SUBSAMPLING_422:225 return e5010_hw_set_input_subsampling(core_base, SUBSAMPLING_422);226 default:227 return -EINVAL;228 };229}230 231static int e5010_querycap(struct file *file, void *priv, struct v4l2_capability *cap)232{233 strscpy(cap->driver, E5010_MODULE_NAME, sizeof(cap->driver));234 strscpy(cap->card, E5010_MODULE_NAME, sizeof(cap->card));235 236 return 0;237}238 239static struct e5010_fmt *find_format(struct v4l2_format *f)240{241 int i;242 243 for (i = 0; i < ARRAY_SIZE(e5010_formats); ++i) {244 if (e5010_formats[i].fourcc == f->fmt.pix_mp.pixelformat &&245 e5010_formats[i].type == f->type)246 return &e5010_formats[i];247 }248 249 return NULL;250}251 252static int e5010_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f)253{254 int i, index = 0;255 struct e5010_fmt *fmt = NULL;256 struct e5010_context *ctx = file->private_data;257 258 if (!V4L2_TYPE_IS_MULTIPLANAR(f->type)) {259 v4l2_err(&ctx->e5010->v4l2_dev, "ENUMFMT with Invalid type: %d\n", f->type);260 return -EINVAL;261 }262 263 for (i = 0; i < ARRAY_SIZE(e5010_formats); ++i) {264 if (e5010_formats[i].type == f->type) {265 if (index == f->index) {266 fmt = &e5010_formats[i];267 break;268 }269 index++;270 }271 }272 273 if (!fmt)274 return -EINVAL;275 276 f->pixelformat = fmt->fourcc;277 return 0;278}279 280static int e5010_g_fmt(struct file *file, void *priv, struct v4l2_format *f)281{282 struct e5010_context *ctx = file->private_data;283 struct e5010_q_data *queue;284 int i;285 struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;286 struct v4l2_plane_pix_format *plane_fmt = pix_mp->plane_fmt;287 288 queue = get_queue(ctx, f->type);289 290 pix_mp->flags = 0;291 pix_mp->field = V4L2_FIELD_NONE;292 pix_mp->pixelformat = queue->fmt->fourcc;293 pix_mp->width = queue->width_adjusted;294 pix_mp->height = queue->height_adjusted;295 pix_mp->num_planes = queue->fmt->num_planes;296 297 if (V4L2_TYPE_IS_OUTPUT(f->type)) {298 if (!pix_mp->colorspace)299 pix_mp->colorspace = V4L2_COLORSPACE_SRGB;300 301 for (i = 0; i < queue->fmt->num_planes; i++) {302 plane_fmt[i].sizeimage = queue->sizeimage[i];303 plane_fmt[i].bytesperline = queue->bytesperline[i];304 }305 306 } else {307 pix_mp->colorspace = V4L2_COLORSPACE_JPEG;308 plane_fmt[0].bytesperline = 0;309 plane_fmt[0].sizeimage = queue->sizeimage[0];310 }311 pix_mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;312 pix_mp->xfer_func = V4L2_XFER_FUNC_DEFAULT;313 pix_mp->quantization = V4L2_QUANTIZATION_DEFAULT;314 315 return 0;316}317 318static int e5010_jpeg_try_fmt(struct v4l2_format *f, struct e5010_context *ctx)319{320 struct e5010_fmt *fmt;321 struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;322 struct v4l2_plane_pix_format *plane_fmt = pix_mp->plane_fmt;323 324 fmt = find_format(f);325 if (!fmt) {326 if (V4L2_TYPE_IS_OUTPUT(f->type))327 pix_mp->pixelformat = V4L2_PIX_FMT_NV12;328 else329 pix_mp->pixelformat = V4L2_PIX_FMT_JPEG;330 fmt = find_format(f);331 if (!fmt)332 return -EINVAL;333 }334 335 if (V4L2_TYPE_IS_OUTPUT(f->type)) {336 if (!pix_mp->colorspace)337 pix_mp->colorspace = V4L2_COLORSPACE_JPEG;338 if (!pix_mp->ycbcr_enc)339 pix_mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;340 if (!pix_mp->quantization)341 pix_mp->quantization = V4L2_QUANTIZATION_DEFAULT;342 if (!pix_mp->xfer_func)343 pix_mp->xfer_func = V4L2_XFER_FUNC_DEFAULT;344 345 v4l2_apply_frmsize_constraints(&pix_mp->width,346 &pix_mp->height,347 &fmt->frmsize);348 349 v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,350 pix_mp->width, pix_mp->height);351 352 } else {353 pix_mp->colorspace = V4L2_COLORSPACE_JPEG;354 pix_mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;355 pix_mp->quantization = V4L2_QUANTIZATION_DEFAULT;356 pix_mp->xfer_func = V4L2_XFER_FUNC_DEFAULT;357 v4l2_apply_frmsize_constraints(&pix_mp->width,358 &pix_mp->height,359 &fmt->frmsize);360 plane_fmt[0].sizeimage = pix_mp->width * pix_mp->height * JPEG_MAX_BYTES_PER_PIXEL;361 plane_fmt[0].sizeimage += HEADER_SIZE;362 plane_fmt[0].bytesperline = 0;363 pix_mp->pixelformat = fmt->fourcc;364 pix_mp->num_planes = fmt->num_planes;365 }366 pix_mp->flags = 0;367 pix_mp->field = V4L2_FIELD_NONE;368 369 dprintk(ctx->e5010, 2,370 "ctx: 0x%p: format type %s:, wxh: %dx%d (plane0 : %d bytes, plane1 : %d bytes),fmt: %c%c%c%c\n",371 ctx, type_name(f->type), pix_mp->width, pix_mp->height,372 plane_fmt[0].sizeimage, plane_fmt[1].sizeimage,373 (fmt->fourcc & 0xff),374 (fmt->fourcc >> 8) & 0xff,375 (fmt->fourcc >> 16) & 0xff,376 (fmt->fourcc >> 24) & 0xff);377 378 return 0;379}380 381static int e5010_try_fmt(struct file *file, void *priv, struct v4l2_format *f)382{383 struct e5010_context *ctx = file->private_data;384 385 return e5010_jpeg_try_fmt(f, ctx);386}387 388static int e5010_s_fmt(struct file *file, void *priv, struct v4l2_format *f)389{390 struct e5010_context *ctx = file->private_data;391 struct vb2_queue *vq;392 int ret = 0, i = 0;393 struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;394 struct v4l2_plane_pix_format *plane_fmt = pix_mp->plane_fmt;395 struct e5010_q_data *queue;396 struct e5010_fmt *fmt;397 398 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);399 if (!vq)400 return -EINVAL;401 402 if (vb2_is_busy(vq)) {403 v4l2_err(&ctx->e5010->v4l2_dev, "queue busy\n");404 return -EBUSY;405 }406 407 ret = e5010_jpeg_try_fmt(f, ctx);408 if (ret)409 return ret;410 411 fmt = find_format(f);412 queue = get_queue(ctx, f->type);413 414 queue->fmt = fmt;415 queue->width = pix_mp->width;416 queue->height = pix_mp->height;417 418 if (V4L2_TYPE_IS_OUTPUT(f->type)) {419 for (i = 0; i < fmt->num_planes; i++) {420 queue->bytesperline[i] = plane_fmt[i].bytesperline;421 queue->sizeimage[i] = plane_fmt[i].sizeimage;422 }423 queue->crop.left = 0;424 queue->crop.top = 0;425 queue->crop.width = queue->width;426 queue->crop.height = queue->height;427 } else {428 queue->sizeimage[0] = plane_fmt[0].sizeimage;429 queue->sizeimage[1] = 0;430 queue->bytesperline[0] = 0;431 queue->bytesperline[1] = 0;432 }433 434 return 0;435}436 437static int e5010_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize)438{439 struct v4l2_format f;440 struct e5010_fmt *fmt;441 442 if (fsize->index != 0)443 return -EINVAL;444 445 f.fmt.pix_mp.pixelformat = fsize->pixel_format;446 if (f.fmt.pix_mp.pixelformat == V4L2_PIX_FMT_JPEG)447 f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;448 else449 f.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;450 451 fmt = find_format(&f);452 if (!fmt)453 return -EINVAL;454 455 fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;456 fsize->stepwise = fmt->frmsize;457 fsize->reserved[0] = 0;458 fsize->reserved[1] = 0;459 460 return 0;461}462 463static int e5010_g_selection(struct file *file, void *fh, struct v4l2_selection *s)464{465 struct e5010_context *ctx = file->private_data;466 struct e5010_q_data *queue;467 468 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)469 return -EINVAL;470 471 queue = get_queue(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);472 473 switch (s->target) {474 case V4L2_SEL_TGT_CROP_DEFAULT:475 case V4L2_SEL_TGT_CROP_BOUNDS:476 s->r.left = 0;477 s->r.top = 0;478 s->r.width = queue->width;479 s->r.height = queue->height;480 break;481 case V4L2_SEL_TGT_CROP:482 memcpy(&s->r, &queue->crop, sizeof(s->r));483 break;484 default:485 return -EINVAL;486 }487 488 return 0;489}490 491static int e5010_s_selection(struct file *file, void *fh, struct v4l2_selection *s)492{493 struct e5010_context *ctx = file->private_data;494 struct e5010_q_data *queue;495 struct vb2_queue *vq;496 struct v4l2_rect base_rect;497 498 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, s->type);499 if (!vq)500 return -EINVAL;501 502 if (vb2_is_streaming(vq))503 return -EBUSY;504 505 if (s->target != V4L2_SEL_TGT_CROP ||506 s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)507 return -EINVAL;508 509 queue = get_queue(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);510 base_rect.top = 0;511 base_rect.left = 0;512 base_rect.width = queue->width;513 base_rect.height = queue->height;514 515 switch (s->flags) {516 case 0:517 s->r.width = round_down(s->r.width, queue->fmt->frmsize.step_width);518 s->r.height = round_down(s->r.height, queue->fmt->frmsize.step_height);519 s->r.left = round_down(s->r.left, queue->fmt->frmsize.step_width);520 s->r.top = round_down(s->r.top, 2);521 522 if (s->r.left + s->r.width > queue->width)523 s->r.width = round_down(s->r.width + s->r.left - queue->width,524 queue->fmt->frmsize.step_width);525 if (s->r.top + s->r.height > queue->height)526 s->r.top = round_down(s->r.top + s->r.height - queue->height, 2);527 break;528 case V4L2_SEL_FLAG_GE:529 s->r.width = round_up(s->r.width, queue->fmt->frmsize.step_width);530 s->r.height = round_up(s->r.height, queue->fmt->frmsize.step_height);531 s->r.left = round_up(s->r.left, queue->fmt->frmsize.step_width);532 s->r.top = round_up(s->r.top, 2);533 break;534 case V4L2_SEL_FLAG_LE:535 s->r.width = round_down(s->r.width, queue->fmt->frmsize.step_width);536 s->r.height = round_down(s->r.height, queue->fmt->frmsize.step_height);537 s->r.left = round_down(s->r.left, queue->fmt->frmsize.step_width);538 s->r.top = round_down(s->r.top, 2);539 break;540 case V4L2_SEL_FLAG_LE | V4L2_SEL_FLAG_GE:541 if (!IS_ALIGNED(s->r.width, queue->fmt->frmsize.step_width) ||542 !IS_ALIGNED(s->r.height, queue->fmt->frmsize.step_height) ||543 !IS_ALIGNED(s->r.left, queue->fmt->frmsize.step_width) ||544 !IS_ALIGNED(s->r.top, 2))545 return -ERANGE;546 break;547 default:548 return -EINVAL;549 }550 551 if (!v4l2_rect_enclosed(&s->r, &base_rect))552 return -ERANGE;553 554 memcpy(&queue->crop, &s->r, sizeof(s->r));555 556 if (!v4l2_rect_equal(&s->r, &base_rect))557 queue->crop_set = true;558 559 dprintk(ctx->e5010, 2, "ctx: 0x%p: crop rectangle: w: %d, h : %d, l : %d, t : %d\n",560 ctx, queue->crop.width, queue->crop.height, queue->crop.left, queue->crop.top);561 562 return 0;563}564 565static int e5010_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub)566{567 switch (sub->type) {568 case V4L2_EVENT_EOS:569 return v4l2_event_subscribe(fh, sub, 0, NULL);570 case V4L2_EVENT_CTRL:571 return v4l2_ctrl_subscribe_event(fh, sub);572 default:573 return -EINVAL;574 }575 576 return 0;577}578 579static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)580{581 struct e5010_context *ctx = priv;582 struct e5010_dev *e5010 = ctx->e5010;583 int ret = 0;584 585 /* src_vq */586 memset(src_vq, 0, sizeof(*src_vq));587 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;588 src_vq->io_modes = VB2_MMAP | VB2_DMABUF;589 src_vq->drv_priv = ctx;590 src_vq->buf_struct_size = sizeof(struct e5010_buffer);591 src_vq->ops = &e5010_video_ops;592 src_vq->mem_ops = &vb2_dma_contig_memops;593 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;594 src_vq->lock = &e5010->mutex;595 src_vq->dev = e5010->v4l2_dev.dev;596 597 ret = vb2_queue_init(src_vq);598 if (ret)599 return ret;600 601 /* dst_vq */602 memset(dst_vq, 0, sizeof(*dst_vq));603 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;604 dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;605 dst_vq->drv_priv = ctx;606 dst_vq->buf_struct_size = sizeof(struct e5010_buffer);607 dst_vq->ops = &e5010_video_ops;608 dst_vq->mem_ops = &vb2_dma_contig_memops;609 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;610 dst_vq->lock = &e5010->mutex;611 dst_vq->dev = e5010->v4l2_dev.dev;612 613 ret = vb2_queue_init(dst_vq);614 if (ret) {615 vb2_queue_release(src_vq);616 return ret;617 }618 619 return 0;620}621 622static int e5010_s_ctrl(struct v4l2_ctrl *ctrl)623{624 struct e5010_context *ctx =625 container_of(ctrl->handler, struct e5010_context, ctrl_handler);626 627 switch (ctrl->id) {628 case V4L2_CID_JPEG_COMPRESSION_QUALITY:629 ctx->quality = ctrl->val;630 calculate_qp_tables(ctx);631 dprintk(ctx->e5010, 2, "ctx: 0x%p compression quality set to : %d\n", ctx,632 ctx->quality);633 break;634 default:635 return -EINVAL;636 }637 638 return 0;639}640 641static const struct v4l2_ctrl_ops e5010_ctrl_ops = {642 .s_ctrl = e5010_s_ctrl,643};644 645static void e5010_encode_ctrls(struct e5010_context *ctx)646{647 v4l2_ctrl_new_std(&ctx->ctrl_handler, &e5010_ctrl_ops,648 V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 100, 1, 75);649}650 651static int e5010_ctrls_setup(struct e5010_context *ctx)652{653 int err;654 655 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 1);656 657 e5010_encode_ctrls(ctx);658 659 if (ctx->ctrl_handler.error) {660 err = ctx->ctrl_handler.error;661 v4l2_ctrl_handler_free(&ctx->ctrl_handler);662 663 return err;664 }665 666 err = v4l2_ctrl_handler_setup(&ctx->ctrl_handler);667 if (err)668 v4l2_ctrl_handler_free(&ctx->ctrl_handler);669 670 return err;671}672 673static void e5010_jpeg_set_default_params(struct e5010_context *ctx)674{675 struct e5010_q_data *queue;676 struct v4l2_format f;677 struct e5010_fmt *fmt;678 struct v4l2_pix_format_mplane *pix_mp = &f.fmt.pix_mp;679 struct v4l2_plane_pix_format *plane_fmt = pix_mp->plane_fmt;680 int i = 0;681 682 f.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;683 f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12;684 fmt = find_format(&f);685 queue = &ctx->out_queue;686 queue->fmt = fmt;687 queue->width = DEFAULT_WIDTH;688 queue->height = DEFAULT_HEIGHT;689 pix_mp->width = queue->width;690 pix_mp->height = queue->height;691 queue->crop.left = 0;692 queue->crop.top = 0;693 queue->crop.width = queue->width;694 queue->crop.height = queue->height;695 v4l2_apply_frmsize_constraints(&pix_mp->width,696 &pix_mp->height,697 &fmt->frmsize);698 v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,699 pix_mp->width, pix_mp->height);700 for (i = 0; i < fmt->num_planes; i++) {701 queue->bytesperline[i] = plane_fmt[i].bytesperline;702 queue->sizeimage[i] = plane_fmt[i].sizeimage;703 }704 queue->width_adjusted = pix_mp->width;705 queue->height_adjusted = pix_mp->height;706 707 f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;708 f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_JPEG;709 fmt = find_format(&f);710 queue = &ctx->cap_queue;711 queue->fmt = fmt;712 queue->width = DEFAULT_WIDTH;713 queue->height = DEFAULT_HEIGHT;714 pix_mp->width = queue->width;715 pix_mp->height = queue->height;716 v4l2_apply_frmsize_constraints(&pix_mp->width,717 &pix_mp->height,718 &fmt->frmsize);719 queue->sizeimage[0] = pix_mp->width * pix_mp->height * JPEG_MAX_BYTES_PER_PIXEL;720 queue->sizeimage[0] += HEADER_SIZE;721 queue->sizeimage[1] = 0;722 queue->bytesperline[0] = 0;723 queue->bytesperline[1] = 0;724 queue->width_adjusted = pix_mp->width;725 queue->height_adjusted = pix_mp->height;726}727 728static int e5010_open(struct file *file)729{730 struct e5010_dev *e5010 = video_drvdata(file);731 struct video_device *vdev = video_devdata(file);732 struct e5010_context *ctx;733 int ret = 0;734 735 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);736 if (!ctx)737 return -ENOMEM;738 739 if (mutex_lock_interruptible(&e5010->mutex)) {740 ret = -ERESTARTSYS;741 goto free;742 }743 744 v4l2_fh_init(&ctx->fh, vdev);745 file->private_data = ctx;746 v4l2_fh_add(&ctx->fh);747 748 ctx->e5010 = e5010;749 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(e5010->m2m_dev, ctx, queue_init);750 if (IS_ERR(ctx->fh.m2m_ctx)) {751 v4l2_err(&e5010->v4l2_dev, "failed to init m2m ctx\n");752 ret = PTR_ERR(ctx->fh.m2m_ctx);753 goto exit;754 }755 756 ret = e5010_ctrls_setup(ctx);757 if (ret) {758 v4l2_err(&e5010->v4l2_dev, "failed to setup e5010 jpeg controls\n");759 goto err_ctrls_setup;760 }761 ctx->fh.ctrl_handler = &ctx->ctrl_handler;762 763 e5010_jpeg_set_default_params(ctx);764 765 dprintk(e5010, 1, "Created instance: 0x%p, m2m_ctx: 0x%p\n", ctx, ctx->fh.m2m_ctx);766 767 mutex_unlock(&e5010->mutex);768 return 0;769 770err_ctrls_setup:771 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);772exit:773 v4l2_fh_del(&ctx->fh);774 v4l2_fh_exit(&ctx->fh);775 mutex_unlock(&e5010->mutex);776free:777 kfree(ctx);778 return ret;779}780 781static int e5010_release(struct file *file)782{783 struct e5010_dev *e5010 = video_drvdata(file);784 struct e5010_context *ctx = file->private_data;785 786 dprintk(e5010, 1, "Releasing instance: 0x%p, m2m_ctx: 0x%p\n", ctx, ctx->fh.m2m_ctx);787 mutex_lock(&e5010->mutex);788 v4l2_ctrl_handler_free(&ctx->ctrl_handler);789 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);790 v4l2_fh_del(&ctx->fh);791 v4l2_fh_exit(&ctx->fh);792 kfree(ctx);793 mutex_unlock(&e5010->mutex);794 795 return 0;796}797 798static void header_write(struct e5010_context *ctx, u8 *addr, unsigned int *offset,799 unsigned int no_bytes, unsigned long bits)800{801 u8 *w_addr = addr + *offset;802 int i;803 804 if ((*offset + no_bytes) > HEADER_SIZE) {805 v4l2_warn(&ctx->e5010->v4l2_dev, "%s: %s: %d: Problem writing header. %d > HEADER_SIZE %d\n",806 __FILE__, __func__, __LINE__, *offset + no_bytes, HEADER_SIZE);807 return;808 }809 810 for (i = no_bytes - 1; i >= 0; i--)811 *(w_addr++) = ((u8 *)&bits)[i];812 813 *offset += no_bytes;814}815 816static void encode_marker_segment(struct e5010_context *ctx, void *addr, unsigned int *offset)817{818 u8 *buffer = (u8 *)addr;819 int i;820 821 header_write(ctx, buffer, offset, 2, START_OF_IMAGE);822 header_write(ctx, buffer, offset, 2, DQT_MARKER);823 header_write(ctx, buffer, offset, 3, LQPQ << 4);824 for (i = 0; i < V4L2_JPEG_PIXELS_IN_BLOCK; i++)825 header_write(ctx, buffer, offset, 1, ctx->luma_qp[v4l2_jpeg_zigzag_scan_index[i]]);826 827 header_write(ctx, buffer, offset, 2, DQT_MARKER);828 header_write(ctx, buffer, offset, 3, (LQPQ << 4) | 1);829 for (i = 0; i < V4L2_JPEG_PIXELS_IN_BLOCK; i++)830 header_write(ctx, buffer, offset, 1,831 ctx->chroma_qp[v4l2_jpeg_zigzag_scan_index[i]]);832 833 /* Huffman tables */834 header_write(ctx, buffer, offset, 2, DHT_MARKER);835 header_write(ctx, buffer, offset, 2, LH_DC);836 header_write(ctx, buffer, offset, 1, V4L2_JPEG_LUM_HT | V4L2_JPEG_DC_HT);837 for (i = 0 ; i < V4L2_JPEG_REF_HT_DC_LEN; i++)838 header_write(ctx, buffer, offset, 1, v4l2_jpeg_ref_table_luma_dc_ht[i]);839 840 header_write(ctx, buffer, offset, 2, DHT_MARKER);841 header_write(ctx, buffer, offset, 2, LH_AC);842 header_write(ctx, buffer, offset, 1, V4L2_JPEG_LUM_HT | V4L2_JPEG_AC_HT);843 for (i = 0 ; i < V4L2_JPEG_REF_HT_AC_LEN; i++)844 header_write(ctx, buffer, offset, 1, v4l2_jpeg_ref_table_luma_ac_ht[i]);845 846 header_write(ctx, buffer, offset, 2, DHT_MARKER);847 header_write(ctx, buffer, offset, 2, LH_DC);848 header_write(ctx, buffer, offset, 1, V4L2_JPEG_CHR_HT | V4L2_JPEG_DC_HT);849 for (i = 0 ; i < V4L2_JPEG_REF_HT_DC_LEN; i++)850 header_write(ctx, buffer, offset, 1, v4l2_jpeg_ref_table_chroma_dc_ht[i]);851 852 header_write(ctx, buffer, offset, 2, DHT_MARKER);853 header_write(ctx, buffer, offset, 2, LH_AC);854 header_write(ctx, buffer, offset, 1, V4L2_JPEG_CHR_HT | V4L2_JPEG_AC_HT);855 for (i = 0 ; i < V4L2_JPEG_REF_HT_AC_LEN; i++)856 header_write(ctx, buffer, offset, 1, v4l2_jpeg_ref_table_chroma_ac_ht[i]);857}858 859static void encode_frame_header(struct e5010_context *ctx, void *addr, unsigned int *offset)860{861 u8 *buffer = (u8 *)addr;862 863 header_write(ctx, buffer, offset, 2, SOF_BASELINE_DCT);864 header_write(ctx, buffer, offset, 2, 8 + (3 * UC_NUM_COMP));865 header_write(ctx, buffer, offset, 1, PRECISION);866 header_write(ctx, buffer, offset, 2, ctx->out_queue.crop.height);867 header_write(ctx, buffer, offset, 2, ctx->out_queue.crop.width);868 header_write(ctx, buffer, offset, 1, UC_NUM_COMP);869 870 /* Luma details */871 header_write(ctx, buffer, offset, 1, 1);872 if (ctx->out_queue.fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_422)873 header_write(ctx, buffer, offset, 1,874 HORZ_SAMPLING_FACTOR | (VERT_SAMPLING_FACTOR_422));875 else876 header_write(ctx, buffer, offset, 1,877 HORZ_SAMPLING_FACTOR | (VERT_SAMPLING_FACTOR_420));878 header_write(ctx, buffer, offset, 1, 0);879 /* Chroma details */880 header_write(ctx, buffer, offset, 1, 2);881 header_write(ctx, buffer, offset, 1, (HORZ_SAMPLING_FACTOR >> 1) | 1);882 header_write(ctx, buffer, offset, 1, 1);883 header_write(ctx, buffer, offset, 1, 3);884 header_write(ctx, buffer, offset, 1, (HORZ_SAMPLING_FACTOR >> 1) | 1);885 header_write(ctx, buffer, offset, 1, 1);886}887 888static void jpg_encode_sos_header(struct e5010_context *ctx, void *addr, unsigned int *offset)889{890 u8 *buffer = (u8 *)addr;891 int i;892 893 header_write(ctx, buffer, offset, 2, START_OF_SCAN);894 header_write(ctx, buffer, offset, 2, 6 + (COMPONENTS_IN_SCAN << 1));895 header_write(ctx, buffer, offset, 1, COMPONENTS_IN_SCAN);896 897 for (i = 0; i < COMPONENTS_IN_SCAN; i++) {898 header_write(ctx, buffer, offset, 1, i + 1);899 if (i == 0)900 header_write(ctx, buffer, offset, 1, 0);901 else902 header_write(ctx, buffer, offset, 1, 17);903 }904 905 header_write(ctx, buffer, offset, 1, 0);906 header_write(ctx, buffer, offset, 1, 63);907 header_write(ctx, buffer, offset, 1, 0);908}909 910static void write_header(struct e5010_context *ctx, void *addr)911{912 unsigned int offset = 0;913 914 encode_marker_segment(ctx, addr, &offset);915 encode_frame_header(ctx, addr, &offset);916 jpg_encode_sos_header(ctx, addr, &offset);917}918 919static irqreturn_t e5010_irq(int irq, void *data)920{921 struct e5010_dev *e5010 = data;922 struct e5010_context *ctx;923 int output_size;924 struct vb2_v4l2_buffer *src_buf, *dst_buf;925 bool pic_done, out_addr_err;926 927 spin_lock(&e5010->hw_lock);928 pic_done = e5010_hw_pic_done_irq(e5010->core_base);929 out_addr_err = e5010_hw_output_address_irq(e5010->core_base);930 931 if (!pic_done && !out_addr_err) {932 spin_unlock(&e5010->hw_lock);933 return IRQ_NONE;934 }935 936 ctx = v4l2_m2m_get_curr_priv(e5010->m2m_dev);937 if (WARN_ON(!ctx))938 goto job_unlock;939 940 dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);941 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);942 if (!dst_buf || !src_buf) {943 v4l2_err(&e5010->v4l2_dev, "ctx: 0x%p No source or destination buffer\n", ctx);944 goto job_unlock;945 }946 947 if (out_addr_err) {948 e5010_hw_clear_output_error(e5010->core_base, 1);949 v4l2_warn(&e5010->v4l2_dev,950 "ctx: 0x%p Output bitstream size exceeded max size\n", ctx);951 v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);952 vb2_set_plane_payload(&dst_buf->vb2_buf, 0, dst_buf->planes[0].length);953 v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);954 if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, src_buf)) {955 dst_buf->flags |= V4L2_BUF_FLAG_LAST;956 v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx);957 v4l2_event_queue_fh(&ctx->fh, &e5010_eos_event);958 dprintk(e5010, 2, "ctx: 0x%p Sending EOS\n", ctx);959 }960 }961 962 if (pic_done) {963 e5010_hw_clear_picture_done(e5010->core_base, 1);964 dprintk(e5010, 3, "ctx: 0x%p Got output bitstream of size %d bytes\n",965 ctx, readl(e5010->core_base + JASPER_OUTPUT_SIZE_OFFSET));966 967 if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, src_buf)) {968 dst_buf->flags |= V4L2_BUF_FLAG_LAST;969 v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx);970 v4l2_event_queue_fh(&ctx->fh, &e5010_eos_event);971 dprintk(e5010, 2, "ctx: 0x%p Sending EOS\n", ctx);972 }973 v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);974 output_size = e5010_hw_get_output_size(e5010->core_base);975 vb2_set_plane_payload(&dst_buf->vb2_buf, 0, output_size + HEADER_SIZE);976 v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);977 dprintk(e5010, 3,978 "ctx: 0x%p frame done for dst_buf->sequence: %d src_buf->sequence: %d\n",979 ctx, dst_buf->sequence, src_buf->sequence);980 }981 982 v4l2_m2m_job_finish(e5010->m2m_dev, ctx->fh.m2m_ctx);983 dprintk(e5010, 3, "ctx: 0x%p Finish job\n", ctx);984 985job_unlock:986 spin_unlock(&e5010->hw_lock);987 return IRQ_HANDLED;988}989 990static int e5010_init_device(struct e5010_dev *e5010)991{992 int ret = 0;993 994 /*TODO: Set MMU in bypass mode until support for the same is added in driver*/995 e5010_hw_bypass_mmu(e5010->mmu_base, 1);996 997 if (e5010_hw_enable_auto_clock_gating(e5010->core_base, 1))998 v4l2_warn(&e5010->v4l2_dev, "failed to enable auto clock gating\n");999 1000 if (e5010_hw_enable_manual_clock_gating(e5010->core_base, 0))1001 v4l2_warn(&e5010->v4l2_dev, "failed to disable manual clock gating\n");1002 1003 if (e5010_hw_enable_crc_check(e5010->core_base, 0))1004 v4l2_warn(&e5010->v4l2_dev, "failed to disable CRC check\n");1005 1006 if (e5010_hw_enable_output_address_error_irq(e5010->core_base, 1))1007 v4l2_err(&e5010->v4l2_dev, "failed to enable Output Address Error interrupts\n");1008 1009 ret = e5010_hw_set_input_source_to_memory(e5010->core_base, 1);1010 if (ret) {1011 v4l2_err(&e5010->v4l2_dev, "failed to set input source to memory\n");1012 return ret;1013 }1014 1015 ret = e5010_hw_enable_picture_done_irq(e5010->core_base, 1);1016 if (ret)1017 v4l2_err(&e5010->v4l2_dev, "failed to enable Picture Done interrupts\n");1018 1019 return ret;1020}1021 1022static int e5010_probe(struct platform_device *pdev)1023{1024 struct e5010_dev *e5010;1025 int irq, ret = 0;1026 struct device *dev = &pdev->dev;1027 1028 ret = dma_set_mask(dev, DMA_BIT_MASK(32));1029 if (ret)1030 return dev_err_probe(dev, ret, "32-bit consistent DMA enable failed\n");1031 1032 e5010 = devm_kzalloc(dev, sizeof(*e5010), GFP_KERNEL);1033 if (!e5010)1034 return -ENOMEM;1035 1036 platform_set_drvdata(pdev, e5010);1037 1038 e5010->dev = dev;1039 1040 mutex_init(&e5010->mutex);1041 spin_lock_init(&e5010->hw_lock);1042 1043 e5010->vdev = video_device_alloc();1044 if (!e5010->vdev) {1045 dev_err(dev, "failed to allocate video device\n");1046 return -ENOMEM;1047 }1048 1049 snprintf(e5010->vdev->name, sizeof(e5010->vdev->name), "%s", E5010_MODULE_NAME);1050 e5010->vdev->fops = &e5010_fops;1051 e5010->vdev->ioctl_ops = &e5010_ioctl_ops;1052 e5010->vdev->minor = -1;1053 e5010->vdev->release = video_device_release;1054 e5010->vdev->vfl_dir = VFL_DIR_M2M;1055 e5010->vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;1056 e5010->vdev->v4l2_dev = &e5010->v4l2_dev;1057 e5010->vdev->lock = &e5010->mutex;1058 1059 ret = v4l2_device_register(dev, &e5010->v4l2_dev);1060 if (ret)1061 return dev_err_probe(dev, ret, "failed to register v4l2 device\n");1062 1063 e5010->m2m_dev = v4l2_m2m_init(&e5010_m2m_ops);1064 if (IS_ERR(e5010->m2m_dev)) {1065 ret = PTR_ERR(e5010->m2m_dev);1066 e5010->m2m_dev = NULL;1067 dev_err_probe(dev, ret, "failed to init mem2mem device\n");1068 goto fail_after_v4l2_register;1069 }1070 1071 video_set_drvdata(e5010->vdev, e5010);1072 1073 e5010->core_base = devm_platform_ioremap_resource_byname(pdev, "core");1074 if (IS_ERR(e5010->core_base)) {1075 ret = PTR_ERR(e5010->core_base);1076 dev_err_probe(dev, ret, "Missing 'core' resources area\n");1077 goto fail_after_v4l2_register;1078 }1079 1080 e5010->mmu_base = devm_platform_ioremap_resource_byname(pdev, "mmu");1081 if (IS_ERR(e5010->mmu_base)) {1082 ret = PTR_ERR(e5010->mmu_base);1083 dev_err_probe(dev, ret, "Missing 'mmu' resources area\n");1084 goto fail_after_v4l2_register;1085 }1086 1087 e5010->last_context_run = NULL;1088 1089 irq = platform_get_irq(pdev, 0);1090 ret = devm_request_irq(dev, irq, e5010_irq, 0,1091 E5010_MODULE_NAME, e5010);1092 if (ret) {1093 dev_err_probe(dev, ret, "failed to register IRQ %d\n", irq);1094 goto fail_after_v4l2_register;1095 }1096 1097 e5010->clk = devm_clk_get(dev, NULL);1098 if (IS_ERR(e5010->clk)) {1099 ret = PTR_ERR(e5010->clk);1100 dev_err_probe(dev, ret, "failed to get clock\n");1101 goto fail_after_v4l2_register;1102 }1103 1104 pm_runtime_enable(dev);1105 1106 ret = video_register_device(e5010->vdev, VFL_TYPE_VIDEO, 0);1107 if (ret) {1108 dev_err_probe(dev, ret, "failed to register video device\n");1109 goto fail_after_video_register_device;1110 }1111 1112 v4l2_info(&e5010->v4l2_dev, "Device registered as /dev/video%d\n",1113 e5010->vdev->num);1114 1115 return 0;1116 1117fail_after_video_register_device:1118 v4l2_m2m_release(e5010->m2m_dev);1119fail_after_v4l2_register:1120 v4l2_device_unregister(&e5010->v4l2_dev);1121 return ret;1122}1123 1124static void e5010_remove(struct platform_device *pdev)1125{1126 struct e5010_dev *e5010 = platform_get_drvdata(pdev);1127 1128 pm_runtime_disable(e5010->dev);1129 video_unregister_device(e5010->vdev);1130 v4l2_m2m_release(e5010->m2m_dev);1131 v4l2_device_unregister(&e5010->v4l2_dev);1132}1133 1134static void e5010_vb2_buffers_return(struct vb2_queue *q, enum vb2_buffer_state state)1135{1136 struct vb2_v4l2_buffer *vbuf;1137 struct e5010_context *ctx = vb2_get_drv_priv(q);1138 1139 if (V4L2_TYPE_IS_OUTPUT(q->type)) {1140 while ((vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) {1141 dprintk(ctx->e5010, 2, "ctx: 0x%p, buf type %s | index %d\n",1142 ctx, type_name(vbuf->vb2_buf.type), vbuf->vb2_buf.index);1143 v4l2_m2m_buf_done(vbuf, state);1144 }1145 } else {1146 while ((vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) {1147 dprintk(ctx->e5010, 2, "ctx: 0x%p, buf type %s | index %d\n",1148 ctx, type_name(vbuf->vb2_buf.type), vbuf->vb2_buf.index);1149 vb2_set_plane_payload(&vbuf->vb2_buf, 0, 0);1150 v4l2_m2m_buf_done(vbuf, state);1151 }1152 }1153}1154 1155static int e5010_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes,1156 unsigned int sizes[], struct device *alloc_devs[])1157{1158 struct e5010_context *ctx = vb2_get_drv_priv(vq);1159 struct e5010_q_data *queue;1160 int i;1161 1162 queue = get_queue(ctx, vq->type);1163 1164 if (*nplanes) {1165 if (*nplanes != queue->fmt->num_planes)1166 return -EINVAL;1167 for (i = 0; i < *nplanes; i++) {1168 if (sizes[i] < queue->sizeimage[i])1169 return -EINVAL;1170 }1171 return 0;1172 }1173 1174 *nplanes = queue->fmt->num_planes;1175 for (i = 0; i < *nplanes; i++)1176 sizes[i] = queue->sizeimage[i];1177 1178 dprintk(ctx->e5010, 2,1179 "ctx: 0x%p, type %s, buffer(s): %d, planes %d, plane1: bytes %d plane2: %d bytes\n",1180 ctx, type_name(vq->type), *nbuffers, *nplanes, sizes[0], sizes[1]);1181 1182 return 0;1183}1184 1185static void e5010_buf_finish(struct vb2_buffer *vb)1186{1187 struct e5010_context *ctx = vb2_get_drv_priv(vb->vb2_queue);1188 void *d_addr;1189 1190 if (vb->state != VB2_BUF_STATE_DONE || V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type))1191 return;1192 1193 d_addr = vb2_plane_vaddr(vb, 0);1194 write_header(ctx, d_addr);1195}1196 1197static int e5010_buf_out_validate(struct vb2_buffer *vb)1198{1199 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);1200 struct e5010_context *ctx = vb2_get_drv_priv(vb->vb2_queue);1201 1202 if (vbuf->field != V4L2_FIELD_NONE)1203 dprintk(ctx->e5010, 1, "ctx: 0x%p, field isn't supported\n", ctx);1204 1205 vbuf->field = V4L2_FIELD_NONE;1206 1207 return 0;1208}1209 1210static int e5010_buf_prepare(struct vb2_buffer *vb)1211{1212 struct e5010_context *ctx = vb2_get_drv_priv(vb->vb2_queue);1213 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);1214 struct e5010_q_data *queue;1215 int i;1216 1217 vbuf->field = V4L2_FIELD_NONE;1218 1219 queue = get_queue(ctx, vb->vb2_queue->type);1220 1221 for (i = 0; i < queue->fmt->num_planes; i++) {1222 if (vb2_plane_size(vb, i) < (unsigned long)queue->sizeimage[i]) {1223 v4l2_err(&ctx->e5010->v4l2_dev, "plane %d too small (%lu < %lu)", i,1224 vb2_plane_size(vb, i), (unsigned long)queue->sizeimage[i]);1225 1226 return -EINVAL;1227 }1228 }1229 1230 if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) {1231 vb2_set_plane_payload(vb, 0, 0);1232 vb2_set_plane_payload(vb, 1, 0);1233 }1234 1235 return 0;1236}1237 1238static void e5010_buf_queue(struct vb2_buffer *vb)1239{1240 struct e5010_context *ctx = vb2_get_drv_priv(vb->vb2_queue);1241 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);1242 1243 if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type) &&1244 vb2_is_streaming(vb->vb2_queue) &&1245 v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) {1246 struct e5010_q_data *queue = get_queue(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);1247 1248 vbuf->sequence = queue->sequence++;1249 v4l2_m2m_last_buffer_done(ctx->fh.m2m_ctx, vbuf);1250 v4l2_event_queue_fh(&ctx->fh, &e5010_eos_event);1251 return;1252 }1253 1254 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);1255}1256 1257static int e5010_encoder_cmd(struct file *file, void *priv,1258 struct v4l2_encoder_cmd *cmd)1259{1260 struct e5010_context *ctx = file->private_data;1261 int ret;1262 struct vb2_queue *cap_vq;1263 1264 cap_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);1265 1266 ret = v4l2_m2m_ioctl_try_encoder_cmd(file, &ctx->fh, cmd);1267 if (ret < 0)1268 return ret;1269 1270 if (!vb2_is_streaming(v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx)) ||1271 !vb2_is_streaming(v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx)))1272 return 0;1273 1274 ret = v4l2_m2m_ioctl_encoder_cmd(file, &ctx->fh, cmd);1275 if (ret < 0)1276 return ret;1277 1278 if (cmd->cmd == V4L2_ENC_CMD_STOP &&1279 v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))1280 v4l2_event_queue_fh(&ctx->fh, &e5010_eos_event);1281 1282 if (cmd->cmd == V4L2_ENC_CMD_START &&1283 v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))1284 vb2_clear_last_buffer_dequeued(cap_vq);1285 1286 return 0;1287}1288 1289static int e5010_start_streaming(struct vb2_queue *q, unsigned int count)1290{1291 struct e5010_context *ctx = vb2_get_drv_priv(q);1292 int ret;1293 1294 struct e5010_q_data *queue = get_queue(ctx, q->type);1295 1296 v4l2_m2m_update_start_streaming_state(ctx->fh.m2m_ctx, q);1297 queue->sequence = 0;1298 1299 ret = pm_runtime_resume_and_get(ctx->e5010->dev);1300 if (ret < 0) {1301 v4l2_err(&ctx->e5010->v4l2_dev, "failed to power up jpeg\n");1302 goto fail;1303 }1304 1305 ret = e5010_init_device(ctx->e5010);1306 if (ret) {1307 v4l2_err(&ctx->e5010->v4l2_dev, "failed to Enable e5010 device\n");1308 goto fail;1309 }1310 1311 return 0;1312 1313fail:1314 e5010_vb2_buffers_return(q, VB2_BUF_STATE_QUEUED);1315 1316 return ret;1317}1318 1319static void e5010_stop_streaming(struct vb2_queue *q)1320{1321 struct e5010_context *ctx = vb2_get_drv_priv(q);1322 1323 e5010_vb2_buffers_return(q, VB2_BUF_STATE_ERROR);1324 1325 if (V4L2_TYPE_IS_OUTPUT(q->type))1326 v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q);1327 1328 if (V4L2_TYPE_IS_OUTPUT(q->type) &&1329 v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) {1330 v4l2_event_queue_fh(&ctx->fh, &e5010_eos_event);1331 }1332 1333 pm_runtime_put_sync(ctx->e5010->dev);1334}1335 1336static void e5010_device_run(void *priv)1337{1338 struct e5010_context *ctx = priv;1339 struct e5010_dev *e5010 = ctx->e5010;1340 struct vb2_v4l2_buffer *s_vb, *d_vb;1341 u32 reg = 0;1342 int ret = 0, luma_crop_offset = 0, chroma_crop_offset = 0;1343 unsigned long flags;1344 int num_planes = ctx->out_queue.fmt->num_planes;1345 1346 spin_lock_irqsave(&e5010->hw_lock, flags);1347 s_vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);1348 WARN_ON(!s_vb);1349 d_vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);1350 WARN_ON(!d_vb);1351 if (!s_vb || !d_vb)1352 goto no_ready_buf_err;1353 1354 s_vb->sequence = ctx->out_queue.sequence++;1355 d_vb->sequence = ctx->cap_queue.sequence++;1356 1357 v4l2_m2m_buf_copy_metadata(s_vb, d_vb, false);1358 1359 if (ctx != e5010->last_context_run || ctx->update_qp) {1360 dprintk(e5010, 1, "ctx updated: 0x%p -> 0x%p, updating qp tables\n",1361 e5010->last_context_run, ctx);1362 ret = update_qp_tables(ctx);1363 }1364 1365 if (ret) {1366 ctx->update_qp = true;1367 v4l2_err(&e5010->v4l2_dev, "failed to update QP tables\n");1368 goto device_busy_err;1369 } else {1370 e5010->last_context_run = ctx;1371 ctx->update_qp = false;1372 }1373 1374 /* Set I/O Buffer addresses */1375 reg = (u32)vb2_dma_contig_plane_dma_addr(&s_vb->vb2_buf, 0);1376 1377 if (ctx->out_queue.crop_set) {1378 luma_crop_offset = ctx->out_queue.bytesperline[0] * ctx->out_queue.crop.top +1379 ctx->out_queue.crop.left;1380 1381 if (ctx->out_queue.fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_422) {1382 chroma_crop_offset =1383 ctx->out_queue.bytesperline[0] * ctx->out_queue.crop.top1384 + ctx->out_queue.crop.left;1385 } else {1386 chroma_crop_offset =1387 ctx->out_queue.bytesperline[0] * ctx->out_queue.crop.top / 21388 + ctx->out_queue.crop.left;1389 }1390 1391 dprintk(e5010, 1, "Luma crop offset : %x, chroma crop offset : %x\n",1392 luma_crop_offset, chroma_crop_offset);1393 }1394 1395 ret = e5010_hw_set_input_luma_addr(e5010->core_base, reg + luma_crop_offset);1396 if (ret || !reg) {1397 v4l2_err(&e5010->v4l2_dev, "failed to set input luma address\n");1398 goto device_busy_err;1399 }1400 1401 if (num_planes == 1)1402 reg += (ctx->out_queue.bytesperline[0]) * (ctx->out_queue.height);1403 else1404 reg = (u32)vb2_dma_contig_plane_dma_addr(&s_vb->vb2_buf, 1);1405 1406 dprintk(e5010, 3,1407 "ctx: 0x%p, luma_addr: 0x%x, chroma_addr: 0x%x, out_addr: 0x%x\n",1408 ctx, (u32)vb2_dma_contig_plane_dma_addr(&s_vb->vb2_buf, 0) + luma_crop_offset,1409 reg + chroma_crop_offset, (u32)vb2_dma_contig_plane_dma_addr(&d_vb->vb2_buf, 0));1410 1411 dprintk(e5010, 3,1412 "ctx: 0x%p, buf indices: src_index: %d, dst_index: %d\n",1413 ctx, s_vb->vb2_buf.index, d_vb->vb2_buf.index);1414 1415 ret = e5010_hw_set_input_chroma_addr(e5010->core_base, reg + chroma_crop_offset);1416 if (ret || !reg) {1417 v4l2_err(&e5010->v4l2_dev, "failed to set input chroma address\n");1418 goto device_busy_err;1419 }1420 1421 reg = (u32)vb2_dma_contig_plane_dma_addr(&d_vb->vb2_buf, 0);1422 reg += HEADER_SIZE;1423 ret = e5010_hw_set_output_base_addr(e5010->core_base, reg);1424 if (ret || !reg) {1425 v4l2_err(&e5010->v4l2_dev, "failed to set output base address\n");1426 goto device_busy_err;1427 }1428 1429 /* Set input settings */1430 ret = e5010_hw_set_horizontal_size(e5010->core_base, ctx->out_queue.crop.width - 1);1431 if (ret) {1432 v4l2_err(&e5010->v4l2_dev, "failed to set input width\n");1433 goto device_busy_err;1434 }1435 1436 ret = e5010_hw_set_vertical_size(e5010->core_base, ctx->out_queue.crop.height - 1);1437 if (ret) {1438 v4l2_err(&e5010->v4l2_dev, "failed to set input width\n");1439 goto device_busy_err;1440 }1441 1442 ret = e5010_hw_set_luma_stride(e5010->core_base, ctx->out_queue.bytesperline[0]);1443 if (ret) {1444 v4l2_err(&e5010->v4l2_dev, "failed to set luma stride\n");1445 goto device_busy_err;1446 }1447 1448 ret = e5010_hw_set_chroma_stride(e5010->core_base, ctx->out_queue.bytesperline[0]);1449 if (ret) {1450 v4l2_err(&e5010->v4l2_dev, "failed to set chroma stride\n");1451 goto device_busy_err;1452 }1453 1454 ret = e5010_set_input_subsampling(e5010->core_base, ctx->out_queue.fmt->subsampling);1455 if (ret) {1456 v4l2_err(&e5010->v4l2_dev, "failed to set input subsampling\n");1457 goto device_busy_err;1458 }1459 1460 ret = e5010_hw_set_chroma_order(e5010->core_base, ctx->out_queue.fmt->chroma_order);1461 if (ret) {1462 v4l2_err(&e5010->v4l2_dev, "failed to set chroma order\n");1463 goto device_busy_err;1464 }1465 1466 e5010_hw_set_output_max_size(e5010->core_base, d_vb->planes[0].length);1467 e5010_hw_encode_start(e5010->core_base, 1);1468 1469 spin_unlock_irqrestore(&e5010->hw_lock, flags);1470 1471 return;1472 1473device_busy_err:1474 e5010_reset(e5010->dev, e5010->core_base, e5010->mmu_base);1475 1476no_ready_buf_err:1477 if (s_vb) {1478 v4l2_m2m_src_buf_remove_by_buf(ctx->fh.m2m_ctx, s_vb);1479 v4l2_m2m_buf_done(s_vb, VB2_BUF_STATE_ERROR);1480 }1481 1482 if (d_vb) {1483 v4l2_m2m_dst_buf_remove_by_buf(ctx->fh.m2m_ctx, d_vb);1484 /* Payload set to 1 since 0 payload can trigger EOS */1485 vb2_set_plane_payload(&d_vb->vb2_buf, 0, 1);1486 v4l2_m2m_buf_done(d_vb, VB2_BUF_STATE_ERROR);1487 }1488 v4l2_m2m_job_finish(e5010->m2m_dev, ctx->fh.m2m_ctx);1489 spin_unlock_irqrestore(&e5010->hw_lock, flags);1490}1491 1492#ifdef CONFIG_PM1493static int e5010_runtime_resume(struct device *dev)1494{1495 struct e5010_dev *e5010 = dev_get_drvdata(dev);1496 int ret;1497 1498 ret = clk_prepare_enable(e5010->clk);1499 if (ret < 0) {1500 v4l2_err(&e5010->v4l2_dev, "failed to enable clock\n");1501 return ret;1502 }1503 1504 return 0;1505}1506 1507static int e5010_runtime_suspend(struct device *dev)1508{1509 struct e5010_dev *e5010 = dev_get_drvdata(dev);1510 1511 clk_disable_unprepare(e5010->clk);1512 1513 return 0;1514}1515#endif1516 1517#ifdef CONFIG_PM_SLEEP1518static int e5010_suspend(struct device *dev)1519{1520 struct e5010_dev *e5010 = dev_get_drvdata(dev);1521 1522 v4l2_m2m_suspend(e5010->m2m_dev);1523 1524 return pm_runtime_force_suspend(dev);1525}1526 1527static int e5010_resume(struct device *dev)1528{1529 struct e5010_dev *e5010 = dev_get_drvdata(dev);1530 int ret;1531 1532 ret = pm_runtime_force_resume(dev);1533 if (ret < 0)1534 return ret;1535 1536 ret = e5010_init_device(e5010);1537 if (ret) {1538 dev_err(dev, "Failed to re-enable e5010 device\n");1539 return ret;1540 }1541 1542 v4l2_m2m_resume(e5010->m2m_dev);1543 1544 return ret;1545}1546#endif1547 1548static const struct dev_pm_ops e5010_pm_ops = {1549 SET_RUNTIME_PM_OPS(e5010_runtime_suspend,1550 e5010_runtime_resume, NULL)1551 SET_SYSTEM_SLEEP_PM_OPS(e5010_suspend, e5010_resume)1552};1553 1554static const struct v4l2_ioctl_ops e5010_ioctl_ops = {1555 .vidioc_querycap = e5010_querycap,1556 1557 .vidioc_enum_fmt_vid_cap = e5010_enum_fmt,1558 .vidioc_g_fmt_vid_cap_mplane = e5010_g_fmt,1559 .vidioc_try_fmt_vid_cap_mplane = e5010_try_fmt,1560 .vidioc_s_fmt_vid_cap_mplane = e5010_s_fmt,1561 1562 .vidioc_enum_fmt_vid_out = e5010_enum_fmt,1563 .vidioc_g_fmt_vid_out_mplane = e5010_g_fmt,1564 .vidioc_try_fmt_vid_out_mplane = e5010_try_fmt,1565 .vidioc_s_fmt_vid_out_mplane = e5010_s_fmt,1566 1567 .vidioc_g_selection = e5010_g_selection,1568 .vidioc_s_selection = e5010_s_selection,1569 1570 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,1571 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,1572 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,1573 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,1574 .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,1575 .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,1576 .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,1577 1578 .vidioc_streamon = v4l2_m2m_ioctl_streamon,1579 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,1580 .vidioc_log_status = v4l2_ctrl_log_status,1581 1582 .vidioc_subscribe_event = e5010_subscribe_event,1583 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,1584 .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd,1585 .vidioc_encoder_cmd = e5010_encoder_cmd,1586 1587 .vidioc_enum_framesizes = e5010_enum_framesizes,1588};1589 1590static const struct vb2_ops e5010_video_ops = {1591 .queue_setup = e5010_queue_setup,1592 .buf_queue = e5010_buf_queue,1593 .buf_finish = e5010_buf_finish,1594 .buf_prepare = e5010_buf_prepare,1595 .buf_out_validate = e5010_buf_out_validate,1596 .wait_prepare = vb2_ops_wait_prepare,1597 .wait_finish = vb2_ops_wait_finish,1598 .start_streaming = e5010_start_streaming,1599 .stop_streaming = e5010_stop_streaming,1600};1601 1602static const struct v4l2_file_operations e5010_fops = {1603 .owner = THIS_MODULE,1604 .open = e5010_open,1605 .release = e5010_release,1606 .poll = v4l2_m2m_fop_poll,1607 .unlocked_ioctl = video_ioctl2,1608 .mmap = v4l2_m2m_fop_mmap,1609};1610 1611static const struct v4l2_m2m_ops e5010_m2m_ops = {1612 .device_run = e5010_device_run,1613};1614 1615static const struct of_device_id e5010_of_match[] = {1616 {.compatible = "img,e5010-jpeg-enc"}, { /* end */},1617};1618MODULE_DEVICE_TABLE(of, e5010_of_match);1619 1620static struct platform_driver e5010_driver = {1621 .probe = e5010_probe,1622 .remove_new = e5010_remove,1623 .driver = {1624 .name = E5010_MODULE_NAME,1625 .of_match_table = e5010_of_match,1626 .pm = &e5010_pm_ops,1627 },1628};1629module_platform_driver(e5010_driver);1630 1631MODULE_LICENSE("GPL");1632MODULE_DESCRIPTION("Imagination E5010 JPEG encoder driver");1633