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