brintos

brintos / linux-shallow public Read only

0
0
Text · 45.1 KiB · 187f2d8 Raw
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