1*ee4a77a3SMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0
2*ee4a77a3SMauro Carvalho Chehab /*
3*ee4a77a3SMauro Carvalho Chehab  * Author: Mikhail Ulyanov
4*ee4a77a3SMauro Carvalho Chehab  * Copyright (C) 2014-2015 Cogent Embedded, Inc.  <source@cogentembedded.com>
5*ee4a77a3SMauro Carvalho Chehab  * Copyright (C) 2014-2015 Renesas Electronics Corporation
6*ee4a77a3SMauro Carvalho Chehab  *
7*ee4a77a3SMauro Carvalho Chehab  * This is based on the drivers/media/platform/s5p-jpeg driver by
8*ee4a77a3SMauro Carvalho Chehab  * Andrzej Pietrasiewicz and Jacek Anaszewski.
9*ee4a77a3SMauro Carvalho Chehab  * Some portions of code inspired by VSP1 driver by Laurent Pinchart.
10*ee4a77a3SMauro Carvalho Chehab  *
11*ee4a77a3SMauro Carvalho Chehab  * TODO in order of priority:
12*ee4a77a3SMauro Carvalho Chehab  *      1) Rotation
13*ee4a77a3SMauro Carvalho Chehab  *      2) Cropping
14*ee4a77a3SMauro Carvalho Chehab  *      3) V4L2_CID_JPEG_ACTIVE_MARKER
15*ee4a77a3SMauro Carvalho Chehab  */
16*ee4a77a3SMauro Carvalho Chehab 
17*ee4a77a3SMauro Carvalho Chehab #include <asm/unaligned.h>
18*ee4a77a3SMauro Carvalho Chehab #include <linux/clk.h>
19*ee4a77a3SMauro Carvalho Chehab #include <linux/err.h>
20*ee4a77a3SMauro Carvalho Chehab #include <linux/interrupt.h>
21*ee4a77a3SMauro Carvalho Chehab #include <linux/io.h>
22*ee4a77a3SMauro Carvalho Chehab #include <linux/kernel.h>
23*ee4a77a3SMauro Carvalho Chehab #include <linux/module.h>
24*ee4a77a3SMauro Carvalho Chehab #include <linux/of.h>
25*ee4a77a3SMauro Carvalho Chehab #include <linux/of_device.h>
26*ee4a77a3SMauro Carvalho Chehab #include <linux/platform_device.h>
27*ee4a77a3SMauro Carvalho Chehab #include <linux/slab.h>
28*ee4a77a3SMauro Carvalho Chehab #include <linux/spinlock.h>
29*ee4a77a3SMauro Carvalho Chehab #include <linux/string.h>
30*ee4a77a3SMauro Carvalho Chehab #include <linux/videodev2.h>
31*ee4a77a3SMauro Carvalho Chehab #include <media/v4l2-ctrls.h>
32*ee4a77a3SMauro Carvalho Chehab #include <media/v4l2-device.h>
33*ee4a77a3SMauro Carvalho Chehab #include <media/v4l2-event.h>
34*ee4a77a3SMauro Carvalho Chehab #include <media/v4l2-fh.h>
35*ee4a77a3SMauro Carvalho Chehab #include <media/v4l2-mem2mem.h>
36*ee4a77a3SMauro Carvalho Chehab #include <media/v4l2-ioctl.h>
37*ee4a77a3SMauro Carvalho Chehab #include <media/videobuf2-v4l2.h>
38*ee4a77a3SMauro Carvalho Chehab #include <media/videobuf2-dma-contig.h>
39*ee4a77a3SMauro Carvalho Chehab 
40*ee4a77a3SMauro Carvalho Chehab 
41*ee4a77a3SMauro Carvalho Chehab #define DRV_NAME "rcar_jpu"
42*ee4a77a3SMauro Carvalho Chehab 
43*ee4a77a3SMauro Carvalho Chehab /*
44*ee4a77a3SMauro Carvalho Chehab  * Align JPEG header end to cache line to make sure we will not have any issues
45*ee4a77a3SMauro Carvalho Chehab  * with cache; additionally to requirement (33.3.27 R01UH0501EJ0100 Rev.1.00)
46*ee4a77a3SMauro Carvalho Chehab  */
47*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_HDR_SIZE		(ALIGN(0x258, L1_CACHE_BYTES))
48*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_MAX_BYTES_PER_PIXEL	2	/* 16 bit precision format */
49*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_MIN_SIZE		25	/* SOI + SOF + EOI */
50*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_QTBL_SIZE		0x40
51*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_HDCTBL_SIZE		0x1c
52*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_HACTBL_SIZE		0xb2
53*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_HEIGHT_OFFSET		0x91
54*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_WIDTH_OFFSET		0x93
55*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_SUBS_OFFSET		0x97
56*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_QTBL_LUM_OFFSET	0x07
57*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_QTBL_CHR_OFFSET	0x4c
58*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_HDCTBL_LUM_OFFSET	0xa4
59*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_HACTBL_LUM_OFFSET	0xc5
60*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_HDCTBL_CHR_OFFSET	0x17c
61*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_HACTBL_CHR_OFFSET	0x19d
62*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_PADDING_OFFSET		0x24f
63*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_LUM 0x00
64*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_CHR 0x01
65*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_DC  0x00
66*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_AC  0x10
67*ee4a77a3SMauro Carvalho Chehab 
68*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_422 0x21
69*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_420 0x22
70*ee4a77a3SMauro Carvalho Chehab 
71*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_DEFAULT_422_PIX_FMT V4L2_PIX_FMT_NV16M
72*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_DEFAULT_420_PIX_FMT V4L2_PIX_FMT_NV12M
73*ee4a77a3SMauro Carvalho Chehab 
74*ee4a77a3SMauro Carvalho Chehab /* JPEG markers */
75*ee4a77a3SMauro Carvalho Chehab #define TEM	0x01
76*ee4a77a3SMauro Carvalho Chehab #define SOF0	0xc0
77*ee4a77a3SMauro Carvalho Chehab #define RST	0xd0
78*ee4a77a3SMauro Carvalho Chehab #define SOI	0xd8
79*ee4a77a3SMauro Carvalho Chehab #define EOI	0xd9
80*ee4a77a3SMauro Carvalho Chehab #define DHP	0xde
81*ee4a77a3SMauro Carvalho Chehab #define DHT	0xc4
82*ee4a77a3SMauro Carvalho Chehab #define COM	0xfe
83*ee4a77a3SMauro Carvalho Chehab #define DQT	0xdb
84*ee4a77a3SMauro Carvalho Chehab #define DRI	0xdd
85*ee4a77a3SMauro Carvalho Chehab #define APP0	0xe0
86*ee4a77a3SMauro Carvalho Chehab 
87*ee4a77a3SMauro Carvalho Chehab #define JPU_RESET_TIMEOUT	100 /* ms */
88*ee4a77a3SMauro Carvalho Chehab #define JPU_JOB_TIMEOUT		300 /* ms */
89*ee4a77a3SMauro Carvalho Chehab #define JPU_MAX_QUALITY		4
90*ee4a77a3SMauro Carvalho Chehab #define JPU_WIDTH_MIN		16
91*ee4a77a3SMauro Carvalho Chehab #define JPU_HEIGHT_MIN		16
92*ee4a77a3SMauro Carvalho Chehab #define JPU_WIDTH_MAX		4096
93*ee4a77a3SMauro Carvalho Chehab #define JPU_HEIGHT_MAX		4096
94*ee4a77a3SMauro Carvalho Chehab #define JPU_MEMALIGN		8
95*ee4a77a3SMauro Carvalho Chehab 
96*ee4a77a3SMauro Carvalho Chehab /* Flags that indicate a format can be used for capture/output */
97*ee4a77a3SMauro Carvalho Chehab #define JPU_FMT_TYPE_OUTPUT	0
98*ee4a77a3SMauro Carvalho Chehab #define JPU_FMT_TYPE_CAPTURE	1
99*ee4a77a3SMauro Carvalho Chehab #define JPU_ENC_CAPTURE		(1 << 0)
100*ee4a77a3SMauro Carvalho Chehab #define JPU_ENC_OUTPUT		(1 << 1)
101*ee4a77a3SMauro Carvalho Chehab #define JPU_DEC_CAPTURE		(1 << 2)
102*ee4a77a3SMauro Carvalho Chehab #define JPU_DEC_OUTPUT		(1 << 3)
103*ee4a77a3SMauro Carvalho Chehab 
104*ee4a77a3SMauro Carvalho Chehab /*
105*ee4a77a3SMauro Carvalho Chehab  * JPEG registers and bits
106*ee4a77a3SMauro Carvalho Chehab  */
107*ee4a77a3SMauro Carvalho Chehab 
108*ee4a77a3SMauro Carvalho Chehab /* JPEG code mode register */
109*ee4a77a3SMauro Carvalho Chehab #define JCMOD	0x00
110*ee4a77a3SMauro Carvalho Chehab #define JCMOD_PCTR		(1 << 7)
111*ee4a77a3SMauro Carvalho Chehab #define JCMOD_MSKIP_ENABLE	(1 << 5)
112*ee4a77a3SMauro Carvalho Chehab #define JCMOD_DSP_ENC		(0 << 3)
113*ee4a77a3SMauro Carvalho Chehab #define JCMOD_DSP_DEC		(1 << 3)
114*ee4a77a3SMauro Carvalho Chehab #define JCMOD_REDU		(7 << 0)
115*ee4a77a3SMauro Carvalho Chehab #define JCMOD_REDU_422		(1 << 0)
116*ee4a77a3SMauro Carvalho Chehab #define JCMOD_REDU_420		(2 << 0)
117*ee4a77a3SMauro Carvalho Chehab 
118*ee4a77a3SMauro Carvalho Chehab /* JPEG code command register */
119*ee4a77a3SMauro Carvalho Chehab #define JCCMD	0x04
120*ee4a77a3SMauro Carvalho Chehab #define JCCMD_SRST	(1 << 12)
121*ee4a77a3SMauro Carvalho Chehab #define JCCMD_JEND	(1 << 2)
122*ee4a77a3SMauro Carvalho Chehab #define JCCMD_JSRT	(1 << 0)
123*ee4a77a3SMauro Carvalho Chehab 
124*ee4a77a3SMauro Carvalho Chehab /* JPEG code quantization table number register */
125*ee4a77a3SMauro Carvalho Chehab #define JCQTN	0x0c
126*ee4a77a3SMauro Carvalho Chehab #define JCQTN_SHIFT(t)		(((t) - 1) << 1)
127*ee4a77a3SMauro Carvalho Chehab 
128*ee4a77a3SMauro Carvalho Chehab /* JPEG code Huffman table number register */
129*ee4a77a3SMauro Carvalho Chehab #define JCHTN	0x10
130*ee4a77a3SMauro Carvalho Chehab #define JCHTN_AC_SHIFT(t)	(((t) << 1) - 1)
131*ee4a77a3SMauro Carvalho Chehab #define JCHTN_DC_SHIFT(t)	(((t) - 1) << 1)
132*ee4a77a3SMauro Carvalho Chehab 
133*ee4a77a3SMauro Carvalho Chehab #define JCVSZU	0x1c /* JPEG code vertical size upper register */
134*ee4a77a3SMauro Carvalho Chehab #define JCVSZD	0x20 /* JPEG code vertical size lower register */
135*ee4a77a3SMauro Carvalho Chehab #define JCHSZU	0x24 /* JPEG code horizontal size upper register */
136*ee4a77a3SMauro Carvalho Chehab #define JCHSZD	0x28 /* JPEG code horizontal size lower register */
137*ee4a77a3SMauro Carvalho Chehab #define JCSZ_MASK 0xff /* JPEG code h/v size register contains only 1 byte*/
138*ee4a77a3SMauro Carvalho Chehab 
139*ee4a77a3SMauro Carvalho Chehab #define JCDTCU	0x2c /* JPEG code data count upper register */
140*ee4a77a3SMauro Carvalho Chehab #define JCDTCM	0x30 /* JPEG code data count middle register */
141*ee4a77a3SMauro Carvalho Chehab #define JCDTCD	0x34 /* JPEG code data count lower register */
142*ee4a77a3SMauro Carvalho Chehab 
143*ee4a77a3SMauro Carvalho Chehab /* JPEG interrupt enable register */
144*ee4a77a3SMauro Carvalho Chehab #define JINTE	0x38
145*ee4a77a3SMauro Carvalho Chehab #define JINTE_ERR		(7 << 5) /* INT5 + INT6 + INT7 */
146*ee4a77a3SMauro Carvalho Chehab #define JINTE_TRANSF_COMPL	(1 << 10)
147*ee4a77a3SMauro Carvalho Chehab 
148*ee4a77a3SMauro Carvalho Chehab /* JPEG interrupt status register */
149*ee4a77a3SMauro Carvalho Chehab #define JINTS	0x3c
150*ee4a77a3SMauro Carvalho Chehab #define JINTS_MASK	0x7c68
151*ee4a77a3SMauro Carvalho Chehab #define JINTS_ERR		(1 << 5)
152*ee4a77a3SMauro Carvalho Chehab #define JINTS_PROCESS_COMPL	(1 << 6)
153*ee4a77a3SMauro Carvalho Chehab #define JINTS_TRANSF_COMPL	(1 << 10)
154*ee4a77a3SMauro Carvalho Chehab 
155*ee4a77a3SMauro Carvalho Chehab #define JCDERR	0x40 /* JPEG code decode error register */
156*ee4a77a3SMauro Carvalho Chehab #define JCDERR_MASK	0xf /* JPEG code decode error register mask*/
157*ee4a77a3SMauro Carvalho Chehab 
158*ee4a77a3SMauro Carvalho Chehab /* JPEG interface encoding */
159*ee4a77a3SMauro Carvalho Chehab #define JIFECNT	0x70
160*ee4a77a3SMauro Carvalho Chehab #define JIFECNT_INFT_422	0
161*ee4a77a3SMauro Carvalho Chehab #define JIFECNT_INFT_420	1
162*ee4a77a3SMauro Carvalho Chehab #define JIFECNT_SWAP_WB		(3 << 4) /* to JPU */
163*ee4a77a3SMauro Carvalho Chehab 
164*ee4a77a3SMauro Carvalho Chehab #define JIFESYA1	0x74	/* encode source Y address register 1 */
165*ee4a77a3SMauro Carvalho Chehab #define JIFESCA1	0x78	/* encode source C address register 1 */
166*ee4a77a3SMauro Carvalho Chehab #define JIFESYA2	0x7c	/* encode source Y address register 2 */
167*ee4a77a3SMauro Carvalho Chehab #define JIFESCA2	0x80	/* encode source C address register 2 */
168*ee4a77a3SMauro Carvalho Chehab #define JIFESMW		0x84	/* encode source memory width register */
169*ee4a77a3SMauro Carvalho Chehab #define JIFESVSZ	0x88	/* encode source vertical size register */
170*ee4a77a3SMauro Carvalho Chehab #define JIFESHSZ	0x8c	/* encode source horizontal size register */
171*ee4a77a3SMauro Carvalho Chehab #define JIFEDA1		0x90	/* encode destination address register 1 */
172*ee4a77a3SMauro Carvalho Chehab #define JIFEDA2		0x94	/* encode destination address register 2 */
173*ee4a77a3SMauro Carvalho Chehab 
174*ee4a77a3SMauro Carvalho Chehab /* JPEG decoding control register */
175*ee4a77a3SMauro Carvalho Chehab #define JIFDCNT	0xa0
176*ee4a77a3SMauro Carvalho Chehab #define JIFDCNT_SWAP_WB		(3 << 1) /* from JPU */
177*ee4a77a3SMauro Carvalho Chehab 
178*ee4a77a3SMauro Carvalho Chehab #define JIFDSA1		0xa4	/* decode source address register 1 */
179*ee4a77a3SMauro Carvalho Chehab #define JIFDDMW		0xb0	/* decode destination  memory width register */
180*ee4a77a3SMauro Carvalho Chehab #define JIFDDVSZ	0xb4	/* decode destination  vert. size register */
181*ee4a77a3SMauro Carvalho Chehab #define JIFDDHSZ	0xb8	/* decode destination  horiz. size register */
182*ee4a77a3SMauro Carvalho Chehab #define JIFDDYA1	0xbc	/* decode destination  Y address register 1 */
183*ee4a77a3SMauro Carvalho Chehab #define JIFDDCA1	0xc0	/* decode destination  C address register 1 */
184*ee4a77a3SMauro Carvalho Chehab 
185*ee4a77a3SMauro Carvalho Chehab #define JCQTBL(n)	(0x10000 + (n) * 0x40)	/* quantization tables regs */
186*ee4a77a3SMauro Carvalho Chehab #define JCHTBD(n)	(0x10100 + (n) * 0x100)	/* Huffman table DC regs */
187*ee4a77a3SMauro Carvalho Chehab #define JCHTBA(n)	(0x10120 + (n) * 0x100)	/* Huffman table AC regs */
188*ee4a77a3SMauro Carvalho Chehab 
189*ee4a77a3SMauro Carvalho Chehab /**
190*ee4a77a3SMauro Carvalho Chehab  * struct jpu - JPEG IP abstraction
191*ee4a77a3SMauro Carvalho Chehab  * @mutex: the mutex protecting this structure
192*ee4a77a3SMauro Carvalho Chehab  * @lock: spinlock protecting the device contexts
193*ee4a77a3SMauro Carvalho Chehab  * @v4l2_dev: v4l2 device for mem2mem mode
194*ee4a77a3SMauro Carvalho Chehab  * @vfd_encoder: video device node for encoder mem2mem mode
195*ee4a77a3SMauro Carvalho Chehab  * @vfd_decoder: video device node for decoder mem2mem mode
196*ee4a77a3SMauro Carvalho Chehab  * @m2m_dev: v4l2 mem2mem device data
197*ee4a77a3SMauro Carvalho Chehab  * @curr: pointer to current context
198*ee4a77a3SMauro Carvalho Chehab  * @regs: JPEG IP registers mapping
199*ee4a77a3SMauro Carvalho Chehab  * @irq: JPEG IP irq
200*ee4a77a3SMauro Carvalho Chehab  * @clk: JPEG IP clock
201*ee4a77a3SMauro Carvalho Chehab  * @dev: JPEG IP struct device
202*ee4a77a3SMauro Carvalho Chehab  * @ref_count: reference counter
203*ee4a77a3SMauro Carvalho Chehab  */
204*ee4a77a3SMauro Carvalho Chehab struct jpu {
205*ee4a77a3SMauro Carvalho Chehab 	struct mutex	mutex;
206*ee4a77a3SMauro Carvalho Chehab 	spinlock_t	lock;
207*ee4a77a3SMauro Carvalho Chehab 	struct v4l2_device	v4l2_dev;
208*ee4a77a3SMauro Carvalho Chehab 	struct video_device	vfd_encoder;
209*ee4a77a3SMauro Carvalho Chehab 	struct video_device	vfd_decoder;
210*ee4a77a3SMauro Carvalho Chehab 	struct v4l2_m2m_dev	*m2m_dev;
211*ee4a77a3SMauro Carvalho Chehab 	struct jpu_ctx		*curr;
212*ee4a77a3SMauro Carvalho Chehab 
213*ee4a77a3SMauro Carvalho Chehab 	void __iomem		*regs;
214*ee4a77a3SMauro Carvalho Chehab 	unsigned int		irq;
215*ee4a77a3SMauro Carvalho Chehab 	struct clk		*clk;
216*ee4a77a3SMauro Carvalho Chehab 	struct device		*dev;
217*ee4a77a3SMauro Carvalho Chehab 	int			ref_count;
218*ee4a77a3SMauro Carvalho Chehab };
219*ee4a77a3SMauro Carvalho Chehab 
220*ee4a77a3SMauro Carvalho Chehab /**
221*ee4a77a3SMauro Carvalho Chehab  * struct jpu_buffer - driver's specific video buffer
222*ee4a77a3SMauro Carvalho Chehab  * @buf: m2m buffer
223*ee4a77a3SMauro Carvalho Chehab  * @compr_quality: destination image quality in compression mode
224*ee4a77a3SMauro Carvalho Chehab  * @subsampling: source image subsampling in decompression mode
225*ee4a77a3SMauro Carvalho Chehab  */
226*ee4a77a3SMauro Carvalho Chehab struct jpu_buffer {
227*ee4a77a3SMauro Carvalho Chehab 	struct v4l2_m2m_buffer buf;
228*ee4a77a3SMauro Carvalho Chehab 	unsigned short	compr_quality;
229*ee4a77a3SMauro Carvalho Chehab 	unsigned char	subsampling;
230*ee4a77a3SMauro Carvalho Chehab };
231*ee4a77a3SMauro Carvalho Chehab 
232*ee4a77a3SMauro Carvalho Chehab /**
233*ee4a77a3SMauro Carvalho Chehab  * struct jpu_fmt - driver's internal format data
234*ee4a77a3SMauro Carvalho Chehab  * @fourcc: the fourcc code, 0 if not applicable
235*ee4a77a3SMauro Carvalho Chehab  * @colorspace: the colorspace specifier
236*ee4a77a3SMauro Carvalho Chehab  * @bpp: number of bits per pixel per plane
237*ee4a77a3SMauro Carvalho Chehab  * @h_align: horizontal alignment order (align to 2^h_align)
238*ee4a77a3SMauro Carvalho Chehab  * @v_align: vertical alignment order (align to 2^v_align)
239*ee4a77a3SMauro Carvalho Chehab  * @subsampling: (horizontal:4 | vertical:4) subsampling factor
240*ee4a77a3SMauro Carvalho Chehab  * @num_planes: number of planes
241*ee4a77a3SMauro Carvalho Chehab  * @types: types of queue this format is applicable to
242*ee4a77a3SMauro Carvalho Chehab  */
243*ee4a77a3SMauro Carvalho Chehab struct jpu_fmt {
244*ee4a77a3SMauro Carvalho Chehab 	u32 fourcc;
245*ee4a77a3SMauro Carvalho Chehab 	u32 colorspace;
246*ee4a77a3SMauro Carvalho Chehab 	u8 bpp[2];
247*ee4a77a3SMauro Carvalho Chehab 	u8 h_align;
248*ee4a77a3SMauro Carvalho Chehab 	u8 v_align;
249*ee4a77a3SMauro Carvalho Chehab 	u8 subsampling;
250*ee4a77a3SMauro Carvalho Chehab 	u8 num_planes;
251*ee4a77a3SMauro Carvalho Chehab 	u16 types;
252*ee4a77a3SMauro Carvalho Chehab };
253*ee4a77a3SMauro Carvalho Chehab 
254*ee4a77a3SMauro Carvalho Chehab /**
255*ee4a77a3SMauro Carvalho Chehab  * struct jpu_q_data - parameters of one queue
256*ee4a77a3SMauro Carvalho Chehab  * @fmtinfo: driver-specific format of this queue
257*ee4a77a3SMauro Carvalho Chehab  * @format: multiplanar format of this queue
258*ee4a77a3SMauro Carvalho Chehab  * @sequence: sequence number
259*ee4a77a3SMauro Carvalho Chehab  */
260*ee4a77a3SMauro Carvalho Chehab struct jpu_q_data {
261*ee4a77a3SMauro Carvalho Chehab 	struct jpu_fmt *fmtinfo;
262*ee4a77a3SMauro Carvalho Chehab 	struct v4l2_pix_format_mplane format;
263*ee4a77a3SMauro Carvalho Chehab 	unsigned int sequence;
264*ee4a77a3SMauro Carvalho Chehab };
265*ee4a77a3SMauro Carvalho Chehab 
266*ee4a77a3SMauro Carvalho Chehab /**
267*ee4a77a3SMauro Carvalho Chehab  * struct jpu_ctx - the device context data
268*ee4a77a3SMauro Carvalho Chehab  * @jpu: JPEG IP device for this context
269*ee4a77a3SMauro Carvalho Chehab  * @encoder: compression (encode) operation or decompression (decode)
270*ee4a77a3SMauro Carvalho Chehab  * @compr_quality: destination image quality in compression (encode) mode
271*ee4a77a3SMauro Carvalho Chehab  * @out_q: source (output) queue information
272*ee4a77a3SMauro Carvalho Chehab  * @cap_q: destination (capture) queue information
273*ee4a77a3SMauro Carvalho Chehab  * @fh: file handler
274*ee4a77a3SMauro Carvalho Chehab  * @ctrl_handler: controls handler
275*ee4a77a3SMauro Carvalho Chehab  */
276*ee4a77a3SMauro Carvalho Chehab struct jpu_ctx {
277*ee4a77a3SMauro Carvalho Chehab 	struct jpu		*jpu;
278*ee4a77a3SMauro Carvalho Chehab 	bool			encoder;
279*ee4a77a3SMauro Carvalho Chehab 	unsigned short		compr_quality;
280*ee4a77a3SMauro Carvalho Chehab 	struct jpu_q_data	out_q;
281*ee4a77a3SMauro Carvalho Chehab 	struct jpu_q_data	cap_q;
282*ee4a77a3SMauro Carvalho Chehab 	struct v4l2_fh		fh;
283*ee4a77a3SMauro Carvalho Chehab 	struct v4l2_ctrl_handler ctrl_handler;
284*ee4a77a3SMauro Carvalho Chehab };
285*ee4a77a3SMauro Carvalho Chehab 
286*ee4a77a3SMauro Carvalho Chehab  /**
287*ee4a77a3SMauro Carvalho Chehab  * jpeg_buffer - description of memory containing input JPEG data
288*ee4a77a3SMauro Carvalho Chehab  * @end: end position in the buffer
289*ee4a77a3SMauro Carvalho Chehab  * @curr: current position in the buffer
290*ee4a77a3SMauro Carvalho Chehab  */
291*ee4a77a3SMauro Carvalho Chehab struct jpeg_buffer {
292*ee4a77a3SMauro Carvalho Chehab 	void *end;
293*ee4a77a3SMauro Carvalho Chehab 	void *curr;
294*ee4a77a3SMauro Carvalho Chehab };
295*ee4a77a3SMauro Carvalho Chehab 
296*ee4a77a3SMauro Carvalho Chehab static struct jpu_fmt jpu_formats[] = {
297*ee4a77a3SMauro Carvalho Chehab 	{ V4L2_PIX_FMT_JPEG, V4L2_COLORSPACE_JPEG,
298*ee4a77a3SMauro Carvalho Chehab 	  {0, 0}, 0, 0, 0, 1, JPU_ENC_CAPTURE | JPU_DEC_OUTPUT },
299*ee4a77a3SMauro Carvalho Chehab 	{ V4L2_PIX_FMT_NV16M, V4L2_COLORSPACE_SRGB,
300*ee4a77a3SMauro Carvalho Chehab 	  {8, 8}, 2, 2, JPU_JPEG_422, 2, JPU_ENC_OUTPUT | JPU_DEC_CAPTURE },
301*ee4a77a3SMauro Carvalho Chehab 	{ V4L2_PIX_FMT_NV12M, V4L2_COLORSPACE_SRGB,
302*ee4a77a3SMauro Carvalho Chehab 	  {8, 4}, 2, 2, JPU_JPEG_420, 2, JPU_ENC_OUTPUT | JPU_DEC_CAPTURE },
303*ee4a77a3SMauro Carvalho Chehab 	{ V4L2_PIX_FMT_NV16, V4L2_COLORSPACE_SRGB,
304*ee4a77a3SMauro Carvalho Chehab 	  {16, 0}, 2, 2, JPU_JPEG_422, 1, JPU_ENC_OUTPUT | JPU_DEC_CAPTURE },
305*ee4a77a3SMauro Carvalho Chehab 	{ V4L2_PIX_FMT_NV12, V4L2_COLORSPACE_SRGB,
306*ee4a77a3SMauro Carvalho Chehab 	  {12, 0}, 2, 2, JPU_JPEG_420, 1, JPU_ENC_OUTPUT | JPU_DEC_CAPTURE },
307*ee4a77a3SMauro Carvalho Chehab };
308*ee4a77a3SMauro Carvalho Chehab 
309*ee4a77a3SMauro Carvalho Chehab static const u8 zigzag[] = {
310*ee4a77a3SMauro Carvalho Chehab 	0x03, 0x02, 0x0b, 0x13, 0x0a, 0x01, 0x00, 0x09,
311*ee4a77a3SMauro Carvalho Chehab 	0x12, 0x1b, 0x23, 0x1a, 0x11, 0x08, 0x07, 0x06,
312*ee4a77a3SMauro Carvalho Chehab 	0x0f, 0x10, 0x19, 0x22, 0x2b, 0x33, 0x2a, 0x21,
313*ee4a77a3SMauro Carvalho Chehab 	0x18, 0x17, 0x0e, 0x05, 0x04, 0x0d, 0x16, 0x1f,
314*ee4a77a3SMauro Carvalho Chehab 	0x20, 0x29, 0x32, 0x3b, 0x3a, 0x31, 0x28, 0x27,
315*ee4a77a3SMauro Carvalho Chehab 	0x1e, 0x15, 0x0e, 0x14, 0x10, 0x26, 0x2f, 0x30,
316*ee4a77a3SMauro Carvalho Chehab 	0x39, 0x38, 0x37, 0x2e, 0x25, 0x1c, 0x24, 0x2b,
317*ee4a77a3SMauro Carvalho Chehab 	0x36, 0x3f, 0x3e, 0x35, 0x2c, 0x34, 0x3d, 0x3c
318*ee4a77a3SMauro Carvalho Chehab };
319*ee4a77a3SMauro Carvalho Chehab 
320*ee4a77a3SMauro Carvalho Chehab #define QTBL_SIZE (ALIGN(JPU_JPEG_QTBL_SIZE, \
321*ee4a77a3SMauro Carvalho Chehab 			  sizeof(unsigned int)) / sizeof(unsigned int))
322*ee4a77a3SMauro Carvalho Chehab #define HDCTBL_SIZE (ALIGN(JPU_JPEG_HDCTBL_SIZE, \
323*ee4a77a3SMauro Carvalho Chehab 			  sizeof(unsigned int)) / sizeof(unsigned int))
324*ee4a77a3SMauro Carvalho Chehab #define HACTBL_SIZE (ALIGN(JPU_JPEG_HACTBL_SIZE, \
325*ee4a77a3SMauro Carvalho Chehab 			  sizeof(unsigned int)) / sizeof(unsigned int))
326*ee4a77a3SMauro Carvalho Chehab /*
327*ee4a77a3SMauro Carvalho Chehab  * Start of image; Quantization tables
328*ee4a77a3SMauro Carvalho Chehab  * SOF0 (17 bytes payload) is Baseline DCT - Sample precision, height, width,
329*ee4a77a3SMauro Carvalho Chehab  * Number of image components, (Ci:8 - Hi:4 - Vi:4 - Tq:8) * 3 - Y,Cb,Cr;
330*ee4a77a3SMauro Carvalho Chehab  * Huffman tables; Padding with 0xff (33.3.27 R01UH0501EJ0100 Rev.1.00)
331*ee4a77a3SMauro Carvalho Chehab  */
332*ee4a77a3SMauro Carvalho Chehab #define JPU_JPEG_HDR_BLOB {                                                    \
333*ee4a77a3SMauro Carvalho Chehab 	0xff, SOI, 0xff, DQT, 0x00, JPU_JPEG_QTBL_SIZE + 0x3, JPU_JPEG_LUM,    \
334*ee4a77a3SMauro Carvalho Chehab 	[JPU_JPEG_QTBL_LUM_OFFSET ...                                          \
335*ee4a77a3SMauro Carvalho Chehab 		JPU_JPEG_QTBL_LUM_OFFSET + JPU_JPEG_QTBL_SIZE - 1] = 0x00,     \
336*ee4a77a3SMauro Carvalho Chehab 	0xff, DQT, 0x00, JPU_JPEG_QTBL_SIZE + 0x3, JPU_JPEG_CHR,               \
337*ee4a77a3SMauro Carvalho Chehab 	[JPU_JPEG_QTBL_CHR_OFFSET ... JPU_JPEG_QTBL_CHR_OFFSET +               \
338*ee4a77a3SMauro Carvalho Chehab 		JPU_JPEG_QTBL_SIZE - 1] = 0x00, 0xff, SOF0, 0x00, 0x11, 0x08,  \
339*ee4a77a3SMauro Carvalho Chehab 	[JPU_JPEG_HEIGHT_OFFSET ... JPU_JPEG_HEIGHT_OFFSET + 1] = 0x00,        \
340*ee4a77a3SMauro Carvalho Chehab 	[JPU_JPEG_WIDTH_OFFSET ... JPU_JPEG_WIDTH_OFFSET + 1] = 0x00,          \
341*ee4a77a3SMauro Carvalho Chehab 	0x03, 0x01, [JPU_JPEG_SUBS_OFFSET] = 0x00, JPU_JPEG_LUM,               \
342*ee4a77a3SMauro Carvalho Chehab 	0x02, 0x11, JPU_JPEG_CHR, 0x03, 0x11, JPU_JPEG_CHR,                    \
343*ee4a77a3SMauro Carvalho Chehab 	0xff, DHT, 0x00, JPU_JPEG_HDCTBL_SIZE + 0x3, JPU_JPEG_LUM|JPU_JPEG_DC, \
344*ee4a77a3SMauro Carvalho Chehab 	[JPU_JPEG_HDCTBL_LUM_OFFSET ...                                        \
345*ee4a77a3SMauro Carvalho Chehab 		JPU_JPEG_HDCTBL_LUM_OFFSET + JPU_JPEG_HDCTBL_SIZE - 1] = 0x00, \
346*ee4a77a3SMauro Carvalho Chehab 	0xff, DHT, 0x00, JPU_JPEG_HACTBL_SIZE + 0x3, JPU_JPEG_LUM|JPU_JPEG_AC, \
347*ee4a77a3SMauro Carvalho Chehab 	[JPU_JPEG_HACTBL_LUM_OFFSET ...                                        \
348*ee4a77a3SMauro Carvalho Chehab 		JPU_JPEG_HACTBL_LUM_OFFSET + JPU_JPEG_HACTBL_SIZE - 1] = 0x00, \
349*ee4a77a3SMauro Carvalho Chehab 	0xff, DHT, 0x00, JPU_JPEG_HDCTBL_SIZE + 0x3, JPU_JPEG_CHR|JPU_JPEG_DC, \
350*ee4a77a3SMauro Carvalho Chehab 	[JPU_JPEG_HDCTBL_CHR_OFFSET ...                                        \
351*ee4a77a3SMauro Carvalho Chehab 		JPU_JPEG_HDCTBL_CHR_OFFSET + JPU_JPEG_HDCTBL_SIZE - 1] = 0x00, \
352*ee4a77a3SMauro Carvalho Chehab 	0xff, DHT, 0x00, JPU_JPEG_HACTBL_SIZE + 0x3, JPU_JPEG_CHR|JPU_JPEG_AC, \
353*ee4a77a3SMauro Carvalho Chehab 	[JPU_JPEG_HACTBL_CHR_OFFSET ...                                        \
354*ee4a77a3SMauro Carvalho Chehab 		JPU_JPEG_HACTBL_CHR_OFFSET + JPU_JPEG_HACTBL_SIZE - 1] = 0x00, \
355*ee4a77a3SMauro Carvalho Chehab 	[JPU_JPEG_PADDING_OFFSET ... JPU_JPEG_HDR_SIZE - 1] = 0xff             \
356*ee4a77a3SMauro Carvalho Chehab }
357*ee4a77a3SMauro Carvalho Chehab 
358*ee4a77a3SMauro Carvalho Chehab static unsigned char jpeg_hdrs[JPU_MAX_QUALITY][JPU_JPEG_HDR_SIZE] = {
359*ee4a77a3SMauro Carvalho Chehab 	[0 ... JPU_MAX_QUALITY - 1] = JPU_JPEG_HDR_BLOB
360*ee4a77a3SMauro Carvalho Chehab };
361*ee4a77a3SMauro Carvalho Chehab 
362*ee4a77a3SMauro Carvalho Chehab static const unsigned int qtbl_lum[JPU_MAX_QUALITY][QTBL_SIZE] = {
363*ee4a77a3SMauro Carvalho Chehab 	{
364*ee4a77a3SMauro Carvalho Chehab 		0x14101927, 0x322e3e44, 0x10121726, 0x26354144,
365*ee4a77a3SMauro Carvalho Chehab 		0x19171f26, 0x35414444, 0x27262635, 0x41444444,
366*ee4a77a3SMauro Carvalho Chehab 		0x32263541, 0x44444444, 0x2e354144, 0x44444444,
367*ee4a77a3SMauro Carvalho Chehab 		0x3e414444, 0x44444444, 0x44444444, 0x44444444
368*ee4a77a3SMauro Carvalho Chehab 	},
369*ee4a77a3SMauro Carvalho Chehab 	{
370*ee4a77a3SMauro Carvalho Chehab 		0x100b0b10, 0x171b1f1e, 0x0b0c0c0f, 0x1417171e,
371*ee4a77a3SMauro Carvalho Chehab 		0x0b0c0d10, 0x171a232f, 0x100f1017, 0x1a252f40,
372*ee4a77a3SMauro Carvalho Chehab 		0x1714171a, 0x27334040, 0x1b171a25, 0x33404040,
373*ee4a77a3SMauro Carvalho Chehab 		0x1f17232f, 0x40404040, 0x1e1e2f40, 0x40404040
374*ee4a77a3SMauro Carvalho Chehab 	},
375*ee4a77a3SMauro Carvalho Chehab 	{
376*ee4a77a3SMauro Carvalho Chehab 		0x0c08080c, 0x11151817, 0x0809090b, 0x0f131217,
377*ee4a77a3SMauro Carvalho Chehab 		0x08090a0c, 0x13141b24, 0x0c0b0c15, 0x141c2435,
378*ee4a77a3SMauro Carvalho Chehab 		0x110f1314, 0x1e27333b, 0x1513141c, 0x27333b3b,
379*ee4a77a3SMauro Carvalho Chehab 		0x18121b24, 0x333b3b3b, 0x17172435, 0x3b3b3b3b
380*ee4a77a3SMauro Carvalho Chehab 	},
381*ee4a77a3SMauro Carvalho Chehab 	{
382*ee4a77a3SMauro Carvalho Chehab 		0x08060608, 0x0c0e1011, 0x06060608, 0x0a0d0c0f,
383*ee4a77a3SMauro Carvalho Chehab 		0x06060708, 0x0d0e1218, 0x0808080e, 0x0d131823,
384*ee4a77a3SMauro Carvalho Chehab 		0x0c0a0d0d, 0x141a2227, 0x0e0d0e13, 0x1a222727,
385*ee4a77a3SMauro Carvalho Chehab 		0x100c1318, 0x22272727, 0x110f1823, 0x27272727
386*ee4a77a3SMauro Carvalho Chehab 	}
387*ee4a77a3SMauro Carvalho Chehab };
388*ee4a77a3SMauro Carvalho Chehab 
389*ee4a77a3SMauro Carvalho Chehab static const unsigned int qtbl_chr[JPU_MAX_QUALITY][QTBL_SIZE] = {
390*ee4a77a3SMauro Carvalho Chehab 	{
391*ee4a77a3SMauro Carvalho Chehab 		0x15192026, 0x36444444, 0x191c1826, 0x36444444,
392*ee4a77a3SMauro Carvalho Chehab 		0x2018202b, 0x42444444, 0x26262b35, 0x44444444,
393*ee4a77a3SMauro Carvalho Chehab 		0x36424444, 0x44444444, 0x44444444, 0x44444444,
394*ee4a77a3SMauro Carvalho Chehab 		0x44444444, 0x44444444, 0x44444444, 0x44444444
395*ee4a77a3SMauro Carvalho Chehab 	},
396*ee4a77a3SMauro Carvalho Chehab 	{
397*ee4a77a3SMauro Carvalho Chehab 		0x110f1115, 0x141a2630, 0x0f131211, 0x141a232b,
398*ee4a77a3SMauro Carvalho Chehab 		0x11121416, 0x1a1e2e35, 0x1511161c, 0x1e273540,
399*ee4a77a3SMauro Carvalho Chehab 		0x14141a1e, 0x27304040, 0x1a1a1e27, 0x303f4040,
400*ee4a77a3SMauro Carvalho Chehab 		0x26232e35, 0x40404040, 0x302b3540, 0x40404040
401*ee4a77a3SMauro Carvalho Chehab 	},
402*ee4a77a3SMauro Carvalho Chehab 	{
403*ee4a77a3SMauro Carvalho Chehab 		0x0d0b0d10, 0x14141d25, 0x0b0e0e0e, 0x10141a20,
404*ee4a77a3SMauro Carvalho Chehab 		0x0d0e0f11, 0x14172328, 0x100e1115, 0x171e2832,
405*ee4a77a3SMauro Carvalho Chehab 		0x14101417, 0x1e25323b, 0x1414171e, 0x25303b3b,
406*ee4a77a3SMauro Carvalho Chehab 		0x1d1a2328, 0x323b3b3b, 0x25202832, 0x3b3b3b3b
407*ee4a77a3SMauro Carvalho Chehab 	},
408*ee4a77a3SMauro Carvalho Chehab 	{
409*ee4a77a3SMauro Carvalho Chehab 		0x0908090b, 0x0e111318, 0x080a090b, 0x0e0d1116,
410*ee4a77a3SMauro Carvalho Chehab 		0x09090d0e, 0x0d0f171a, 0x0b0b0e0e, 0x0f141a21,
411*ee4a77a3SMauro Carvalho Chehab 		0x0e0e0d0f, 0x14182127, 0x110d0f14, 0x18202727,
412*ee4a77a3SMauro Carvalho Chehab 		0x1311171a, 0x21272727, 0x18161a21, 0x27272727
413*ee4a77a3SMauro Carvalho Chehab 	}
414*ee4a77a3SMauro Carvalho Chehab };
415*ee4a77a3SMauro Carvalho Chehab 
416*ee4a77a3SMauro Carvalho Chehab static const unsigned int hdctbl_lum[HDCTBL_SIZE] = {
417*ee4a77a3SMauro Carvalho Chehab 	0x00010501, 0x01010101, 0x01000000, 0x00000000,
418*ee4a77a3SMauro Carvalho Chehab 	0x00010203, 0x04050607, 0x08090a0b
419*ee4a77a3SMauro Carvalho Chehab };
420*ee4a77a3SMauro Carvalho Chehab 
421*ee4a77a3SMauro Carvalho Chehab static const unsigned int hdctbl_chr[HDCTBL_SIZE] = {
422*ee4a77a3SMauro Carvalho Chehab 	0x00010501, 0x01010101, 0x01000000, 0x00000000,
423*ee4a77a3SMauro Carvalho Chehab 	0x00010203, 0x04050607, 0x08090a0b
424*ee4a77a3SMauro Carvalho Chehab };
425*ee4a77a3SMauro Carvalho Chehab 
426*ee4a77a3SMauro Carvalho Chehab static const unsigned int hactbl_lum[HACTBL_SIZE] = {
427*ee4a77a3SMauro Carvalho Chehab 	0x00020103, 0x03020403, 0x05050404, 0x0000017d, 0x01020300, 0x04110512,
428*ee4a77a3SMauro Carvalho Chehab 	0x21314106, 0x13516107,	0x22711432, 0x8191a108, 0x2342b1c1, 0x1552d1f0,
429*ee4a77a3SMauro Carvalho Chehab 	0x24336272, 0x82090a16, 0x1718191a, 0x25262728, 0x292a3435, 0x36373839,
430*ee4a77a3SMauro Carvalho Chehab 	0x3a434445, 0x46474849, 0x4a535455, 0x56575859, 0x5a636465, 0x66676869,
431*ee4a77a3SMauro Carvalho Chehab 	0x6a737475, 0x76777879, 0x7a838485, 0x86878889, 0x8a929394, 0x95969798,
432*ee4a77a3SMauro Carvalho Chehab 	0x999aa2a3, 0xa4a5a6a7, 0xa8a9aab2, 0xb3b4b5b6, 0xb7b8b9ba, 0xc2c3c4c5,
433*ee4a77a3SMauro Carvalho Chehab 	0xc6c7c8c9, 0xcad2d3d4, 0xd5d6d7d8, 0xd9dae1e2, 0xe3e4e5e6, 0xe7e8e9ea,
434*ee4a77a3SMauro Carvalho Chehab 	0xf1f2f3f4, 0xf5f6f7f8, 0xf9fa0000
435*ee4a77a3SMauro Carvalho Chehab };
436*ee4a77a3SMauro Carvalho Chehab 
437*ee4a77a3SMauro Carvalho Chehab static const unsigned int hactbl_chr[HACTBL_SIZE] = {
438*ee4a77a3SMauro Carvalho Chehab 	0x00020103, 0x03020403, 0x05050404, 0x0000017d, 0x01020300, 0x04110512,
439*ee4a77a3SMauro Carvalho Chehab 	0x21314106, 0x13516107,	0x22711432, 0x8191a108, 0x2342b1c1, 0x1552d1f0,
440*ee4a77a3SMauro Carvalho Chehab 	0x24336272, 0x82090a16, 0x1718191a, 0x25262728, 0x292a3435, 0x36373839,
441*ee4a77a3SMauro Carvalho Chehab 	0x3a434445, 0x46474849, 0x4a535455, 0x56575859, 0x5a636465, 0x66676869,
442*ee4a77a3SMauro Carvalho Chehab 	0x6a737475, 0x76777879, 0x7a838485, 0x86878889, 0x8a929394, 0x95969798,
443*ee4a77a3SMauro Carvalho Chehab 	0x999aa2a3, 0xa4a5a6a7, 0xa8a9aab2, 0xb3b4b5b6, 0xb7b8b9ba, 0xc2c3c4c5,
444*ee4a77a3SMauro Carvalho Chehab 	0xc6c7c8c9, 0xcad2d3d4, 0xd5d6d7d8, 0xd9dae1e2, 0xe3e4e5e6, 0xe7e8e9ea,
445*ee4a77a3SMauro Carvalho Chehab 	0xf1f2f3f4, 0xf5f6f7f8, 0xf9fa0000
446*ee4a77a3SMauro Carvalho Chehab };
447*ee4a77a3SMauro Carvalho Chehab 
448*ee4a77a3SMauro Carvalho Chehab static const char *error_to_text[16] = {
449*ee4a77a3SMauro Carvalho Chehab 	"Normal",
450*ee4a77a3SMauro Carvalho Chehab 	"SOI not detected",
451*ee4a77a3SMauro Carvalho Chehab 	"SOF1 to SOFF detected",
452*ee4a77a3SMauro Carvalho Chehab 	"Subsampling not detected",
453*ee4a77a3SMauro Carvalho Chehab 	"SOF accuracy error",
454*ee4a77a3SMauro Carvalho Chehab 	"DQT accuracy error",
455*ee4a77a3SMauro Carvalho Chehab 	"Component error 1",
456*ee4a77a3SMauro Carvalho Chehab 	"Component error 2",
457*ee4a77a3SMauro Carvalho Chehab 	"SOF0, DQT, and DHT not detected when SOS detected",
458*ee4a77a3SMauro Carvalho Chehab 	"SOS not detected",
459*ee4a77a3SMauro Carvalho Chehab 	"EOI not detected",
460*ee4a77a3SMauro Carvalho Chehab 	"Restart interval data number error detected",
461*ee4a77a3SMauro Carvalho Chehab 	"Image size error",
462*ee4a77a3SMauro Carvalho Chehab 	"Last MCU data number error",
463*ee4a77a3SMauro Carvalho Chehab 	"Block data number error",
464*ee4a77a3SMauro Carvalho Chehab 	"Unknown"
465*ee4a77a3SMauro Carvalho Chehab };
466*ee4a77a3SMauro Carvalho Chehab 
467*ee4a77a3SMauro Carvalho Chehab static struct jpu_buffer *vb2_to_jpu_buffer(struct vb2_v4l2_buffer *vb)
468*ee4a77a3SMauro Carvalho Chehab {
469*ee4a77a3SMauro Carvalho Chehab 	struct v4l2_m2m_buffer *b =
470*ee4a77a3SMauro Carvalho Chehab 		container_of(vb, struct v4l2_m2m_buffer, vb);
471*ee4a77a3SMauro Carvalho Chehab 
472*ee4a77a3SMauro Carvalho Chehab 	return container_of(b, struct jpu_buffer, buf);
473*ee4a77a3SMauro Carvalho Chehab }
474*ee4a77a3SMauro Carvalho Chehab 
475*ee4a77a3SMauro Carvalho Chehab static u32 jpu_read(struct jpu *jpu, unsigned int reg)
476*ee4a77a3SMauro Carvalho Chehab {
477*ee4a77a3SMauro Carvalho Chehab 	return ioread32(jpu->regs + reg);
478*ee4a77a3SMauro Carvalho Chehab }
479*ee4a77a3SMauro Carvalho Chehab 
480*ee4a77a3SMauro Carvalho Chehab static void jpu_write(struct jpu *jpu, u32 val, unsigned int reg)
481*ee4a77a3SMauro Carvalho Chehab {
482*ee4a77a3SMauro Carvalho Chehab 	iowrite32(val, jpu->regs + reg);
483*ee4a77a3SMauro Carvalho Chehab }
484*ee4a77a3SMauro Carvalho Chehab 
485*ee4a77a3SMauro Carvalho Chehab static struct jpu_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
486*ee4a77a3SMauro Carvalho Chehab {
487*ee4a77a3SMauro Carvalho Chehab 	return container_of(c->handler, struct jpu_ctx, ctrl_handler);
488*ee4a77a3SMauro Carvalho Chehab }
489*ee4a77a3SMauro Carvalho Chehab 
490*ee4a77a3SMauro Carvalho Chehab static struct jpu_ctx *fh_to_ctx(struct v4l2_fh *fh)
491*ee4a77a3SMauro Carvalho Chehab {
492*ee4a77a3SMauro Carvalho Chehab 	return container_of(fh, struct jpu_ctx, fh);
493*ee4a77a3SMauro Carvalho Chehab }
494*ee4a77a3SMauro Carvalho Chehab 
495*ee4a77a3SMauro Carvalho Chehab static void jpu_set_tbl(struct jpu *jpu, u32 reg, const unsigned int *tbl,
496*ee4a77a3SMauro Carvalho Chehab 			unsigned int len) {
497*ee4a77a3SMauro Carvalho Chehab 	unsigned int i;
498*ee4a77a3SMauro Carvalho Chehab 
499*ee4a77a3SMauro Carvalho Chehab 	for (i = 0; i < len; i++)
500*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, tbl[i], reg + (i << 2));
501*ee4a77a3SMauro Carvalho Chehab }
502*ee4a77a3SMauro Carvalho Chehab 
503*ee4a77a3SMauro Carvalho Chehab static void jpu_set_qtbl(struct jpu *jpu, unsigned short quality)
504*ee4a77a3SMauro Carvalho Chehab {
505*ee4a77a3SMauro Carvalho Chehab 	jpu_set_tbl(jpu, JCQTBL(0), qtbl_lum[quality], QTBL_SIZE);
506*ee4a77a3SMauro Carvalho Chehab 	jpu_set_tbl(jpu, JCQTBL(1), qtbl_chr[quality], QTBL_SIZE);
507*ee4a77a3SMauro Carvalho Chehab }
508*ee4a77a3SMauro Carvalho Chehab 
509*ee4a77a3SMauro Carvalho Chehab static void jpu_set_htbl(struct jpu *jpu)
510*ee4a77a3SMauro Carvalho Chehab {
511*ee4a77a3SMauro Carvalho Chehab 	jpu_set_tbl(jpu, JCHTBD(0), hdctbl_lum, HDCTBL_SIZE);
512*ee4a77a3SMauro Carvalho Chehab 	jpu_set_tbl(jpu, JCHTBA(0), hactbl_lum, HACTBL_SIZE);
513*ee4a77a3SMauro Carvalho Chehab 	jpu_set_tbl(jpu, JCHTBD(1), hdctbl_chr, HDCTBL_SIZE);
514*ee4a77a3SMauro Carvalho Chehab 	jpu_set_tbl(jpu, JCHTBA(1), hactbl_chr, HACTBL_SIZE);
515*ee4a77a3SMauro Carvalho Chehab }
516*ee4a77a3SMauro Carvalho Chehab 
517*ee4a77a3SMauro Carvalho Chehab static int jpu_wait_reset(struct jpu *jpu)
518*ee4a77a3SMauro Carvalho Chehab {
519*ee4a77a3SMauro Carvalho Chehab 	unsigned long timeout;
520*ee4a77a3SMauro Carvalho Chehab 
521*ee4a77a3SMauro Carvalho Chehab 	timeout = jiffies + msecs_to_jiffies(JPU_RESET_TIMEOUT);
522*ee4a77a3SMauro Carvalho Chehab 
523*ee4a77a3SMauro Carvalho Chehab 	while (jpu_read(jpu, JCCMD) & JCCMD_SRST) {
524*ee4a77a3SMauro Carvalho Chehab 		if (time_after(jiffies, timeout)) {
525*ee4a77a3SMauro Carvalho Chehab 			dev_err(jpu->dev, "timed out in reset\n");
526*ee4a77a3SMauro Carvalho Chehab 			return -ETIMEDOUT;
527*ee4a77a3SMauro Carvalho Chehab 		}
528*ee4a77a3SMauro Carvalho Chehab 		schedule();
529*ee4a77a3SMauro Carvalho Chehab 	}
530*ee4a77a3SMauro Carvalho Chehab 
531*ee4a77a3SMauro Carvalho Chehab 	return 0;
532*ee4a77a3SMauro Carvalho Chehab }
533*ee4a77a3SMauro Carvalho Chehab 
534*ee4a77a3SMauro Carvalho Chehab static int jpu_reset(struct jpu *jpu)
535*ee4a77a3SMauro Carvalho Chehab {
536*ee4a77a3SMauro Carvalho Chehab 	jpu_write(jpu, JCCMD_SRST, JCCMD);
537*ee4a77a3SMauro Carvalho Chehab 	return jpu_wait_reset(jpu);
538*ee4a77a3SMauro Carvalho Chehab }
539*ee4a77a3SMauro Carvalho Chehab 
540*ee4a77a3SMauro Carvalho Chehab /*
541*ee4a77a3SMauro Carvalho Chehab  * ============================================================================
542*ee4a77a3SMauro Carvalho Chehab  * video ioctl operations
543*ee4a77a3SMauro Carvalho Chehab  * ============================================================================
544*ee4a77a3SMauro Carvalho Chehab  */
545*ee4a77a3SMauro Carvalho Chehab static void put_qtbl(u8 *p, const u8 *qtbl)
546*ee4a77a3SMauro Carvalho Chehab {
547*ee4a77a3SMauro Carvalho Chehab 	unsigned int i;
548*ee4a77a3SMauro Carvalho Chehab 
549*ee4a77a3SMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(zigzag); i++)
550*ee4a77a3SMauro Carvalho Chehab 		p[i] = *(qtbl + zigzag[i]);
551*ee4a77a3SMauro Carvalho Chehab }
552*ee4a77a3SMauro Carvalho Chehab 
553*ee4a77a3SMauro Carvalho Chehab static void put_htbl(u8 *p, const u8 *htbl, unsigned int len)
554*ee4a77a3SMauro Carvalho Chehab {
555*ee4a77a3SMauro Carvalho Chehab 	unsigned int i, j;
556*ee4a77a3SMauro Carvalho Chehab 
557*ee4a77a3SMauro Carvalho Chehab 	for (i = 0; i < len; i += 4)
558*ee4a77a3SMauro Carvalho Chehab 		for (j = 0; j < 4 && (i + j) < len; ++j)
559*ee4a77a3SMauro Carvalho Chehab 			p[i + j] = htbl[i + 3 - j];
560*ee4a77a3SMauro Carvalho Chehab }
561*ee4a77a3SMauro Carvalho Chehab 
562*ee4a77a3SMauro Carvalho Chehab static void jpu_generate_hdr(unsigned short quality, unsigned char *p)
563*ee4a77a3SMauro Carvalho Chehab {
564*ee4a77a3SMauro Carvalho Chehab 	put_qtbl(p + JPU_JPEG_QTBL_LUM_OFFSET, (const u8 *)qtbl_lum[quality]);
565*ee4a77a3SMauro Carvalho Chehab 	put_qtbl(p + JPU_JPEG_QTBL_CHR_OFFSET, (const u8 *)qtbl_chr[quality]);
566*ee4a77a3SMauro Carvalho Chehab 
567*ee4a77a3SMauro Carvalho Chehab 	put_htbl(p + JPU_JPEG_HDCTBL_LUM_OFFSET, (const u8 *)hdctbl_lum,
568*ee4a77a3SMauro Carvalho Chehab 		 JPU_JPEG_HDCTBL_SIZE);
569*ee4a77a3SMauro Carvalho Chehab 	put_htbl(p + JPU_JPEG_HACTBL_LUM_OFFSET, (const u8 *)hactbl_lum,
570*ee4a77a3SMauro Carvalho Chehab 		 JPU_JPEG_HACTBL_SIZE);
571*ee4a77a3SMauro Carvalho Chehab 
572*ee4a77a3SMauro Carvalho Chehab 	put_htbl(p + JPU_JPEG_HDCTBL_CHR_OFFSET, (const u8 *)hdctbl_chr,
573*ee4a77a3SMauro Carvalho Chehab 		 JPU_JPEG_HDCTBL_SIZE);
574*ee4a77a3SMauro Carvalho Chehab 	put_htbl(p + JPU_JPEG_HACTBL_CHR_OFFSET, (const u8 *)hactbl_chr,
575*ee4a77a3SMauro Carvalho Chehab 		 JPU_JPEG_HACTBL_SIZE);
576*ee4a77a3SMauro Carvalho Chehab }
577*ee4a77a3SMauro Carvalho Chehab 
578*ee4a77a3SMauro Carvalho Chehab static int get_byte(struct jpeg_buffer *buf)
579*ee4a77a3SMauro Carvalho Chehab {
580*ee4a77a3SMauro Carvalho Chehab 	if (buf->curr >= buf->end)
581*ee4a77a3SMauro Carvalho Chehab 		return -1;
582*ee4a77a3SMauro Carvalho Chehab 
583*ee4a77a3SMauro Carvalho Chehab 	return *(u8 *)buf->curr++;
584*ee4a77a3SMauro Carvalho Chehab }
585*ee4a77a3SMauro Carvalho Chehab 
586*ee4a77a3SMauro Carvalho Chehab static int get_word_be(struct jpeg_buffer *buf, unsigned int *word)
587*ee4a77a3SMauro Carvalho Chehab {
588*ee4a77a3SMauro Carvalho Chehab 	if (buf->end - buf->curr < 2)
589*ee4a77a3SMauro Carvalho Chehab 		return -1;
590*ee4a77a3SMauro Carvalho Chehab 
591*ee4a77a3SMauro Carvalho Chehab 	*word = get_unaligned_be16(buf->curr);
592*ee4a77a3SMauro Carvalho Chehab 	buf->curr += 2;
593*ee4a77a3SMauro Carvalho Chehab 
594*ee4a77a3SMauro Carvalho Chehab 	return 0;
595*ee4a77a3SMauro Carvalho Chehab }
596*ee4a77a3SMauro Carvalho Chehab 
597*ee4a77a3SMauro Carvalho Chehab static void skip(struct jpeg_buffer *buf, unsigned long len)
598*ee4a77a3SMauro Carvalho Chehab {
599*ee4a77a3SMauro Carvalho Chehab 	buf->curr += min((unsigned long)(buf->end - buf->curr), len);
600*ee4a77a3SMauro Carvalho Chehab }
601*ee4a77a3SMauro Carvalho Chehab 
602*ee4a77a3SMauro Carvalho Chehab static u8 jpu_parse_hdr(void *buffer, unsigned long size, unsigned int *width,
603*ee4a77a3SMauro Carvalho Chehab 			  unsigned int *height)
604*ee4a77a3SMauro Carvalho Chehab {
605*ee4a77a3SMauro Carvalho Chehab 	struct jpeg_buffer jpeg_buffer;
606*ee4a77a3SMauro Carvalho Chehab 	unsigned int word;
607*ee4a77a3SMauro Carvalho Chehab 	bool soi = false;
608*ee4a77a3SMauro Carvalho Chehab 
609*ee4a77a3SMauro Carvalho Chehab 	jpeg_buffer.end = buffer + size;
610*ee4a77a3SMauro Carvalho Chehab 	jpeg_buffer.curr = buffer;
611*ee4a77a3SMauro Carvalho Chehab 
612*ee4a77a3SMauro Carvalho Chehab 	/*
613*ee4a77a3SMauro Carvalho Chehab 	 * basic size check and EOI - we don't want to let JPU cross
614*ee4a77a3SMauro Carvalho Chehab 	 * buffer bounds in any case. Hope it's stopping by EOI.
615*ee4a77a3SMauro Carvalho Chehab 	 */
616*ee4a77a3SMauro Carvalho Chehab 	if (size < JPU_JPEG_MIN_SIZE || *(u8 *)(buffer + size - 1) != EOI)
617*ee4a77a3SMauro Carvalho Chehab 		return 0;
618*ee4a77a3SMauro Carvalho Chehab 
619*ee4a77a3SMauro Carvalho Chehab 	for (;;) {
620*ee4a77a3SMauro Carvalho Chehab 		int c;
621*ee4a77a3SMauro Carvalho Chehab 
622*ee4a77a3SMauro Carvalho Chehab 		/* skip preceding filler bytes */
623*ee4a77a3SMauro Carvalho Chehab 		do
624*ee4a77a3SMauro Carvalho Chehab 			c = get_byte(&jpeg_buffer);
625*ee4a77a3SMauro Carvalho Chehab 		while (c == 0xff || c == 0);
626*ee4a77a3SMauro Carvalho Chehab 
627*ee4a77a3SMauro Carvalho Chehab 		if (!soi && c == SOI) {
628*ee4a77a3SMauro Carvalho Chehab 			soi = true;
629*ee4a77a3SMauro Carvalho Chehab 			continue;
630*ee4a77a3SMauro Carvalho Chehab 		} else if (soi != (c != SOI))
631*ee4a77a3SMauro Carvalho Chehab 			return 0;
632*ee4a77a3SMauro Carvalho Chehab 
633*ee4a77a3SMauro Carvalho Chehab 		switch (c) {
634*ee4a77a3SMauro Carvalho Chehab 		case SOF0: /* SOF0: baseline JPEG */
635*ee4a77a3SMauro Carvalho Chehab 			skip(&jpeg_buffer, 3); /* segment length and bpp */
636*ee4a77a3SMauro Carvalho Chehab 			if (get_word_be(&jpeg_buffer, height) ||
637*ee4a77a3SMauro Carvalho Chehab 			    get_word_be(&jpeg_buffer, width) ||
638*ee4a77a3SMauro Carvalho Chehab 			    get_byte(&jpeg_buffer) != 3) /* YCbCr only */
639*ee4a77a3SMauro Carvalho Chehab 				return 0;
640*ee4a77a3SMauro Carvalho Chehab 
641*ee4a77a3SMauro Carvalho Chehab 			skip(&jpeg_buffer, 1);
642*ee4a77a3SMauro Carvalho Chehab 			return get_byte(&jpeg_buffer);
643*ee4a77a3SMauro Carvalho Chehab 		case DHT:
644*ee4a77a3SMauro Carvalho Chehab 		case DQT:
645*ee4a77a3SMauro Carvalho Chehab 		case COM:
646*ee4a77a3SMauro Carvalho Chehab 		case DRI:
647*ee4a77a3SMauro Carvalho Chehab 		case APP0 ... APP0 + 0x0f:
648*ee4a77a3SMauro Carvalho Chehab 			if (get_word_be(&jpeg_buffer, &word))
649*ee4a77a3SMauro Carvalho Chehab 				return 0;
650*ee4a77a3SMauro Carvalho Chehab 			skip(&jpeg_buffer, (long)word - 2);
651*ee4a77a3SMauro Carvalho Chehab 			break;
652*ee4a77a3SMauro Carvalho Chehab 		case 0:
653*ee4a77a3SMauro Carvalho Chehab 			break;
654*ee4a77a3SMauro Carvalho Chehab 		default:
655*ee4a77a3SMauro Carvalho Chehab 			return 0;
656*ee4a77a3SMauro Carvalho Chehab 		}
657*ee4a77a3SMauro Carvalho Chehab 	}
658*ee4a77a3SMauro Carvalho Chehab 
659*ee4a77a3SMauro Carvalho Chehab 	return 0;
660*ee4a77a3SMauro Carvalho Chehab }
661*ee4a77a3SMauro Carvalho Chehab 
662*ee4a77a3SMauro Carvalho Chehab static int jpu_querycap(struct file *file, void *priv,
663*ee4a77a3SMauro Carvalho Chehab 			struct v4l2_capability *cap)
664*ee4a77a3SMauro Carvalho Chehab {
665*ee4a77a3SMauro Carvalho Chehab 	struct jpu_ctx *ctx = fh_to_ctx(priv);
666*ee4a77a3SMauro Carvalho Chehab 
667*ee4a77a3SMauro Carvalho Chehab 	if (ctx->encoder)
668*ee4a77a3SMauro Carvalho Chehab 		strscpy(cap->card, DRV_NAME " encoder", sizeof(cap->card));
669*ee4a77a3SMauro Carvalho Chehab 	else
670*ee4a77a3SMauro Carvalho Chehab 		strscpy(cap->card, DRV_NAME " decoder", sizeof(cap->card));
671*ee4a77a3SMauro Carvalho Chehab 
672*ee4a77a3SMauro Carvalho Chehab 	strscpy(cap->driver, DRV_NAME, sizeof(cap->driver));
673*ee4a77a3SMauro Carvalho Chehab 	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
674*ee4a77a3SMauro Carvalho Chehab 		 dev_name(ctx->jpu->dev));
675*ee4a77a3SMauro Carvalho Chehab 	memset(cap->reserved, 0, sizeof(cap->reserved));
676*ee4a77a3SMauro Carvalho Chehab 
677*ee4a77a3SMauro Carvalho Chehab 	return 0;
678*ee4a77a3SMauro Carvalho Chehab }
679*ee4a77a3SMauro Carvalho Chehab 
680*ee4a77a3SMauro Carvalho Chehab static struct jpu_fmt *jpu_find_format(bool encoder, u32 pixelformat,
681*ee4a77a3SMauro Carvalho Chehab 				       unsigned int fmt_type)
682*ee4a77a3SMauro Carvalho Chehab {
683*ee4a77a3SMauro Carvalho Chehab 	unsigned int i, fmt_flag;
684*ee4a77a3SMauro Carvalho Chehab 
685*ee4a77a3SMauro Carvalho Chehab 	if (encoder)
686*ee4a77a3SMauro Carvalho Chehab 		fmt_flag = fmt_type == JPU_FMT_TYPE_OUTPUT ? JPU_ENC_OUTPUT :
687*ee4a77a3SMauro Carvalho Chehab 							     JPU_ENC_CAPTURE;
688*ee4a77a3SMauro Carvalho Chehab 	else
689*ee4a77a3SMauro Carvalho Chehab 		fmt_flag = fmt_type == JPU_FMT_TYPE_OUTPUT ? JPU_DEC_OUTPUT :
690*ee4a77a3SMauro Carvalho Chehab 							     JPU_DEC_CAPTURE;
691*ee4a77a3SMauro Carvalho Chehab 
692*ee4a77a3SMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(jpu_formats); i++) {
693*ee4a77a3SMauro Carvalho Chehab 		struct jpu_fmt *fmt = &jpu_formats[i];
694*ee4a77a3SMauro Carvalho Chehab 
695*ee4a77a3SMauro Carvalho Chehab 		if (fmt->fourcc == pixelformat && fmt->types & fmt_flag)
696*ee4a77a3SMauro Carvalho Chehab 			return fmt;
697*ee4a77a3SMauro Carvalho Chehab 	}
698*ee4a77a3SMauro Carvalho Chehab 
699*ee4a77a3SMauro Carvalho Chehab 	return NULL;
700*ee4a77a3SMauro Carvalho Chehab }
701*ee4a77a3SMauro Carvalho Chehab 
702*ee4a77a3SMauro Carvalho Chehab static int jpu_enum_fmt(struct v4l2_fmtdesc *f, u32 type)
703*ee4a77a3SMauro Carvalho Chehab {
704*ee4a77a3SMauro Carvalho Chehab 	unsigned int i, num = 0;
705*ee4a77a3SMauro Carvalho Chehab 
706*ee4a77a3SMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(jpu_formats); ++i) {
707*ee4a77a3SMauro Carvalho Chehab 		if (jpu_formats[i].types & type) {
708*ee4a77a3SMauro Carvalho Chehab 			if (num == f->index)
709*ee4a77a3SMauro Carvalho Chehab 				break;
710*ee4a77a3SMauro Carvalho Chehab 			++num;
711*ee4a77a3SMauro Carvalho Chehab 		}
712*ee4a77a3SMauro Carvalho Chehab 	}
713*ee4a77a3SMauro Carvalho Chehab 
714*ee4a77a3SMauro Carvalho Chehab 	if (i >= ARRAY_SIZE(jpu_formats))
715*ee4a77a3SMauro Carvalho Chehab 		return -EINVAL;
716*ee4a77a3SMauro Carvalho Chehab 
717*ee4a77a3SMauro Carvalho Chehab 	f->pixelformat = jpu_formats[i].fourcc;
718*ee4a77a3SMauro Carvalho Chehab 
719*ee4a77a3SMauro Carvalho Chehab 	return 0;
720*ee4a77a3SMauro Carvalho Chehab }
721*ee4a77a3SMauro Carvalho Chehab 
722*ee4a77a3SMauro Carvalho Chehab static int jpu_enum_fmt_cap(struct file *file, void *priv,
723*ee4a77a3SMauro Carvalho Chehab 			    struct v4l2_fmtdesc *f)
724*ee4a77a3SMauro Carvalho Chehab {
725*ee4a77a3SMauro Carvalho Chehab 	struct jpu_ctx *ctx = fh_to_ctx(priv);
726*ee4a77a3SMauro Carvalho Chehab 
727*ee4a77a3SMauro Carvalho Chehab 	return jpu_enum_fmt(f, ctx->encoder ? JPU_ENC_CAPTURE :
728*ee4a77a3SMauro Carvalho Chehab 			    JPU_DEC_CAPTURE);
729*ee4a77a3SMauro Carvalho Chehab }
730*ee4a77a3SMauro Carvalho Chehab 
731*ee4a77a3SMauro Carvalho Chehab static int jpu_enum_fmt_out(struct file *file, void *priv,
732*ee4a77a3SMauro Carvalho Chehab 			    struct v4l2_fmtdesc *f)
733*ee4a77a3SMauro Carvalho Chehab {
734*ee4a77a3SMauro Carvalho Chehab 	struct jpu_ctx *ctx = fh_to_ctx(priv);
735*ee4a77a3SMauro Carvalho Chehab 
736*ee4a77a3SMauro Carvalho Chehab 	return jpu_enum_fmt(f, ctx->encoder ? JPU_ENC_OUTPUT : JPU_DEC_OUTPUT);
737*ee4a77a3SMauro Carvalho Chehab }
738*ee4a77a3SMauro Carvalho Chehab 
739*ee4a77a3SMauro Carvalho Chehab static struct jpu_q_data *jpu_get_q_data(struct jpu_ctx *ctx,
740*ee4a77a3SMauro Carvalho Chehab 					 enum v4l2_buf_type type)
741*ee4a77a3SMauro Carvalho Chehab {
742*ee4a77a3SMauro Carvalho Chehab 	if (V4L2_TYPE_IS_OUTPUT(type))
743*ee4a77a3SMauro Carvalho Chehab 		return &ctx->out_q;
744*ee4a77a3SMauro Carvalho Chehab 	else
745*ee4a77a3SMauro Carvalho Chehab 		return &ctx->cap_q;
746*ee4a77a3SMauro Carvalho Chehab }
747*ee4a77a3SMauro Carvalho Chehab 
748*ee4a77a3SMauro Carvalho Chehab static void jpu_bound_align_image(u32 *w, unsigned int w_min,
749*ee4a77a3SMauro Carvalho Chehab 				  unsigned int w_max, unsigned int w_align,
750*ee4a77a3SMauro Carvalho Chehab 				  u32 *h, unsigned int h_min,
751*ee4a77a3SMauro Carvalho Chehab 				  unsigned int h_max, unsigned int h_align)
752*ee4a77a3SMauro Carvalho Chehab {
753*ee4a77a3SMauro Carvalho Chehab 	unsigned int width, height, w_step, h_step;
754*ee4a77a3SMauro Carvalho Chehab 
755*ee4a77a3SMauro Carvalho Chehab 	width = *w;
756*ee4a77a3SMauro Carvalho Chehab 	height = *h;
757*ee4a77a3SMauro Carvalho Chehab 
758*ee4a77a3SMauro Carvalho Chehab 	w_step = 1U << w_align;
759*ee4a77a3SMauro Carvalho Chehab 	h_step = 1U << h_align;
760*ee4a77a3SMauro Carvalho Chehab 	v4l_bound_align_image(w, w_min, w_max, w_align, h, h_min, h_max,
761*ee4a77a3SMauro Carvalho Chehab 			      h_align, 3);
762*ee4a77a3SMauro Carvalho Chehab 
763*ee4a77a3SMauro Carvalho Chehab 	if (*w < width && *w + w_step < w_max)
764*ee4a77a3SMauro Carvalho Chehab 		*w += w_step;
765*ee4a77a3SMauro Carvalho Chehab 	if (*h < height && *h + h_step < h_max)
766*ee4a77a3SMauro Carvalho Chehab 		*h += h_step;
767*ee4a77a3SMauro Carvalho Chehab }
768*ee4a77a3SMauro Carvalho Chehab 
769*ee4a77a3SMauro Carvalho Chehab static int __jpu_try_fmt(struct jpu_ctx *ctx, struct jpu_fmt **fmtinfo,
770*ee4a77a3SMauro Carvalho Chehab 			 struct v4l2_pix_format_mplane *pix,
771*ee4a77a3SMauro Carvalho Chehab 			 enum v4l2_buf_type type)
772*ee4a77a3SMauro Carvalho Chehab {
773*ee4a77a3SMauro Carvalho Chehab 	struct jpu_fmt *fmt;
774*ee4a77a3SMauro Carvalho Chehab 	unsigned int f_type, w, h;
775*ee4a77a3SMauro Carvalho Chehab 
776*ee4a77a3SMauro Carvalho Chehab 	f_type = V4L2_TYPE_IS_OUTPUT(type) ? JPU_FMT_TYPE_OUTPUT :
777*ee4a77a3SMauro Carvalho Chehab 						JPU_FMT_TYPE_CAPTURE;
778*ee4a77a3SMauro Carvalho Chehab 
779*ee4a77a3SMauro Carvalho Chehab 	fmt = jpu_find_format(ctx->encoder, pix->pixelformat, f_type);
780*ee4a77a3SMauro Carvalho Chehab 	if (!fmt) {
781*ee4a77a3SMauro Carvalho Chehab 		unsigned int pixelformat;
782*ee4a77a3SMauro Carvalho Chehab 
783*ee4a77a3SMauro Carvalho Chehab 		dev_dbg(ctx->jpu->dev, "unknown format; set default format\n");
784*ee4a77a3SMauro Carvalho Chehab 		if (ctx->encoder)
785*ee4a77a3SMauro Carvalho Chehab 			pixelformat = f_type == JPU_FMT_TYPE_OUTPUT ?
786*ee4a77a3SMauro Carvalho Chehab 				V4L2_PIX_FMT_NV16M : V4L2_PIX_FMT_JPEG;
787*ee4a77a3SMauro Carvalho Chehab 		else
788*ee4a77a3SMauro Carvalho Chehab 			pixelformat = f_type == JPU_FMT_TYPE_CAPTURE ?
789*ee4a77a3SMauro Carvalho Chehab 				V4L2_PIX_FMT_NV16M : V4L2_PIX_FMT_JPEG;
790*ee4a77a3SMauro Carvalho Chehab 		fmt = jpu_find_format(ctx->encoder, pixelformat, f_type);
791*ee4a77a3SMauro Carvalho Chehab 	}
792*ee4a77a3SMauro Carvalho Chehab 
793*ee4a77a3SMauro Carvalho Chehab 	pix->pixelformat = fmt->fourcc;
794*ee4a77a3SMauro Carvalho Chehab 	pix->colorspace = fmt->colorspace;
795*ee4a77a3SMauro Carvalho Chehab 	pix->field = V4L2_FIELD_NONE;
796*ee4a77a3SMauro Carvalho Chehab 	pix->num_planes = fmt->num_planes;
797*ee4a77a3SMauro Carvalho Chehab 
798*ee4a77a3SMauro Carvalho Chehab 	jpu_bound_align_image(&pix->width, JPU_WIDTH_MIN, JPU_WIDTH_MAX,
799*ee4a77a3SMauro Carvalho Chehab 			      fmt->h_align, &pix->height, JPU_HEIGHT_MIN,
800*ee4a77a3SMauro Carvalho Chehab 			      JPU_HEIGHT_MAX, fmt->v_align);
801*ee4a77a3SMauro Carvalho Chehab 
802*ee4a77a3SMauro Carvalho Chehab 	w = pix->width;
803*ee4a77a3SMauro Carvalho Chehab 	h = pix->height;
804*ee4a77a3SMauro Carvalho Chehab 
805*ee4a77a3SMauro Carvalho Chehab 	if (fmt->fourcc == V4L2_PIX_FMT_JPEG) {
806*ee4a77a3SMauro Carvalho Chehab 		/* ignore userspaces's sizeimage for encoding */
807*ee4a77a3SMauro Carvalho Chehab 		if (pix->plane_fmt[0].sizeimage <= 0 || ctx->encoder)
808*ee4a77a3SMauro Carvalho Chehab 			pix->plane_fmt[0].sizeimage = JPU_JPEG_HDR_SIZE +
809*ee4a77a3SMauro Carvalho Chehab 				(JPU_JPEG_MAX_BYTES_PER_PIXEL * w * h);
810*ee4a77a3SMauro Carvalho Chehab 		pix->plane_fmt[0].bytesperline = 0;
811*ee4a77a3SMauro Carvalho Chehab 	} else {
812*ee4a77a3SMauro Carvalho Chehab 		unsigned int i, bpl = 0;
813*ee4a77a3SMauro Carvalho Chehab 
814*ee4a77a3SMauro Carvalho Chehab 		for (i = 0; i < pix->num_planes; ++i)
815*ee4a77a3SMauro Carvalho Chehab 			bpl = max(bpl, pix->plane_fmt[i].bytesperline);
816*ee4a77a3SMauro Carvalho Chehab 
817*ee4a77a3SMauro Carvalho Chehab 		bpl = clamp_t(unsigned int, bpl, w, JPU_WIDTH_MAX);
818*ee4a77a3SMauro Carvalho Chehab 		bpl = round_up(bpl, JPU_MEMALIGN);
819*ee4a77a3SMauro Carvalho Chehab 
820*ee4a77a3SMauro Carvalho Chehab 		for (i = 0; i < pix->num_planes; ++i) {
821*ee4a77a3SMauro Carvalho Chehab 			pix->plane_fmt[i].bytesperline = bpl;
822*ee4a77a3SMauro Carvalho Chehab 			pix->plane_fmt[i].sizeimage = bpl * h * fmt->bpp[i] / 8;
823*ee4a77a3SMauro Carvalho Chehab 		}
824*ee4a77a3SMauro Carvalho Chehab 	}
825*ee4a77a3SMauro Carvalho Chehab 
826*ee4a77a3SMauro Carvalho Chehab 	if (fmtinfo)
827*ee4a77a3SMauro Carvalho Chehab 		*fmtinfo = fmt;
828*ee4a77a3SMauro Carvalho Chehab 
829*ee4a77a3SMauro Carvalho Chehab 	return 0;
830*ee4a77a3SMauro Carvalho Chehab }
831*ee4a77a3SMauro Carvalho Chehab 
832*ee4a77a3SMauro Carvalho Chehab static int jpu_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
833*ee4a77a3SMauro Carvalho Chehab {
834*ee4a77a3SMauro Carvalho Chehab 	struct jpu_ctx *ctx = fh_to_ctx(priv);
835*ee4a77a3SMauro Carvalho Chehab 
836*ee4a77a3SMauro Carvalho Chehab 	if (!v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type))
837*ee4a77a3SMauro Carvalho Chehab 		return -EINVAL;
838*ee4a77a3SMauro Carvalho Chehab 
839*ee4a77a3SMauro Carvalho Chehab 	return __jpu_try_fmt(ctx, NULL, &f->fmt.pix_mp, f->type);
840*ee4a77a3SMauro Carvalho Chehab }
841*ee4a77a3SMauro Carvalho Chehab 
842*ee4a77a3SMauro Carvalho Chehab static int jpu_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
843*ee4a77a3SMauro Carvalho Chehab {
844*ee4a77a3SMauro Carvalho Chehab 	struct vb2_queue *vq;
845*ee4a77a3SMauro Carvalho Chehab 	struct jpu_ctx *ctx = fh_to_ctx(priv);
846*ee4a77a3SMauro Carvalho Chehab 	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
847*ee4a77a3SMauro Carvalho Chehab 	struct jpu_fmt *fmtinfo;
848*ee4a77a3SMauro Carvalho Chehab 	struct jpu_q_data *q_data;
849*ee4a77a3SMauro Carvalho Chehab 	int ret;
850*ee4a77a3SMauro Carvalho Chehab 
851*ee4a77a3SMauro Carvalho Chehab 	vq = v4l2_m2m_get_vq(m2m_ctx, f->type);
852*ee4a77a3SMauro Carvalho Chehab 	if (!vq)
853*ee4a77a3SMauro Carvalho Chehab 		return -EINVAL;
854*ee4a77a3SMauro Carvalho Chehab 
855*ee4a77a3SMauro Carvalho Chehab 	if (vb2_is_busy(vq)) {
856*ee4a77a3SMauro Carvalho Chehab 		v4l2_err(&ctx->jpu->v4l2_dev, "%s queue busy\n", __func__);
857*ee4a77a3SMauro Carvalho Chehab 		return -EBUSY;
858*ee4a77a3SMauro Carvalho Chehab 	}
859*ee4a77a3SMauro Carvalho Chehab 
860*ee4a77a3SMauro Carvalho Chehab 	ret = __jpu_try_fmt(ctx, &fmtinfo, &f->fmt.pix_mp, f->type);
861*ee4a77a3SMauro Carvalho Chehab 	if (ret < 0)
862*ee4a77a3SMauro Carvalho Chehab 		return ret;
863*ee4a77a3SMauro Carvalho Chehab 
864*ee4a77a3SMauro Carvalho Chehab 	q_data = jpu_get_q_data(ctx, f->type);
865*ee4a77a3SMauro Carvalho Chehab 
866*ee4a77a3SMauro Carvalho Chehab 	q_data->format = f->fmt.pix_mp;
867*ee4a77a3SMauro Carvalho Chehab 	q_data->fmtinfo = fmtinfo;
868*ee4a77a3SMauro Carvalho Chehab 
869*ee4a77a3SMauro Carvalho Chehab 	return 0;
870*ee4a77a3SMauro Carvalho Chehab }
871*ee4a77a3SMauro Carvalho Chehab 
872*ee4a77a3SMauro Carvalho Chehab static int jpu_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
873*ee4a77a3SMauro Carvalho Chehab {
874*ee4a77a3SMauro Carvalho Chehab 	struct jpu_q_data *q_data;
875*ee4a77a3SMauro Carvalho Chehab 	struct jpu_ctx *ctx = fh_to_ctx(priv);
876*ee4a77a3SMauro Carvalho Chehab 
877*ee4a77a3SMauro Carvalho Chehab 	if (!v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type))
878*ee4a77a3SMauro Carvalho Chehab 		return -EINVAL;
879*ee4a77a3SMauro Carvalho Chehab 
880*ee4a77a3SMauro Carvalho Chehab 	q_data = jpu_get_q_data(ctx, f->type);
881*ee4a77a3SMauro Carvalho Chehab 	f->fmt.pix_mp = q_data->format;
882*ee4a77a3SMauro Carvalho Chehab 
883*ee4a77a3SMauro Carvalho Chehab 	return 0;
884*ee4a77a3SMauro Carvalho Chehab }
885*ee4a77a3SMauro Carvalho Chehab 
886*ee4a77a3SMauro Carvalho Chehab /*
887*ee4a77a3SMauro Carvalho Chehab  * V4L2 controls
888*ee4a77a3SMauro Carvalho Chehab  */
889*ee4a77a3SMauro Carvalho Chehab static int jpu_s_ctrl(struct v4l2_ctrl *ctrl)
890*ee4a77a3SMauro Carvalho Chehab {
891*ee4a77a3SMauro Carvalho Chehab 	struct jpu_ctx *ctx = ctrl_to_ctx(ctrl);
892*ee4a77a3SMauro Carvalho Chehab 	unsigned long flags;
893*ee4a77a3SMauro Carvalho Chehab 
894*ee4a77a3SMauro Carvalho Chehab 	spin_lock_irqsave(&ctx->jpu->lock, flags);
895*ee4a77a3SMauro Carvalho Chehab 	if (ctrl->id == V4L2_CID_JPEG_COMPRESSION_QUALITY)
896*ee4a77a3SMauro Carvalho Chehab 		ctx->compr_quality = ctrl->val;
897*ee4a77a3SMauro Carvalho Chehab 	spin_unlock_irqrestore(&ctx->jpu->lock, flags);
898*ee4a77a3SMauro Carvalho Chehab 
899*ee4a77a3SMauro Carvalho Chehab 	return 0;
900*ee4a77a3SMauro Carvalho Chehab }
901*ee4a77a3SMauro Carvalho Chehab 
902*ee4a77a3SMauro Carvalho Chehab static const struct v4l2_ctrl_ops jpu_ctrl_ops = {
903*ee4a77a3SMauro Carvalho Chehab 	.s_ctrl		= jpu_s_ctrl,
904*ee4a77a3SMauro Carvalho Chehab };
905*ee4a77a3SMauro Carvalho Chehab 
906*ee4a77a3SMauro Carvalho Chehab static int jpu_streamon(struct file *file, void *priv, enum v4l2_buf_type type)
907*ee4a77a3SMauro Carvalho Chehab {
908*ee4a77a3SMauro Carvalho Chehab 	struct jpu_ctx *ctx = fh_to_ctx(priv);
909*ee4a77a3SMauro Carvalho Chehab 	struct jpu_q_data *src_q_data, *dst_q_data, *orig, adj, *ref;
910*ee4a77a3SMauro Carvalho Chehab 	enum v4l2_buf_type adj_type;
911*ee4a77a3SMauro Carvalho Chehab 
912*ee4a77a3SMauro Carvalho Chehab 	src_q_data = jpu_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
913*ee4a77a3SMauro Carvalho Chehab 	dst_q_data = jpu_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
914*ee4a77a3SMauro Carvalho Chehab 
915*ee4a77a3SMauro Carvalho Chehab 	if (ctx->encoder) {
916*ee4a77a3SMauro Carvalho Chehab 		adj = *src_q_data;
917*ee4a77a3SMauro Carvalho Chehab 		orig = src_q_data;
918*ee4a77a3SMauro Carvalho Chehab 		ref = dst_q_data;
919*ee4a77a3SMauro Carvalho Chehab 		adj_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
920*ee4a77a3SMauro Carvalho Chehab 	} else {
921*ee4a77a3SMauro Carvalho Chehab 		adj = *dst_q_data;
922*ee4a77a3SMauro Carvalho Chehab 		orig = dst_q_data;
923*ee4a77a3SMauro Carvalho Chehab 		ref = src_q_data;
924*ee4a77a3SMauro Carvalho Chehab 		adj_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
925*ee4a77a3SMauro Carvalho Chehab 	}
926*ee4a77a3SMauro Carvalho Chehab 
927*ee4a77a3SMauro Carvalho Chehab 	adj.format.width = ref->format.width;
928*ee4a77a3SMauro Carvalho Chehab 	adj.format.height = ref->format.height;
929*ee4a77a3SMauro Carvalho Chehab 
930*ee4a77a3SMauro Carvalho Chehab 	__jpu_try_fmt(ctx, NULL, &adj.format, adj_type);
931*ee4a77a3SMauro Carvalho Chehab 
932*ee4a77a3SMauro Carvalho Chehab 	if (adj.format.width != orig->format.width ||
933*ee4a77a3SMauro Carvalho Chehab 	    adj.format.height != orig->format.height) {
934*ee4a77a3SMauro Carvalho Chehab 		dev_err(ctx->jpu->dev, "src and dst formats do not match.\n");
935*ee4a77a3SMauro Carvalho Chehab 		/* maybe we can return -EPIPE here? */
936*ee4a77a3SMauro Carvalho Chehab 		return -EINVAL;
937*ee4a77a3SMauro Carvalho Chehab 	}
938*ee4a77a3SMauro Carvalho Chehab 
939*ee4a77a3SMauro Carvalho Chehab 	return v4l2_m2m_streamon(file, ctx->fh.m2m_ctx, type);
940*ee4a77a3SMauro Carvalho Chehab }
941*ee4a77a3SMauro Carvalho Chehab 
942*ee4a77a3SMauro Carvalho Chehab static const struct v4l2_ioctl_ops jpu_ioctl_ops = {
943*ee4a77a3SMauro Carvalho Chehab 	.vidioc_querycap		= jpu_querycap,
944*ee4a77a3SMauro Carvalho Chehab 
945*ee4a77a3SMauro Carvalho Chehab 	.vidioc_enum_fmt_vid_cap	= jpu_enum_fmt_cap,
946*ee4a77a3SMauro Carvalho Chehab 	.vidioc_enum_fmt_vid_out	= jpu_enum_fmt_out,
947*ee4a77a3SMauro Carvalho Chehab 	.vidioc_g_fmt_vid_cap_mplane	= jpu_g_fmt,
948*ee4a77a3SMauro Carvalho Chehab 	.vidioc_g_fmt_vid_out_mplane	= jpu_g_fmt,
949*ee4a77a3SMauro Carvalho Chehab 	.vidioc_try_fmt_vid_cap_mplane	= jpu_try_fmt,
950*ee4a77a3SMauro Carvalho Chehab 	.vidioc_try_fmt_vid_out_mplane	= jpu_try_fmt,
951*ee4a77a3SMauro Carvalho Chehab 	.vidioc_s_fmt_vid_cap_mplane	= jpu_s_fmt,
952*ee4a77a3SMauro Carvalho Chehab 	.vidioc_s_fmt_vid_out_mplane	= jpu_s_fmt,
953*ee4a77a3SMauro Carvalho Chehab 
954*ee4a77a3SMauro Carvalho Chehab 	.vidioc_reqbufs			= v4l2_m2m_ioctl_reqbufs,
955*ee4a77a3SMauro Carvalho Chehab 	.vidioc_create_bufs             = v4l2_m2m_ioctl_create_bufs,
956*ee4a77a3SMauro Carvalho Chehab 	.vidioc_querybuf		= v4l2_m2m_ioctl_querybuf,
957*ee4a77a3SMauro Carvalho Chehab 	.vidioc_qbuf			= v4l2_m2m_ioctl_qbuf,
958*ee4a77a3SMauro Carvalho Chehab 	.vidioc_dqbuf			= v4l2_m2m_ioctl_dqbuf,
959*ee4a77a3SMauro Carvalho Chehab 	.vidioc_expbuf			= v4l2_m2m_ioctl_expbuf,
960*ee4a77a3SMauro Carvalho Chehab 
961*ee4a77a3SMauro Carvalho Chehab 	.vidioc_streamon		= jpu_streamon,
962*ee4a77a3SMauro Carvalho Chehab 	.vidioc_streamoff		= v4l2_m2m_ioctl_streamoff,
963*ee4a77a3SMauro Carvalho Chehab 
964*ee4a77a3SMauro Carvalho Chehab 	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
965*ee4a77a3SMauro Carvalho Chehab 	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe
966*ee4a77a3SMauro Carvalho Chehab };
967*ee4a77a3SMauro Carvalho Chehab 
968*ee4a77a3SMauro Carvalho Chehab static int jpu_controls_create(struct jpu_ctx *ctx)
969*ee4a77a3SMauro Carvalho Chehab {
970*ee4a77a3SMauro Carvalho Chehab 	struct v4l2_ctrl *ctrl;
971*ee4a77a3SMauro Carvalho Chehab 	int ret;
972*ee4a77a3SMauro Carvalho Chehab 
973*ee4a77a3SMauro Carvalho Chehab 	v4l2_ctrl_handler_init(&ctx->ctrl_handler, 1);
974*ee4a77a3SMauro Carvalho Chehab 
975*ee4a77a3SMauro Carvalho Chehab 	ctrl = v4l2_ctrl_new_std(&ctx->ctrl_handler, &jpu_ctrl_ops,
976*ee4a77a3SMauro Carvalho Chehab 				 V4L2_CID_JPEG_COMPRESSION_QUALITY,
977*ee4a77a3SMauro Carvalho Chehab 				 0, JPU_MAX_QUALITY - 1, 1, 0);
978*ee4a77a3SMauro Carvalho Chehab 
979*ee4a77a3SMauro Carvalho Chehab 	if (ctx->ctrl_handler.error) {
980*ee4a77a3SMauro Carvalho Chehab 		ret = ctx->ctrl_handler.error;
981*ee4a77a3SMauro Carvalho Chehab 		goto error_free;
982*ee4a77a3SMauro Carvalho Chehab 	}
983*ee4a77a3SMauro Carvalho Chehab 
984*ee4a77a3SMauro Carvalho Chehab 	if (!ctx->encoder)
985*ee4a77a3SMauro Carvalho Chehab 		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
986*ee4a77a3SMauro Carvalho Chehab 				V4L2_CTRL_FLAG_READ_ONLY;
987*ee4a77a3SMauro Carvalho Chehab 
988*ee4a77a3SMauro Carvalho Chehab 	ret = v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
989*ee4a77a3SMauro Carvalho Chehab 	if (ret < 0)
990*ee4a77a3SMauro Carvalho Chehab 		goto error_free;
991*ee4a77a3SMauro Carvalho Chehab 
992*ee4a77a3SMauro Carvalho Chehab 	return 0;
993*ee4a77a3SMauro Carvalho Chehab 
994*ee4a77a3SMauro Carvalho Chehab error_free:
995*ee4a77a3SMauro Carvalho Chehab 	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
996*ee4a77a3SMauro Carvalho Chehab 	return ret;
997*ee4a77a3SMauro Carvalho Chehab }
998*ee4a77a3SMauro Carvalho Chehab 
999*ee4a77a3SMauro Carvalho Chehab /*
1000*ee4a77a3SMauro Carvalho Chehab  * ============================================================================
1001*ee4a77a3SMauro Carvalho Chehab  * Queue operations
1002*ee4a77a3SMauro Carvalho Chehab  * ============================================================================
1003*ee4a77a3SMauro Carvalho Chehab  */
1004*ee4a77a3SMauro Carvalho Chehab static int jpu_queue_setup(struct vb2_queue *vq,
1005*ee4a77a3SMauro Carvalho Chehab 			   unsigned int *nbuffers, unsigned int *nplanes,
1006*ee4a77a3SMauro Carvalho Chehab 			   unsigned int sizes[], struct device *alloc_devs[])
1007*ee4a77a3SMauro Carvalho Chehab {
1008*ee4a77a3SMauro Carvalho Chehab 	struct jpu_ctx *ctx = vb2_get_drv_priv(vq);
1009*ee4a77a3SMauro Carvalho Chehab 	struct jpu_q_data *q_data;
1010*ee4a77a3SMauro Carvalho Chehab 	unsigned int i;
1011*ee4a77a3SMauro Carvalho Chehab 
1012*ee4a77a3SMauro Carvalho Chehab 	q_data = jpu_get_q_data(ctx, vq->type);
1013*ee4a77a3SMauro Carvalho Chehab 
1014*ee4a77a3SMauro Carvalho Chehab 	if (*nplanes) {
1015*ee4a77a3SMauro Carvalho Chehab 		if (*nplanes != q_data->format.num_planes)
1016*ee4a77a3SMauro Carvalho Chehab 			return -EINVAL;
1017*ee4a77a3SMauro Carvalho Chehab 
1018*ee4a77a3SMauro Carvalho Chehab 		for (i = 0; i < *nplanes; i++) {
1019*ee4a77a3SMauro Carvalho Chehab 			unsigned int q_size = q_data->format.plane_fmt[i].sizeimage;
1020*ee4a77a3SMauro Carvalho Chehab 
1021*ee4a77a3SMauro Carvalho Chehab 			if (sizes[i] < q_size)
1022*ee4a77a3SMauro Carvalho Chehab 				return -EINVAL;
1023*ee4a77a3SMauro Carvalho Chehab 		}
1024*ee4a77a3SMauro Carvalho Chehab 		return 0;
1025*ee4a77a3SMauro Carvalho Chehab 	}
1026*ee4a77a3SMauro Carvalho Chehab 
1027*ee4a77a3SMauro Carvalho Chehab 	*nplanes = q_data->format.num_planes;
1028*ee4a77a3SMauro Carvalho Chehab 
1029*ee4a77a3SMauro Carvalho Chehab 	for (i = 0; i < *nplanes; i++)
1030*ee4a77a3SMauro Carvalho Chehab 		sizes[i] = q_data->format.plane_fmt[i].sizeimage;
1031*ee4a77a3SMauro Carvalho Chehab 
1032*ee4a77a3SMauro Carvalho Chehab 	return 0;
1033*ee4a77a3SMauro Carvalho Chehab }
1034*ee4a77a3SMauro Carvalho Chehab 
1035*ee4a77a3SMauro Carvalho Chehab static int jpu_buf_prepare(struct vb2_buffer *vb)
1036*ee4a77a3SMauro Carvalho Chehab {
1037*ee4a77a3SMauro Carvalho Chehab 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1038*ee4a77a3SMauro Carvalho Chehab 	struct jpu_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1039*ee4a77a3SMauro Carvalho Chehab 	struct jpu_q_data *q_data;
1040*ee4a77a3SMauro Carvalho Chehab 	unsigned int i;
1041*ee4a77a3SMauro Carvalho Chehab 
1042*ee4a77a3SMauro Carvalho Chehab 	q_data = jpu_get_q_data(ctx, vb->vb2_queue->type);
1043*ee4a77a3SMauro Carvalho Chehab 
1044*ee4a77a3SMauro Carvalho Chehab 	if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
1045*ee4a77a3SMauro Carvalho Chehab 		if (vbuf->field == V4L2_FIELD_ANY)
1046*ee4a77a3SMauro Carvalho Chehab 			vbuf->field = V4L2_FIELD_NONE;
1047*ee4a77a3SMauro Carvalho Chehab 		if (vbuf->field != V4L2_FIELD_NONE) {
1048*ee4a77a3SMauro Carvalho Chehab 			dev_err(ctx->jpu->dev, "%s field isn't supported\n",
1049*ee4a77a3SMauro Carvalho Chehab 					__func__);
1050*ee4a77a3SMauro Carvalho Chehab 			return -EINVAL;
1051*ee4a77a3SMauro Carvalho Chehab 		}
1052*ee4a77a3SMauro Carvalho Chehab 	}
1053*ee4a77a3SMauro Carvalho Chehab 
1054*ee4a77a3SMauro Carvalho Chehab 	for (i = 0; i < q_data->format.num_planes; i++) {
1055*ee4a77a3SMauro Carvalho Chehab 		unsigned long size = q_data->format.plane_fmt[i].sizeimage;
1056*ee4a77a3SMauro Carvalho Chehab 
1057*ee4a77a3SMauro Carvalho Chehab 		if (vb2_plane_size(vb, i) < size) {
1058*ee4a77a3SMauro Carvalho Chehab 			dev_err(ctx->jpu->dev,
1059*ee4a77a3SMauro Carvalho Chehab 				"%s: data will not fit into plane (%lu < %lu)\n",
1060*ee4a77a3SMauro Carvalho Chehab 			       __func__, vb2_plane_size(vb, i), size);
1061*ee4a77a3SMauro Carvalho Chehab 			return -EINVAL;
1062*ee4a77a3SMauro Carvalho Chehab 		}
1063*ee4a77a3SMauro Carvalho Chehab 
1064*ee4a77a3SMauro Carvalho Chehab 		/* decoder capture queue */
1065*ee4a77a3SMauro Carvalho Chehab 		if (!ctx->encoder && V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type))
1066*ee4a77a3SMauro Carvalho Chehab 			vb2_set_plane_payload(vb, i, size);
1067*ee4a77a3SMauro Carvalho Chehab 	}
1068*ee4a77a3SMauro Carvalho Chehab 
1069*ee4a77a3SMauro Carvalho Chehab 	return 0;
1070*ee4a77a3SMauro Carvalho Chehab }
1071*ee4a77a3SMauro Carvalho Chehab 
1072*ee4a77a3SMauro Carvalho Chehab static void jpu_buf_queue(struct vb2_buffer *vb)
1073*ee4a77a3SMauro Carvalho Chehab {
1074*ee4a77a3SMauro Carvalho Chehab 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1075*ee4a77a3SMauro Carvalho Chehab 	struct jpu_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1076*ee4a77a3SMauro Carvalho Chehab 
1077*ee4a77a3SMauro Carvalho Chehab 	if (!ctx->encoder && V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
1078*ee4a77a3SMauro Carvalho Chehab 		struct jpu_buffer *jpu_buf = vb2_to_jpu_buffer(vbuf);
1079*ee4a77a3SMauro Carvalho Chehab 		struct jpu_q_data *q_data, adjust;
1080*ee4a77a3SMauro Carvalho Chehab 		void *buffer = vb2_plane_vaddr(vb, 0);
1081*ee4a77a3SMauro Carvalho Chehab 		unsigned long buf_size = vb2_get_plane_payload(vb, 0);
1082*ee4a77a3SMauro Carvalho Chehab 		unsigned int width, height;
1083*ee4a77a3SMauro Carvalho Chehab 
1084*ee4a77a3SMauro Carvalho Chehab 		u8 subsampling = jpu_parse_hdr(buffer, buf_size, &width,
1085*ee4a77a3SMauro Carvalho Chehab 						 &height);
1086*ee4a77a3SMauro Carvalho Chehab 
1087*ee4a77a3SMauro Carvalho Chehab 		/* check if JPEG data basic parsing was successful */
1088*ee4a77a3SMauro Carvalho Chehab 		if (subsampling != JPU_JPEG_422 && subsampling != JPU_JPEG_420)
1089*ee4a77a3SMauro Carvalho Chehab 			goto format_error;
1090*ee4a77a3SMauro Carvalho Chehab 
1091*ee4a77a3SMauro Carvalho Chehab 		q_data = &ctx->out_q;
1092*ee4a77a3SMauro Carvalho Chehab 
1093*ee4a77a3SMauro Carvalho Chehab 		adjust = *q_data;
1094*ee4a77a3SMauro Carvalho Chehab 		adjust.format.width = width;
1095*ee4a77a3SMauro Carvalho Chehab 		adjust.format.height = height;
1096*ee4a77a3SMauro Carvalho Chehab 
1097*ee4a77a3SMauro Carvalho Chehab 		__jpu_try_fmt(ctx, &adjust.fmtinfo, &adjust.format,
1098*ee4a77a3SMauro Carvalho Chehab 			      V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
1099*ee4a77a3SMauro Carvalho Chehab 
1100*ee4a77a3SMauro Carvalho Chehab 		if (adjust.format.width != q_data->format.width ||
1101*ee4a77a3SMauro Carvalho Chehab 		    adjust.format.height != q_data->format.height)
1102*ee4a77a3SMauro Carvalho Chehab 			goto format_error;
1103*ee4a77a3SMauro Carvalho Chehab 
1104*ee4a77a3SMauro Carvalho Chehab 		/*
1105*ee4a77a3SMauro Carvalho Chehab 		 * keep subsampling in buffer to check it
1106*ee4a77a3SMauro Carvalho Chehab 		 * for compatibility in device_run
1107*ee4a77a3SMauro Carvalho Chehab 		 */
1108*ee4a77a3SMauro Carvalho Chehab 		jpu_buf->subsampling = subsampling;
1109*ee4a77a3SMauro Carvalho Chehab 	}
1110*ee4a77a3SMauro Carvalho Chehab 
1111*ee4a77a3SMauro Carvalho Chehab 	if (ctx->fh.m2m_ctx)
1112*ee4a77a3SMauro Carvalho Chehab 		v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1113*ee4a77a3SMauro Carvalho Chehab 
1114*ee4a77a3SMauro Carvalho Chehab 	return;
1115*ee4a77a3SMauro Carvalho Chehab 
1116*ee4a77a3SMauro Carvalho Chehab format_error:
1117*ee4a77a3SMauro Carvalho Chehab 	dev_err(ctx->jpu->dev, "incompatible or corrupted JPEG data\n");
1118*ee4a77a3SMauro Carvalho Chehab 	vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
1119*ee4a77a3SMauro Carvalho Chehab }
1120*ee4a77a3SMauro Carvalho Chehab 
1121*ee4a77a3SMauro Carvalho Chehab static void jpu_buf_finish(struct vb2_buffer *vb)
1122*ee4a77a3SMauro Carvalho Chehab {
1123*ee4a77a3SMauro Carvalho Chehab 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1124*ee4a77a3SMauro Carvalho Chehab 	struct jpu_buffer *jpu_buf = vb2_to_jpu_buffer(vbuf);
1125*ee4a77a3SMauro Carvalho Chehab 	struct jpu_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1126*ee4a77a3SMauro Carvalho Chehab 	struct jpu_q_data *q_data = &ctx->out_q;
1127*ee4a77a3SMauro Carvalho Chehab 	enum v4l2_buf_type type = vb->vb2_queue->type;
1128*ee4a77a3SMauro Carvalho Chehab 	u8 *buffer;
1129*ee4a77a3SMauro Carvalho Chehab 
1130*ee4a77a3SMauro Carvalho Chehab 	if (vb->state == VB2_BUF_STATE_DONE)
1131*ee4a77a3SMauro Carvalho Chehab 		vbuf->sequence = jpu_get_q_data(ctx, type)->sequence++;
1132*ee4a77a3SMauro Carvalho Chehab 
1133*ee4a77a3SMauro Carvalho Chehab 	if (!ctx->encoder || vb->state != VB2_BUF_STATE_DONE ||
1134*ee4a77a3SMauro Carvalho Chehab 	    V4L2_TYPE_IS_OUTPUT(type))
1135*ee4a77a3SMauro Carvalho Chehab 		return;
1136*ee4a77a3SMauro Carvalho Chehab 
1137*ee4a77a3SMauro Carvalho Chehab 	buffer = vb2_plane_vaddr(vb, 0);
1138*ee4a77a3SMauro Carvalho Chehab 
1139*ee4a77a3SMauro Carvalho Chehab 	memcpy(buffer, jpeg_hdrs[jpu_buf->compr_quality], JPU_JPEG_HDR_SIZE);
1140*ee4a77a3SMauro Carvalho Chehab 	*(__be16 *)(buffer + JPU_JPEG_HEIGHT_OFFSET) =
1141*ee4a77a3SMauro Carvalho Chehab 					cpu_to_be16(q_data->format.height);
1142*ee4a77a3SMauro Carvalho Chehab 	*(__be16 *)(buffer + JPU_JPEG_WIDTH_OFFSET) =
1143*ee4a77a3SMauro Carvalho Chehab 					cpu_to_be16(q_data->format.width);
1144*ee4a77a3SMauro Carvalho Chehab 	*(buffer + JPU_JPEG_SUBS_OFFSET) = q_data->fmtinfo->subsampling;
1145*ee4a77a3SMauro Carvalho Chehab }
1146*ee4a77a3SMauro Carvalho Chehab 
1147*ee4a77a3SMauro Carvalho Chehab static int jpu_start_streaming(struct vb2_queue *vq, unsigned count)
1148*ee4a77a3SMauro Carvalho Chehab {
1149*ee4a77a3SMauro Carvalho Chehab 	struct jpu_ctx *ctx = vb2_get_drv_priv(vq);
1150*ee4a77a3SMauro Carvalho Chehab 	struct jpu_q_data *q_data = jpu_get_q_data(ctx, vq->type);
1151*ee4a77a3SMauro Carvalho Chehab 
1152*ee4a77a3SMauro Carvalho Chehab 	q_data->sequence = 0;
1153*ee4a77a3SMauro Carvalho Chehab 	return 0;
1154*ee4a77a3SMauro Carvalho Chehab }
1155*ee4a77a3SMauro Carvalho Chehab 
1156*ee4a77a3SMauro Carvalho Chehab static void jpu_stop_streaming(struct vb2_queue *vq)
1157*ee4a77a3SMauro Carvalho Chehab {
1158*ee4a77a3SMauro Carvalho Chehab 	struct jpu_ctx *ctx = vb2_get_drv_priv(vq);
1159*ee4a77a3SMauro Carvalho Chehab 	struct vb2_v4l2_buffer *vb;
1160*ee4a77a3SMauro Carvalho Chehab 	unsigned long flags;
1161*ee4a77a3SMauro Carvalho Chehab 
1162*ee4a77a3SMauro Carvalho Chehab 	for (;;) {
1163*ee4a77a3SMauro Carvalho Chehab 		if (V4L2_TYPE_IS_OUTPUT(vq->type))
1164*ee4a77a3SMauro Carvalho Chehab 			vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
1165*ee4a77a3SMauro Carvalho Chehab 		else
1166*ee4a77a3SMauro Carvalho Chehab 			vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
1167*ee4a77a3SMauro Carvalho Chehab 		if (vb == NULL)
1168*ee4a77a3SMauro Carvalho Chehab 			return;
1169*ee4a77a3SMauro Carvalho Chehab 		spin_lock_irqsave(&ctx->jpu->lock, flags);
1170*ee4a77a3SMauro Carvalho Chehab 		v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);
1171*ee4a77a3SMauro Carvalho Chehab 		spin_unlock_irqrestore(&ctx->jpu->lock, flags);
1172*ee4a77a3SMauro Carvalho Chehab 	}
1173*ee4a77a3SMauro Carvalho Chehab }
1174*ee4a77a3SMauro Carvalho Chehab 
1175*ee4a77a3SMauro Carvalho Chehab static const struct vb2_ops jpu_qops = {
1176*ee4a77a3SMauro Carvalho Chehab 	.queue_setup		= jpu_queue_setup,
1177*ee4a77a3SMauro Carvalho Chehab 	.buf_prepare		= jpu_buf_prepare,
1178*ee4a77a3SMauro Carvalho Chehab 	.buf_queue		= jpu_buf_queue,
1179*ee4a77a3SMauro Carvalho Chehab 	.buf_finish		= jpu_buf_finish,
1180*ee4a77a3SMauro Carvalho Chehab 	.start_streaming	= jpu_start_streaming,
1181*ee4a77a3SMauro Carvalho Chehab 	.stop_streaming		= jpu_stop_streaming,
1182*ee4a77a3SMauro Carvalho Chehab 	.wait_prepare		= vb2_ops_wait_prepare,
1183*ee4a77a3SMauro Carvalho Chehab 	.wait_finish		= vb2_ops_wait_finish,
1184*ee4a77a3SMauro Carvalho Chehab };
1185*ee4a77a3SMauro Carvalho Chehab 
1186*ee4a77a3SMauro Carvalho Chehab static int jpu_queue_init(void *priv, struct vb2_queue *src_vq,
1187*ee4a77a3SMauro Carvalho Chehab 			  struct vb2_queue *dst_vq)
1188*ee4a77a3SMauro Carvalho Chehab {
1189*ee4a77a3SMauro Carvalho Chehab 	struct jpu_ctx *ctx = priv;
1190*ee4a77a3SMauro Carvalho Chehab 	int ret;
1191*ee4a77a3SMauro Carvalho Chehab 
1192*ee4a77a3SMauro Carvalho Chehab 	memset(src_vq, 0, sizeof(*src_vq));
1193*ee4a77a3SMauro Carvalho Chehab 	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1194*ee4a77a3SMauro Carvalho Chehab 	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
1195*ee4a77a3SMauro Carvalho Chehab 	src_vq->drv_priv = ctx;
1196*ee4a77a3SMauro Carvalho Chehab 	src_vq->buf_struct_size = sizeof(struct jpu_buffer);
1197*ee4a77a3SMauro Carvalho Chehab 	src_vq->ops = &jpu_qops;
1198*ee4a77a3SMauro Carvalho Chehab 	src_vq->mem_ops = &vb2_dma_contig_memops;
1199*ee4a77a3SMauro Carvalho Chehab 	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1200*ee4a77a3SMauro Carvalho Chehab 	src_vq->lock = &ctx->jpu->mutex;
1201*ee4a77a3SMauro Carvalho Chehab 	src_vq->dev = ctx->jpu->v4l2_dev.dev;
1202*ee4a77a3SMauro Carvalho Chehab 
1203*ee4a77a3SMauro Carvalho Chehab 	ret = vb2_queue_init(src_vq);
1204*ee4a77a3SMauro Carvalho Chehab 	if (ret)
1205*ee4a77a3SMauro Carvalho Chehab 		return ret;
1206*ee4a77a3SMauro Carvalho Chehab 
1207*ee4a77a3SMauro Carvalho Chehab 	memset(dst_vq, 0, sizeof(*dst_vq));
1208*ee4a77a3SMauro Carvalho Chehab 	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1209*ee4a77a3SMauro Carvalho Chehab 	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
1210*ee4a77a3SMauro Carvalho Chehab 	dst_vq->drv_priv = ctx;
1211*ee4a77a3SMauro Carvalho Chehab 	dst_vq->buf_struct_size = sizeof(struct jpu_buffer);
1212*ee4a77a3SMauro Carvalho Chehab 	dst_vq->ops = &jpu_qops;
1213*ee4a77a3SMauro Carvalho Chehab 	dst_vq->mem_ops = &vb2_dma_contig_memops;
1214*ee4a77a3SMauro Carvalho Chehab 	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1215*ee4a77a3SMauro Carvalho Chehab 	dst_vq->lock = &ctx->jpu->mutex;
1216*ee4a77a3SMauro Carvalho Chehab 	dst_vq->dev = ctx->jpu->v4l2_dev.dev;
1217*ee4a77a3SMauro Carvalho Chehab 
1218*ee4a77a3SMauro Carvalho Chehab 	return vb2_queue_init(dst_vq);
1219*ee4a77a3SMauro Carvalho Chehab }
1220*ee4a77a3SMauro Carvalho Chehab 
1221*ee4a77a3SMauro Carvalho Chehab /*
1222*ee4a77a3SMauro Carvalho Chehab  * ============================================================================
1223*ee4a77a3SMauro Carvalho Chehab  * Device file operations
1224*ee4a77a3SMauro Carvalho Chehab  * ============================================================================
1225*ee4a77a3SMauro Carvalho Chehab  */
1226*ee4a77a3SMauro Carvalho Chehab static int jpu_open(struct file *file)
1227*ee4a77a3SMauro Carvalho Chehab {
1228*ee4a77a3SMauro Carvalho Chehab 	struct jpu *jpu = video_drvdata(file);
1229*ee4a77a3SMauro Carvalho Chehab 	struct video_device *vfd = video_devdata(file);
1230*ee4a77a3SMauro Carvalho Chehab 	struct jpu_ctx *ctx;
1231*ee4a77a3SMauro Carvalho Chehab 	int ret;
1232*ee4a77a3SMauro Carvalho Chehab 
1233*ee4a77a3SMauro Carvalho Chehab 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
1234*ee4a77a3SMauro Carvalho Chehab 	if (!ctx)
1235*ee4a77a3SMauro Carvalho Chehab 		return -ENOMEM;
1236*ee4a77a3SMauro Carvalho Chehab 
1237*ee4a77a3SMauro Carvalho Chehab 	v4l2_fh_init(&ctx->fh, vfd);
1238*ee4a77a3SMauro Carvalho Chehab 	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
1239*ee4a77a3SMauro Carvalho Chehab 	file->private_data = &ctx->fh;
1240*ee4a77a3SMauro Carvalho Chehab 	v4l2_fh_add(&ctx->fh);
1241*ee4a77a3SMauro Carvalho Chehab 
1242*ee4a77a3SMauro Carvalho Chehab 	ctx->jpu = jpu;
1243*ee4a77a3SMauro Carvalho Chehab 	ctx->encoder = vfd == &jpu->vfd_encoder;
1244*ee4a77a3SMauro Carvalho Chehab 
1245*ee4a77a3SMauro Carvalho Chehab 	__jpu_try_fmt(ctx, &ctx->out_q.fmtinfo, &ctx->out_q.format,
1246*ee4a77a3SMauro Carvalho Chehab 		      V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
1247*ee4a77a3SMauro Carvalho Chehab 	__jpu_try_fmt(ctx, &ctx->cap_q.fmtinfo, &ctx->cap_q.format,
1248*ee4a77a3SMauro Carvalho Chehab 		      V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
1249*ee4a77a3SMauro Carvalho Chehab 
1250*ee4a77a3SMauro Carvalho Chehab 	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpu->m2m_dev, ctx, jpu_queue_init);
1251*ee4a77a3SMauro Carvalho Chehab 	if (IS_ERR(ctx->fh.m2m_ctx)) {
1252*ee4a77a3SMauro Carvalho Chehab 		ret = PTR_ERR(ctx->fh.m2m_ctx);
1253*ee4a77a3SMauro Carvalho Chehab 		goto v4l_prepare_rollback;
1254*ee4a77a3SMauro Carvalho Chehab 	}
1255*ee4a77a3SMauro Carvalho Chehab 
1256*ee4a77a3SMauro Carvalho Chehab 	ret = jpu_controls_create(ctx);
1257*ee4a77a3SMauro Carvalho Chehab 	if (ret < 0)
1258*ee4a77a3SMauro Carvalho Chehab 		goto v4l_prepare_rollback;
1259*ee4a77a3SMauro Carvalho Chehab 
1260*ee4a77a3SMauro Carvalho Chehab 	if (mutex_lock_interruptible(&jpu->mutex)) {
1261*ee4a77a3SMauro Carvalho Chehab 		ret = -ERESTARTSYS;
1262*ee4a77a3SMauro Carvalho Chehab 		goto v4l_prepare_rollback;
1263*ee4a77a3SMauro Carvalho Chehab 	}
1264*ee4a77a3SMauro Carvalho Chehab 
1265*ee4a77a3SMauro Carvalho Chehab 	if (jpu->ref_count == 0) {
1266*ee4a77a3SMauro Carvalho Chehab 		ret = clk_prepare_enable(jpu->clk);
1267*ee4a77a3SMauro Carvalho Chehab 		if (ret < 0)
1268*ee4a77a3SMauro Carvalho Chehab 			goto device_prepare_rollback;
1269*ee4a77a3SMauro Carvalho Chehab 		/* ...issue software reset */
1270*ee4a77a3SMauro Carvalho Chehab 		ret = jpu_reset(jpu);
1271*ee4a77a3SMauro Carvalho Chehab 		if (ret)
1272*ee4a77a3SMauro Carvalho Chehab 			goto jpu_reset_rollback;
1273*ee4a77a3SMauro Carvalho Chehab 	}
1274*ee4a77a3SMauro Carvalho Chehab 
1275*ee4a77a3SMauro Carvalho Chehab 	jpu->ref_count++;
1276*ee4a77a3SMauro Carvalho Chehab 
1277*ee4a77a3SMauro Carvalho Chehab 	mutex_unlock(&jpu->mutex);
1278*ee4a77a3SMauro Carvalho Chehab 	return 0;
1279*ee4a77a3SMauro Carvalho Chehab 
1280*ee4a77a3SMauro Carvalho Chehab jpu_reset_rollback:
1281*ee4a77a3SMauro Carvalho Chehab 	clk_disable_unprepare(jpu->clk);
1282*ee4a77a3SMauro Carvalho Chehab device_prepare_rollback:
1283*ee4a77a3SMauro Carvalho Chehab 	mutex_unlock(&jpu->mutex);
1284*ee4a77a3SMauro Carvalho Chehab v4l_prepare_rollback:
1285*ee4a77a3SMauro Carvalho Chehab 	v4l2_fh_del(&ctx->fh);
1286*ee4a77a3SMauro Carvalho Chehab 	v4l2_fh_exit(&ctx->fh);
1287*ee4a77a3SMauro Carvalho Chehab 	kfree(ctx);
1288*ee4a77a3SMauro Carvalho Chehab 	return ret;
1289*ee4a77a3SMauro Carvalho Chehab }
1290*ee4a77a3SMauro Carvalho Chehab 
1291*ee4a77a3SMauro Carvalho Chehab static int jpu_release(struct file *file)
1292*ee4a77a3SMauro Carvalho Chehab {
1293*ee4a77a3SMauro Carvalho Chehab 	struct jpu *jpu = video_drvdata(file);
1294*ee4a77a3SMauro Carvalho Chehab 	struct jpu_ctx *ctx = fh_to_ctx(file->private_data);
1295*ee4a77a3SMauro Carvalho Chehab 
1296*ee4a77a3SMauro Carvalho Chehab 	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
1297*ee4a77a3SMauro Carvalho Chehab 	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
1298*ee4a77a3SMauro Carvalho Chehab 	v4l2_fh_del(&ctx->fh);
1299*ee4a77a3SMauro Carvalho Chehab 	v4l2_fh_exit(&ctx->fh);
1300*ee4a77a3SMauro Carvalho Chehab 	kfree(ctx);
1301*ee4a77a3SMauro Carvalho Chehab 
1302*ee4a77a3SMauro Carvalho Chehab 	mutex_lock(&jpu->mutex);
1303*ee4a77a3SMauro Carvalho Chehab 	if (--jpu->ref_count == 0)
1304*ee4a77a3SMauro Carvalho Chehab 		clk_disable_unprepare(jpu->clk);
1305*ee4a77a3SMauro Carvalho Chehab 	mutex_unlock(&jpu->mutex);
1306*ee4a77a3SMauro Carvalho Chehab 
1307*ee4a77a3SMauro Carvalho Chehab 	return 0;
1308*ee4a77a3SMauro Carvalho Chehab }
1309*ee4a77a3SMauro Carvalho Chehab 
1310*ee4a77a3SMauro Carvalho Chehab static const struct v4l2_file_operations jpu_fops = {
1311*ee4a77a3SMauro Carvalho Chehab 	.owner		= THIS_MODULE,
1312*ee4a77a3SMauro Carvalho Chehab 	.open		= jpu_open,
1313*ee4a77a3SMauro Carvalho Chehab 	.release	= jpu_release,
1314*ee4a77a3SMauro Carvalho Chehab 	.unlocked_ioctl	= video_ioctl2,
1315*ee4a77a3SMauro Carvalho Chehab 	.poll		= v4l2_m2m_fop_poll,
1316*ee4a77a3SMauro Carvalho Chehab 	.mmap		= v4l2_m2m_fop_mmap,
1317*ee4a77a3SMauro Carvalho Chehab };
1318*ee4a77a3SMauro Carvalho Chehab 
1319*ee4a77a3SMauro Carvalho Chehab /*
1320*ee4a77a3SMauro Carvalho Chehab  * ============================================================================
1321*ee4a77a3SMauro Carvalho Chehab  * mem2mem callbacks
1322*ee4a77a3SMauro Carvalho Chehab  * ============================================================================
1323*ee4a77a3SMauro Carvalho Chehab  */
1324*ee4a77a3SMauro Carvalho Chehab static void jpu_cleanup(struct jpu_ctx *ctx, bool reset)
1325*ee4a77a3SMauro Carvalho Chehab {
1326*ee4a77a3SMauro Carvalho Chehab 	/* remove current buffers and finish job */
1327*ee4a77a3SMauro Carvalho Chehab 	struct vb2_v4l2_buffer *src_buf, *dst_buf;
1328*ee4a77a3SMauro Carvalho Chehab 	unsigned long flags;
1329*ee4a77a3SMauro Carvalho Chehab 
1330*ee4a77a3SMauro Carvalho Chehab 	spin_lock_irqsave(&ctx->jpu->lock, flags);
1331*ee4a77a3SMauro Carvalho Chehab 
1332*ee4a77a3SMauro Carvalho Chehab 	src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
1333*ee4a77a3SMauro Carvalho Chehab 	dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
1334*ee4a77a3SMauro Carvalho Chehab 
1335*ee4a77a3SMauro Carvalho Chehab 	v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
1336*ee4a77a3SMauro Carvalho Chehab 	v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
1337*ee4a77a3SMauro Carvalho Chehab 
1338*ee4a77a3SMauro Carvalho Chehab 	/* ...and give it a chance on next run */
1339*ee4a77a3SMauro Carvalho Chehab 	if (reset)
1340*ee4a77a3SMauro Carvalho Chehab 		jpu_write(ctx->jpu, JCCMD_SRST, JCCMD);
1341*ee4a77a3SMauro Carvalho Chehab 
1342*ee4a77a3SMauro Carvalho Chehab 	spin_unlock_irqrestore(&ctx->jpu->lock, flags);
1343*ee4a77a3SMauro Carvalho Chehab 
1344*ee4a77a3SMauro Carvalho Chehab 	v4l2_m2m_job_finish(ctx->jpu->m2m_dev, ctx->fh.m2m_ctx);
1345*ee4a77a3SMauro Carvalho Chehab }
1346*ee4a77a3SMauro Carvalho Chehab 
1347*ee4a77a3SMauro Carvalho Chehab static void jpu_device_run(void *priv)
1348*ee4a77a3SMauro Carvalho Chehab {
1349*ee4a77a3SMauro Carvalho Chehab 	struct jpu_ctx *ctx = priv;
1350*ee4a77a3SMauro Carvalho Chehab 	struct jpu *jpu = ctx->jpu;
1351*ee4a77a3SMauro Carvalho Chehab 	struct jpu_buffer *jpu_buf;
1352*ee4a77a3SMauro Carvalho Chehab 	struct jpu_q_data *q_data;
1353*ee4a77a3SMauro Carvalho Chehab 	struct vb2_v4l2_buffer *src_buf, *dst_buf;
1354*ee4a77a3SMauro Carvalho Chehab 	unsigned int w, h, bpl;
1355*ee4a77a3SMauro Carvalho Chehab 	unsigned char num_planes, subsampling;
1356*ee4a77a3SMauro Carvalho Chehab 	unsigned long flags;
1357*ee4a77a3SMauro Carvalho Chehab 
1358*ee4a77a3SMauro Carvalho Chehab 	/* ...wait until module reset completes; we have mutex locked here */
1359*ee4a77a3SMauro Carvalho Chehab 	if (jpu_wait_reset(jpu)) {
1360*ee4a77a3SMauro Carvalho Chehab 		jpu_cleanup(ctx, true);
1361*ee4a77a3SMauro Carvalho Chehab 		return;
1362*ee4a77a3SMauro Carvalho Chehab 	}
1363*ee4a77a3SMauro Carvalho Chehab 
1364*ee4a77a3SMauro Carvalho Chehab 	spin_lock_irqsave(&ctx->jpu->lock, flags);
1365*ee4a77a3SMauro Carvalho Chehab 
1366*ee4a77a3SMauro Carvalho Chehab 	jpu->curr = ctx;
1367*ee4a77a3SMauro Carvalho Chehab 
1368*ee4a77a3SMauro Carvalho Chehab 	src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
1369*ee4a77a3SMauro Carvalho Chehab 	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
1370*ee4a77a3SMauro Carvalho Chehab 
1371*ee4a77a3SMauro Carvalho Chehab 	if (ctx->encoder) {
1372*ee4a77a3SMauro Carvalho Chehab 		jpu_buf = vb2_to_jpu_buffer(dst_buf);
1373*ee4a77a3SMauro Carvalho Chehab 		q_data = &ctx->out_q;
1374*ee4a77a3SMauro Carvalho Chehab 	} else {
1375*ee4a77a3SMauro Carvalho Chehab 		jpu_buf = vb2_to_jpu_buffer(src_buf);
1376*ee4a77a3SMauro Carvalho Chehab 		q_data = &ctx->cap_q;
1377*ee4a77a3SMauro Carvalho Chehab 	}
1378*ee4a77a3SMauro Carvalho Chehab 
1379*ee4a77a3SMauro Carvalho Chehab 	w = q_data->format.width;
1380*ee4a77a3SMauro Carvalho Chehab 	h = q_data->format.height;
1381*ee4a77a3SMauro Carvalho Chehab 	bpl = q_data->format.plane_fmt[0].bytesperline;
1382*ee4a77a3SMauro Carvalho Chehab 	num_planes = q_data->fmtinfo->num_planes;
1383*ee4a77a3SMauro Carvalho Chehab 	subsampling = q_data->fmtinfo->subsampling;
1384*ee4a77a3SMauro Carvalho Chehab 
1385*ee4a77a3SMauro Carvalho Chehab 	if (ctx->encoder) {
1386*ee4a77a3SMauro Carvalho Chehab 		unsigned long src_1_addr, src_2_addr, dst_addr;
1387*ee4a77a3SMauro Carvalho Chehab 		unsigned int redu, inft;
1388*ee4a77a3SMauro Carvalho Chehab 
1389*ee4a77a3SMauro Carvalho Chehab 		dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
1390*ee4a77a3SMauro Carvalho Chehab 		src_1_addr =
1391*ee4a77a3SMauro Carvalho Chehab 			vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
1392*ee4a77a3SMauro Carvalho Chehab 		if (num_planes > 1)
1393*ee4a77a3SMauro Carvalho Chehab 			src_2_addr = vb2_dma_contig_plane_dma_addr(
1394*ee4a77a3SMauro Carvalho Chehab 					&src_buf->vb2_buf, 1);
1395*ee4a77a3SMauro Carvalho Chehab 		else
1396*ee4a77a3SMauro Carvalho Chehab 			src_2_addr = src_1_addr + w * h;
1397*ee4a77a3SMauro Carvalho Chehab 
1398*ee4a77a3SMauro Carvalho Chehab 		jpu_buf->compr_quality = ctx->compr_quality;
1399*ee4a77a3SMauro Carvalho Chehab 
1400*ee4a77a3SMauro Carvalho Chehab 		if (subsampling == JPU_JPEG_420) {
1401*ee4a77a3SMauro Carvalho Chehab 			redu = JCMOD_REDU_420;
1402*ee4a77a3SMauro Carvalho Chehab 			inft = JIFECNT_INFT_420;
1403*ee4a77a3SMauro Carvalho Chehab 		} else {
1404*ee4a77a3SMauro Carvalho Chehab 			redu = JCMOD_REDU_422;
1405*ee4a77a3SMauro Carvalho Chehab 			inft = JIFECNT_INFT_422;
1406*ee4a77a3SMauro Carvalho Chehab 		}
1407*ee4a77a3SMauro Carvalho Chehab 
1408*ee4a77a3SMauro Carvalho Chehab 		/* only no marker mode works for encoding */
1409*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, JCMOD_DSP_ENC | JCMOD_PCTR | redu |
1410*ee4a77a3SMauro Carvalho Chehab 			  JCMOD_MSKIP_ENABLE, JCMOD);
1411*ee4a77a3SMauro Carvalho Chehab 
1412*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, JIFECNT_SWAP_WB | inft, JIFECNT);
1413*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, JIFDCNT_SWAP_WB, JIFDCNT);
1414*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, JINTE_TRANSF_COMPL, JINTE);
1415*ee4a77a3SMauro Carvalho Chehab 
1416*ee4a77a3SMauro Carvalho Chehab 		/* Y and C components source addresses */
1417*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, src_1_addr, JIFESYA1);
1418*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, src_2_addr, JIFESCA1);
1419*ee4a77a3SMauro Carvalho Chehab 
1420*ee4a77a3SMauro Carvalho Chehab 		/* memory width */
1421*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, bpl, JIFESMW);
1422*ee4a77a3SMauro Carvalho Chehab 
1423*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, (w >> 8) & JCSZ_MASK, JCHSZU);
1424*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, w & JCSZ_MASK, JCHSZD);
1425*ee4a77a3SMauro Carvalho Chehab 
1426*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, (h >> 8) & JCSZ_MASK, JCVSZU);
1427*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, h & JCSZ_MASK, JCVSZD);
1428*ee4a77a3SMauro Carvalho Chehab 
1429*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, w, JIFESHSZ);
1430*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, h, JIFESVSZ);
1431*ee4a77a3SMauro Carvalho Chehab 
1432*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, dst_addr + JPU_JPEG_HDR_SIZE, JIFEDA1);
1433*ee4a77a3SMauro Carvalho Chehab 
1434*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, 0 << JCQTN_SHIFT(1) | 1 << JCQTN_SHIFT(2) |
1435*ee4a77a3SMauro Carvalho Chehab 			  1 << JCQTN_SHIFT(3), JCQTN);
1436*ee4a77a3SMauro Carvalho Chehab 
1437*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, 0 << JCHTN_AC_SHIFT(1) | 0 << JCHTN_DC_SHIFT(1) |
1438*ee4a77a3SMauro Carvalho Chehab 			  1 << JCHTN_AC_SHIFT(2) | 1 << JCHTN_DC_SHIFT(2) |
1439*ee4a77a3SMauro Carvalho Chehab 			  1 << JCHTN_AC_SHIFT(3) | 1 << JCHTN_DC_SHIFT(3),
1440*ee4a77a3SMauro Carvalho Chehab 			  JCHTN);
1441*ee4a77a3SMauro Carvalho Chehab 
1442*ee4a77a3SMauro Carvalho Chehab 		jpu_set_qtbl(jpu, ctx->compr_quality);
1443*ee4a77a3SMauro Carvalho Chehab 		jpu_set_htbl(jpu);
1444*ee4a77a3SMauro Carvalho Chehab 	} else {
1445*ee4a77a3SMauro Carvalho Chehab 		unsigned long src_addr, dst_1_addr, dst_2_addr;
1446*ee4a77a3SMauro Carvalho Chehab 
1447*ee4a77a3SMauro Carvalho Chehab 		if (jpu_buf->subsampling != subsampling) {
1448*ee4a77a3SMauro Carvalho Chehab 			dev_err(ctx->jpu->dev,
1449*ee4a77a3SMauro Carvalho Chehab 				"src and dst formats do not match.\n");
1450*ee4a77a3SMauro Carvalho Chehab 			spin_unlock_irqrestore(&ctx->jpu->lock, flags);
1451*ee4a77a3SMauro Carvalho Chehab 			jpu_cleanup(ctx, false);
1452*ee4a77a3SMauro Carvalho Chehab 			return;
1453*ee4a77a3SMauro Carvalho Chehab 		}
1454*ee4a77a3SMauro Carvalho Chehab 
1455*ee4a77a3SMauro Carvalho Chehab 		src_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
1456*ee4a77a3SMauro Carvalho Chehab 		dst_1_addr =
1457*ee4a77a3SMauro Carvalho Chehab 			vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
1458*ee4a77a3SMauro Carvalho Chehab 		if (q_data->fmtinfo->num_planes > 1)
1459*ee4a77a3SMauro Carvalho Chehab 			dst_2_addr = vb2_dma_contig_plane_dma_addr(
1460*ee4a77a3SMauro Carvalho Chehab 					&dst_buf->vb2_buf, 1);
1461*ee4a77a3SMauro Carvalho Chehab 		else
1462*ee4a77a3SMauro Carvalho Chehab 			dst_2_addr = dst_1_addr + w * h;
1463*ee4a77a3SMauro Carvalho Chehab 
1464*ee4a77a3SMauro Carvalho Chehab 		/* ...set up decoder operation */
1465*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, JCMOD_DSP_DEC | JCMOD_PCTR, JCMOD);
1466*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, JIFECNT_SWAP_WB, JIFECNT);
1467*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, JIFDCNT_SWAP_WB, JIFDCNT);
1468*ee4a77a3SMauro Carvalho Chehab 
1469*ee4a77a3SMauro Carvalho Chehab 		/* ...enable interrupts on transfer completion and d-g error */
1470*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, JINTE_TRANSF_COMPL | JINTE_ERR, JINTE);
1471*ee4a77a3SMauro Carvalho Chehab 
1472*ee4a77a3SMauro Carvalho Chehab 		/* ...set source/destination addresses of encoded data */
1473*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, src_addr, JIFDSA1);
1474*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, dst_1_addr, JIFDDYA1);
1475*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, dst_2_addr, JIFDDCA1);
1476*ee4a77a3SMauro Carvalho Chehab 
1477*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, bpl, JIFDDMW);
1478*ee4a77a3SMauro Carvalho Chehab 	}
1479*ee4a77a3SMauro Carvalho Chehab 
1480*ee4a77a3SMauro Carvalho Chehab 	/* ...start encoder/decoder operation */
1481*ee4a77a3SMauro Carvalho Chehab 	jpu_write(jpu, JCCMD_JSRT, JCCMD);
1482*ee4a77a3SMauro Carvalho Chehab 
1483*ee4a77a3SMauro Carvalho Chehab 	spin_unlock_irqrestore(&ctx->jpu->lock, flags);
1484*ee4a77a3SMauro Carvalho Chehab }
1485*ee4a77a3SMauro Carvalho Chehab 
1486*ee4a77a3SMauro Carvalho Chehab static const struct v4l2_m2m_ops jpu_m2m_ops = {
1487*ee4a77a3SMauro Carvalho Chehab 	.device_run	= jpu_device_run,
1488*ee4a77a3SMauro Carvalho Chehab };
1489*ee4a77a3SMauro Carvalho Chehab 
1490*ee4a77a3SMauro Carvalho Chehab /*
1491*ee4a77a3SMauro Carvalho Chehab  * ============================================================================
1492*ee4a77a3SMauro Carvalho Chehab  * IRQ handler
1493*ee4a77a3SMauro Carvalho Chehab  * ============================================================================
1494*ee4a77a3SMauro Carvalho Chehab  */
1495*ee4a77a3SMauro Carvalho Chehab static irqreturn_t jpu_irq_handler(int irq, void *dev_id)
1496*ee4a77a3SMauro Carvalho Chehab {
1497*ee4a77a3SMauro Carvalho Chehab 	struct jpu *jpu = dev_id;
1498*ee4a77a3SMauro Carvalho Chehab 	struct jpu_ctx *curr_ctx;
1499*ee4a77a3SMauro Carvalho Chehab 	struct vb2_v4l2_buffer *src_buf, *dst_buf;
1500*ee4a77a3SMauro Carvalho Chehab 	unsigned int int_status;
1501*ee4a77a3SMauro Carvalho Chehab 
1502*ee4a77a3SMauro Carvalho Chehab 	int_status = jpu_read(jpu, JINTS);
1503*ee4a77a3SMauro Carvalho Chehab 
1504*ee4a77a3SMauro Carvalho Chehab 	/* ...spurious interrupt */
1505*ee4a77a3SMauro Carvalho Chehab 	if (!((JINTS_TRANSF_COMPL | JINTS_PROCESS_COMPL | JINTS_ERR) &
1506*ee4a77a3SMauro Carvalho Chehab 	    int_status))
1507*ee4a77a3SMauro Carvalho Chehab 		return IRQ_NONE;
1508*ee4a77a3SMauro Carvalho Chehab 
1509*ee4a77a3SMauro Carvalho Chehab 	/* ...clear interrupts */
1510*ee4a77a3SMauro Carvalho Chehab 	jpu_write(jpu, ~(int_status & JINTS_MASK), JINTS);
1511*ee4a77a3SMauro Carvalho Chehab 	if (int_status & (JINTS_ERR | JINTS_PROCESS_COMPL))
1512*ee4a77a3SMauro Carvalho Chehab 		jpu_write(jpu, JCCMD_JEND, JCCMD);
1513*ee4a77a3SMauro Carvalho Chehab 
1514*ee4a77a3SMauro Carvalho Chehab 	spin_lock(&jpu->lock);
1515*ee4a77a3SMauro Carvalho Chehab 
1516*ee4a77a3SMauro Carvalho Chehab 	if ((int_status & JINTS_PROCESS_COMPL) &&
1517*ee4a77a3SMauro Carvalho Chehab 	   !(int_status & JINTS_TRANSF_COMPL))
1518*ee4a77a3SMauro Carvalho Chehab 		goto handled;
1519*ee4a77a3SMauro Carvalho Chehab 
1520*ee4a77a3SMauro Carvalho Chehab 	curr_ctx = v4l2_m2m_get_curr_priv(jpu->m2m_dev);
1521*ee4a77a3SMauro Carvalho Chehab 	if (!curr_ctx) {
1522*ee4a77a3SMauro Carvalho Chehab 		/* ...instance is not running */
1523*ee4a77a3SMauro Carvalho Chehab 		dev_err(jpu->dev, "no active context for m2m\n");
1524*ee4a77a3SMauro Carvalho Chehab 		goto handled;
1525*ee4a77a3SMauro Carvalho Chehab 	}
1526*ee4a77a3SMauro Carvalho Chehab 
1527*ee4a77a3SMauro Carvalho Chehab 	src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
1528*ee4a77a3SMauro Carvalho Chehab 	dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
1529*ee4a77a3SMauro Carvalho Chehab 
1530*ee4a77a3SMauro Carvalho Chehab 	if (int_status & JINTS_TRANSF_COMPL) {
1531*ee4a77a3SMauro Carvalho Chehab 		if (curr_ctx->encoder) {
1532*ee4a77a3SMauro Carvalho Chehab 			unsigned long payload_size = jpu_read(jpu, JCDTCU) << 16
1533*ee4a77a3SMauro Carvalho Chehab 						   | jpu_read(jpu, JCDTCM) << 8
1534*ee4a77a3SMauro Carvalho Chehab 						   | jpu_read(jpu, JCDTCD);
1535*ee4a77a3SMauro Carvalho Chehab 			vb2_set_plane_payload(&dst_buf->vb2_buf, 0,
1536*ee4a77a3SMauro Carvalho Chehab 				payload_size + JPU_JPEG_HDR_SIZE);
1537*ee4a77a3SMauro Carvalho Chehab 		}
1538*ee4a77a3SMauro Carvalho Chehab 
1539*ee4a77a3SMauro Carvalho Chehab 		dst_buf->field = src_buf->field;
1540*ee4a77a3SMauro Carvalho Chehab 		dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
1541*ee4a77a3SMauro Carvalho Chehab 		if (src_buf->flags & V4L2_BUF_FLAG_TIMECODE)
1542*ee4a77a3SMauro Carvalho Chehab 			dst_buf->timecode = src_buf->timecode;
1543*ee4a77a3SMauro Carvalho Chehab 		dst_buf->flags = src_buf->flags &
1544*ee4a77a3SMauro Carvalho Chehab 			(V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_KEYFRAME |
1545*ee4a77a3SMauro Carvalho Chehab 			 V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME |
1546*ee4a77a3SMauro Carvalho Chehab 			 V4L2_BUF_FLAG_TSTAMP_SRC_MASK);
1547*ee4a77a3SMauro Carvalho Chehab 
1548*ee4a77a3SMauro Carvalho Chehab 		v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
1549*ee4a77a3SMauro Carvalho Chehab 		v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
1550*ee4a77a3SMauro Carvalho Chehab 	} else if (int_status & JINTS_ERR) {
1551*ee4a77a3SMauro Carvalho Chehab 		unsigned char error = jpu_read(jpu, JCDERR) & JCDERR_MASK;
1552*ee4a77a3SMauro Carvalho Chehab 
1553*ee4a77a3SMauro Carvalho Chehab 		dev_dbg(jpu->dev, "processing error: %#X: %s\n", error,
1554*ee4a77a3SMauro Carvalho Chehab 			error_to_text[error]);
1555*ee4a77a3SMauro Carvalho Chehab 
1556*ee4a77a3SMauro Carvalho Chehab 		v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
1557*ee4a77a3SMauro Carvalho Chehab 		v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
1558*ee4a77a3SMauro Carvalho Chehab 	}
1559*ee4a77a3SMauro Carvalho Chehab 
1560*ee4a77a3SMauro Carvalho Chehab 	jpu->curr = NULL;
1561*ee4a77a3SMauro Carvalho Chehab 
1562*ee4a77a3SMauro Carvalho Chehab 	/* ...reset JPU after completion */
1563*ee4a77a3SMauro Carvalho Chehab 	jpu_write(jpu, JCCMD_SRST, JCCMD);
1564*ee4a77a3SMauro Carvalho Chehab 	spin_unlock(&jpu->lock);
1565*ee4a77a3SMauro Carvalho Chehab 
1566*ee4a77a3SMauro Carvalho Chehab 	v4l2_m2m_job_finish(jpu->m2m_dev, curr_ctx->fh.m2m_ctx);
1567*ee4a77a3SMauro Carvalho Chehab 
1568*ee4a77a3SMauro Carvalho Chehab 	return IRQ_HANDLED;
1569*ee4a77a3SMauro Carvalho Chehab 
1570*ee4a77a3SMauro Carvalho Chehab handled:
1571*ee4a77a3SMauro Carvalho Chehab 	spin_unlock(&jpu->lock);
1572*ee4a77a3SMauro Carvalho Chehab 	return IRQ_HANDLED;
1573*ee4a77a3SMauro Carvalho Chehab }
1574*ee4a77a3SMauro Carvalho Chehab 
1575*ee4a77a3SMauro Carvalho Chehab /*
1576*ee4a77a3SMauro Carvalho Chehab  * ============================================================================
1577*ee4a77a3SMauro Carvalho Chehab  * Driver basic infrastructure
1578*ee4a77a3SMauro Carvalho Chehab  * ============================================================================
1579*ee4a77a3SMauro Carvalho Chehab  */
1580*ee4a77a3SMauro Carvalho Chehab static const struct of_device_id jpu_dt_ids[] = {
1581*ee4a77a3SMauro Carvalho Chehab 	{ .compatible = "renesas,jpu-r8a7790" }, /* H2 */
1582*ee4a77a3SMauro Carvalho Chehab 	{ .compatible = "renesas,jpu-r8a7791" }, /* M2-W */
1583*ee4a77a3SMauro Carvalho Chehab 	{ .compatible = "renesas,jpu-r8a7792" }, /* V2H */
1584*ee4a77a3SMauro Carvalho Chehab 	{ .compatible = "renesas,jpu-r8a7793" }, /* M2-N */
1585*ee4a77a3SMauro Carvalho Chehab 	{ .compatible = "renesas,rcar-gen2-jpu" },
1586*ee4a77a3SMauro Carvalho Chehab 	{ },
1587*ee4a77a3SMauro Carvalho Chehab };
1588*ee4a77a3SMauro Carvalho Chehab MODULE_DEVICE_TABLE(of, jpu_dt_ids);
1589*ee4a77a3SMauro Carvalho Chehab 
1590*ee4a77a3SMauro Carvalho Chehab static int jpu_probe(struct platform_device *pdev)
1591*ee4a77a3SMauro Carvalho Chehab {
1592*ee4a77a3SMauro Carvalho Chehab 	struct jpu *jpu;
1593*ee4a77a3SMauro Carvalho Chehab 	int ret;
1594*ee4a77a3SMauro Carvalho Chehab 	unsigned int i;
1595*ee4a77a3SMauro Carvalho Chehab 
1596*ee4a77a3SMauro Carvalho Chehab 	jpu = devm_kzalloc(&pdev->dev, sizeof(*jpu), GFP_KERNEL);
1597*ee4a77a3SMauro Carvalho Chehab 	if (!jpu)
1598*ee4a77a3SMauro Carvalho Chehab 		return -ENOMEM;
1599*ee4a77a3SMauro Carvalho Chehab 
1600*ee4a77a3SMauro Carvalho Chehab 	mutex_init(&jpu->mutex);
1601*ee4a77a3SMauro Carvalho Chehab 	spin_lock_init(&jpu->lock);
1602*ee4a77a3SMauro Carvalho Chehab 	jpu->dev = &pdev->dev;
1603*ee4a77a3SMauro Carvalho Chehab 
1604*ee4a77a3SMauro Carvalho Chehab 	/* memory-mapped registers */
1605*ee4a77a3SMauro Carvalho Chehab 	jpu->regs = devm_platform_ioremap_resource(pdev, 0);
1606*ee4a77a3SMauro Carvalho Chehab 	if (IS_ERR(jpu->regs))
1607*ee4a77a3SMauro Carvalho Chehab 		return PTR_ERR(jpu->regs);
1608*ee4a77a3SMauro Carvalho Chehab 
1609*ee4a77a3SMauro Carvalho Chehab 	/* interrupt service routine registration */
1610*ee4a77a3SMauro Carvalho Chehab 	jpu->irq = ret = platform_get_irq(pdev, 0);
1611*ee4a77a3SMauro Carvalho Chehab 	if (ret < 0) {
1612*ee4a77a3SMauro Carvalho Chehab 		dev_err(&pdev->dev, "cannot find IRQ\n");
1613*ee4a77a3SMauro Carvalho Chehab 		return ret;
1614*ee4a77a3SMauro Carvalho Chehab 	}
1615*ee4a77a3SMauro Carvalho Chehab 
1616*ee4a77a3SMauro Carvalho Chehab 	ret = devm_request_irq(&pdev->dev, jpu->irq, jpu_irq_handler, 0,
1617*ee4a77a3SMauro Carvalho Chehab 			       dev_name(&pdev->dev), jpu);
1618*ee4a77a3SMauro Carvalho Chehab 	if (ret) {
1619*ee4a77a3SMauro Carvalho Chehab 		dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpu->irq);
1620*ee4a77a3SMauro Carvalho Chehab 		return ret;
1621*ee4a77a3SMauro Carvalho Chehab 	}
1622*ee4a77a3SMauro Carvalho Chehab 
1623*ee4a77a3SMauro Carvalho Chehab 	/* clocks */
1624*ee4a77a3SMauro Carvalho Chehab 	jpu->clk = devm_clk_get(&pdev->dev, NULL);
1625*ee4a77a3SMauro Carvalho Chehab 	if (IS_ERR(jpu->clk)) {
1626*ee4a77a3SMauro Carvalho Chehab 		dev_err(&pdev->dev, "cannot get clock\n");
1627*ee4a77a3SMauro Carvalho Chehab 		return PTR_ERR(jpu->clk);
1628*ee4a77a3SMauro Carvalho Chehab 	}
1629*ee4a77a3SMauro Carvalho Chehab 
1630*ee4a77a3SMauro Carvalho Chehab 	/* v4l2 device */
1631*ee4a77a3SMauro Carvalho Chehab 	ret = v4l2_device_register(&pdev->dev, &jpu->v4l2_dev);
1632*ee4a77a3SMauro Carvalho Chehab 	if (ret) {
1633*ee4a77a3SMauro Carvalho Chehab 		dev_err(&pdev->dev, "Failed to register v4l2 device\n");
1634*ee4a77a3SMauro Carvalho Chehab 		return ret;
1635*ee4a77a3SMauro Carvalho Chehab 	}
1636*ee4a77a3SMauro Carvalho Chehab 
1637*ee4a77a3SMauro Carvalho Chehab 	/* mem2mem device */
1638*ee4a77a3SMauro Carvalho Chehab 	jpu->m2m_dev = v4l2_m2m_init(&jpu_m2m_ops);
1639*ee4a77a3SMauro Carvalho Chehab 	if (IS_ERR(jpu->m2m_dev)) {
1640*ee4a77a3SMauro Carvalho Chehab 		v4l2_err(&jpu->v4l2_dev, "Failed to init mem2mem device\n");
1641*ee4a77a3SMauro Carvalho Chehab 		ret = PTR_ERR(jpu->m2m_dev);
1642*ee4a77a3SMauro Carvalho Chehab 		goto device_register_rollback;
1643*ee4a77a3SMauro Carvalho Chehab 	}
1644*ee4a77a3SMauro Carvalho Chehab 
1645*ee4a77a3SMauro Carvalho Chehab 	/* fill in quantization and Huffman tables for encoder */
1646*ee4a77a3SMauro Carvalho Chehab 	for (i = 0; i < JPU_MAX_QUALITY; i++)
1647*ee4a77a3SMauro Carvalho Chehab 		jpu_generate_hdr(i, (unsigned char *)jpeg_hdrs[i]);
1648*ee4a77a3SMauro Carvalho Chehab 
1649*ee4a77a3SMauro Carvalho Chehab 	strscpy(jpu->vfd_encoder.name, DRV_NAME, sizeof(jpu->vfd_encoder.name));
1650*ee4a77a3SMauro Carvalho Chehab 	jpu->vfd_encoder.fops		= &jpu_fops;
1651*ee4a77a3SMauro Carvalho Chehab 	jpu->vfd_encoder.ioctl_ops	= &jpu_ioctl_ops;
1652*ee4a77a3SMauro Carvalho Chehab 	jpu->vfd_encoder.minor		= -1;
1653*ee4a77a3SMauro Carvalho Chehab 	jpu->vfd_encoder.release	= video_device_release_empty;
1654*ee4a77a3SMauro Carvalho Chehab 	jpu->vfd_encoder.lock		= &jpu->mutex;
1655*ee4a77a3SMauro Carvalho Chehab 	jpu->vfd_encoder.v4l2_dev	= &jpu->v4l2_dev;
1656*ee4a77a3SMauro Carvalho Chehab 	jpu->vfd_encoder.vfl_dir	= VFL_DIR_M2M;
1657*ee4a77a3SMauro Carvalho Chehab 	jpu->vfd_encoder.device_caps	= V4L2_CAP_STREAMING |
1658*ee4a77a3SMauro Carvalho Chehab 					  V4L2_CAP_VIDEO_M2M_MPLANE;
1659*ee4a77a3SMauro Carvalho Chehab 
1660*ee4a77a3SMauro Carvalho Chehab 	ret = video_register_device(&jpu->vfd_encoder, VFL_TYPE_VIDEO, -1);
1661*ee4a77a3SMauro Carvalho Chehab 	if (ret) {
1662*ee4a77a3SMauro Carvalho Chehab 		v4l2_err(&jpu->v4l2_dev, "Failed to register video device\n");
1663*ee4a77a3SMauro Carvalho Chehab 		goto m2m_init_rollback;
1664*ee4a77a3SMauro Carvalho Chehab 	}
1665*ee4a77a3SMauro Carvalho Chehab 
1666*ee4a77a3SMauro Carvalho Chehab 	video_set_drvdata(&jpu->vfd_encoder, jpu);
1667*ee4a77a3SMauro Carvalho Chehab 
1668*ee4a77a3SMauro Carvalho Chehab 	strscpy(jpu->vfd_decoder.name, DRV_NAME, sizeof(jpu->vfd_decoder.name));
1669*ee4a77a3SMauro Carvalho Chehab 	jpu->vfd_decoder.fops		= &jpu_fops;
1670*ee4a77a3SMauro Carvalho Chehab 	jpu->vfd_decoder.ioctl_ops	= &jpu_ioctl_ops;
1671*ee4a77a3SMauro Carvalho Chehab 	jpu->vfd_decoder.minor		= -1;
1672*ee4a77a3SMauro Carvalho Chehab 	jpu->vfd_decoder.release	= video_device_release_empty;
1673*ee4a77a3SMauro Carvalho Chehab 	jpu->vfd_decoder.lock		= &jpu->mutex;
1674*ee4a77a3SMauro Carvalho Chehab 	jpu->vfd_decoder.v4l2_dev	= &jpu->v4l2_dev;
1675*ee4a77a3SMauro Carvalho Chehab 	jpu->vfd_decoder.vfl_dir	= VFL_DIR_M2M;
1676*ee4a77a3SMauro Carvalho Chehab 	jpu->vfd_decoder.device_caps	= V4L2_CAP_STREAMING |
1677*ee4a77a3SMauro Carvalho Chehab 					  V4L2_CAP_VIDEO_M2M_MPLANE;
1678*ee4a77a3SMauro Carvalho Chehab 
1679*ee4a77a3SMauro Carvalho Chehab 	ret = video_register_device(&jpu->vfd_decoder, VFL_TYPE_VIDEO, -1);
1680*ee4a77a3SMauro Carvalho Chehab 	if (ret) {
1681*ee4a77a3SMauro Carvalho Chehab 		v4l2_err(&jpu->v4l2_dev, "Failed to register video device\n");
1682*ee4a77a3SMauro Carvalho Chehab 		goto enc_vdev_register_rollback;
1683*ee4a77a3SMauro Carvalho Chehab 	}
1684*ee4a77a3SMauro Carvalho Chehab 
1685*ee4a77a3SMauro Carvalho Chehab 	video_set_drvdata(&jpu->vfd_decoder, jpu);
1686*ee4a77a3SMauro Carvalho Chehab 	platform_set_drvdata(pdev, jpu);
1687*ee4a77a3SMauro Carvalho Chehab 
1688*ee4a77a3SMauro Carvalho Chehab 	v4l2_info(&jpu->v4l2_dev, "encoder device registered as /dev/video%d\n",
1689*ee4a77a3SMauro Carvalho Chehab 		  jpu->vfd_encoder.num);
1690*ee4a77a3SMauro Carvalho Chehab 	v4l2_info(&jpu->v4l2_dev, "decoder device registered as /dev/video%d\n",
1691*ee4a77a3SMauro Carvalho Chehab 		  jpu->vfd_decoder.num);
1692*ee4a77a3SMauro Carvalho Chehab 
1693*ee4a77a3SMauro Carvalho Chehab 	return 0;
1694*ee4a77a3SMauro Carvalho Chehab 
1695*ee4a77a3SMauro Carvalho Chehab enc_vdev_register_rollback:
1696*ee4a77a3SMauro Carvalho Chehab 	video_unregister_device(&jpu->vfd_encoder);
1697*ee4a77a3SMauro Carvalho Chehab 
1698*ee4a77a3SMauro Carvalho Chehab m2m_init_rollback:
1699*ee4a77a3SMauro Carvalho Chehab 	v4l2_m2m_release(jpu->m2m_dev);
1700*ee4a77a3SMauro Carvalho Chehab 
1701*ee4a77a3SMauro Carvalho Chehab device_register_rollback:
1702*ee4a77a3SMauro Carvalho Chehab 	v4l2_device_unregister(&jpu->v4l2_dev);
1703*ee4a77a3SMauro Carvalho Chehab 
1704*ee4a77a3SMauro Carvalho Chehab 	return ret;
1705*ee4a77a3SMauro Carvalho Chehab }
1706*ee4a77a3SMauro Carvalho Chehab 
1707*ee4a77a3SMauro Carvalho Chehab static int jpu_remove(struct platform_device *pdev)
1708*ee4a77a3SMauro Carvalho Chehab {
1709*ee4a77a3SMauro Carvalho Chehab 	struct jpu *jpu = platform_get_drvdata(pdev);
1710*ee4a77a3SMauro Carvalho Chehab 
1711*ee4a77a3SMauro Carvalho Chehab 	video_unregister_device(&jpu->vfd_decoder);
1712*ee4a77a3SMauro Carvalho Chehab 	video_unregister_device(&jpu->vfd_encoder);
1713*ee4a77a3SMauro Carvalho Chehab 	v4l2_m2m_release(jpu->m2m_dev);
1714*ee4a77a3SMauro Carvalho Chehab 	v4l2_device_unregister(&jpu->v4l2_dev);
1715*ee4a77a3SMauro Carvalho Chehab 
1716*ee4a77a3SMauro Carvalho Chehab 	return 0;
1717*ee4a77a3SMauro Carvalho Chehab }
1718*ee4a77a3SMauro Carvalho Chehab 
1719*ee4a77a3SMauro Carvalho Chehab #ifdef CONFIG_PM_SLEEP
1720*ee4a77a3SMauro Carvalho Chehab static int jpu_suspend(struct device *dev)
1721*ee4a77a3SMauro Carvalho Chehab {
1722*ee4a77a3SMauro Carvalho Chehab 	struct jpu *jpu = dev_get_drvdata(dev);
1723*ee4a77a3SMauro Carvalho Chehab 
1724*ee4a77a3SMauro Carvalho Chehab 	if (jpu->ref_count == 0)
1725*ee4a77a3SMauro Carvalho Chehab 		return 0;
1726*ee4a77a3SMauro Carvalho Chehab 
1727*ee4a77a3SMauro Carvalho Chehab 	clk_disable_unprepare(jpu->clk);
1728*ee4a77a3SMauro Carvalho Chehab 
1729*ee4a77a3SMauro Carvalho Chehab 	return 0;
1730*ee4a77a3SMauro Carvalho Chehab }
1731*ee4a77a3SMauro Carvalho Chehab 
1732*ee4a77a3SMauro Carvalho Chehab static int jpu_resume(struct device *dev)
1733*ee4a77a3SMauro Carvalho Chehab {
1734*ee4a77a3SMauro Carvalho Chehab 	struct jpu *jpu = dev_get_drvdata(dev);
1735*ee4a77a3SMauro Carvalho Chehab 
1736*ee4a77a3SMauro Carvalho Chehab 	if (jpu->ref_count == 0)
1737*ee4a77a3SMauro Carvalho Chehab 		return 0;
1738*ee4a77a3SMauro Carvalho Chehab 
1739*ee4a77a3SMauro Carvalho Chehab 	clk_prepare_enable(jpu->clk);
1740*ee4a77a3SMauro Carvalho Chehab 
1741*ee4a77a3SMauro Carvalho Chehab 	return 0;
1742*ee4a77a3SMauro Carvalho Chehab }
1743*ee4a77a3SMauro Carvalho Chehab #endif
1744*ee4a77a3SMauro Carvalho Chehab 
1745*ee4a77a3SMauro Carvalho Chehab static const struct dev_pm_ops jpu_pm_ops = {
1746*ee4a77a3SMauro Carvalho Chehab 	SET_SYSTEM_SLEEP_PM_OPS(jpu_suspend, jpu_resume)
1747*ee4a77a3SMauro Carvalho Chehab };
1748*ee4a77a3SMauro Carvalho Chehab 
1749*ee4a77a3SMauro Carvalho Chehab static struct platform_driver jpu_driver = {
1750*ee4a77a3SMauro Carvalho Chehab 	.probe = jpu_probe,
1751*ee4a77a3SMauro Carvalho Chehab 	.remove = jpu_remove,
1752*ee4a77a3SMauro Carvalho Chehab 	.driver = {
1753*ee4a77a3SMauro Carvalho Chehab 		.of_match_table = jpu_dt_ids,
1754*ee4a77a3SMauro Carvalho Chehab 		.name = DRV_NAME,
1755*ee4a77a3SMauro Carvalho Chehab 		.pm = &jpu_pm_ops,
1756*ee4a77a3SMauro Carvalho Chehab 	},
1757*ee4a77a3SMauro Carvalho Chehab };
1758*ee4a77a3SMauro Carvalho Chehab 
1759*ee4a77a3SMauro Carvalho Chehab module_platform_driver(jpu_driver);
1760*ee4a77a3SMauro Carvalho Chehab 
1761*ee4a77a3SMauro Carvalho Chehab MODULE_ALIAS("platform:" DRV_NAME);
1762*ee4a77a3SMauro Carvalho Chehab MODULE_AUTHOR("Mikhail Ulianov <mikhail.ulyanov@cogentembedded.com>");
1763*ee4a77a3SMauro Carvalho Chehab MODULE_DESCRIPTION("Renesas R-Car JPEG processing unit driver");
1764*ee4a77a3SMauro Carvalho Chehab MODULE_LICENSE("GPL v2");
1765