blob: 73698cc26dd504a7b9171b4f07778b765973ad49 [file] [log] [blame]
Thomas Gleixnerc942fdd2019-05-27 08:55:06 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Ben Collinsfaa4fd22010-06-17 13:27:26 -04002/*
Hans Verkuildcae5da2013-03-25 05:35:17 -03003 * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
4 *
5 * Original author:
6 * Ben Collins <bcollins@ubuntu.com>
7 *
8 * Additional work by:
9 * John Brooks <john.brooks@bluecherry.net>
Ben Collinsfaa4fd22010-06-17 13:27:26 -040010 */
11
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/kthread.h>
15#include <linux/freezer.h>
Hans Verkuildcae5da2013-03-25 05:35:17 -030016
Ben Collinsfaa4fd22010-06-17 13:27:26 -040017#include <media/v4l2-ioctl.h>
18#include <media/v4l2-common.h>
Hans Verkuil94160492013-03-12 18:47:03 -030019#include <media/v4l2-event.h>
Hans Verkuil382c31a2013-03-15 12:04:14 -030020#include <media/videobuf2-dma-sg.h>
Hans Verkuildcae5da2013-03-25 05:35:17 -030021
Krzysztof Hałasaae69b222011-02-11 13:36:27 +010022#include "solo6x10.h"
Hans Verkuildad7fab2013-03-25 05:42:46 -030023#include "solo6x10-tw28.h"
Hans Verkuilb3c7d452011-11-03 06:57:08 -030024#include "solo6x10-jpeg.h"
Ben Collinsfaa4fd22010-06-17 13:27:26 -040025
Hans Verkuildcae5da2013-03-25 05:35:17 -030026#define MIN_VID_BUFFERS 2
Andrey Utkine34f2a92016-07-09 21:44:50 -030027#define FRAME_BUF_SIZE (400 * 1024)
Ben Collinsfaa4fd22010-06-17 13:27:26 -040028#define MP4_QS 16
Hans Verkuildcae5da2013-03-25 05:35:17 -030029#define DMA_ALIGN 4096
Ben Collinsfaa4fd22010-06-17 13:27:26 -040030
Hans Verkuildcae5da2013-03-25 05:35:17 -030031/* 6010 M4V */
Ismael Luceno8a4d9a92014-12-24 08:35:59 -030032static u8 vop_6010_ntsc_d1[] = {
Hans Verkuildcae5da2013-03-25 05:35:17 -030033 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
34 0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40,
35 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
36 0x1f, 0x4c, 0x58, 0x10, 0xf0, 0x71, 0x18, 0x3f,
37};
38
Ismael Luceno8a4d9a92014-12-24 08:35:59 -030039static u8 vop_6010_ntsc_cif[] = {
Hans Verkuildcae5da2013-03-25 05:35:17 -030040 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
41 0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40,
42 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
43 0x1f, 0x4c, 0x2c, 0x10, 0x78, 0x51, 0x18, 0x3f,
44};
45
Ismael Luceno8a4d9a92014-12-24 08:35:59 -030046static u8 vop_6010_pal_d1[] = {
Hans Verkuildcae5da2013-03-25 05:35:17 -030047 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
48 0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40,
49 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
50 0x1f, 0x4c, 0x58, 0x11, 0x20, 0x71, 0x18, 0x3f,
51};
52
Ismael Luceno8a4d9a92014-12-24 08:35:59 -030053static u8 vop_6010_pal_cif[] = {
Hans Verkuildcae5da2013-03-25 05:35:17 -030054 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
55 0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40,
56 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
57 0x1f, 0x4c, 0x2c, 0x10, 0x90, 0x51, 0x18, 0x3f,
58};
59
60/* 6110 h.264 */
Ismael Luceno8a4d9a92014-12-24 08:35:59 -030061static u8 vop_6110_ntsc_d1[] = {
Hans Verkuildcae5da2013-03-25 05:35:17 -030062 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
63 0x9a, 0x74, 0x05, 0x81, 0xec, 0x80, 0x00, 0x00,
64 0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00,
65};
66
Ismael Luceno8a4d9a92014-12-24 08:35:59 -030067static u8 vop_6110_ntsc_cif[] = {
Hans Verkuildcae5da2013-03-25 05:35:17 -030068 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
69 0x9a, 0x74, 0x0b, 0x0f, 0xc8, 0x00, 0x00, 0x00,
70 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00,
71};
72
Ismael Luceno8a4d9a92014-12-24 08:35:59 -030073static u8 vop_6110_pal_d1[] = {
Hans Verkuildcae5da2013-03-25 05:35:17 -030074 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
75 0x9a, 0x74, 0x05, 0x80, 0x93, 0x20, 0x00, 0x00,
76 0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00,
77};
78
Ismael Luceno8a4d9a92014-12-24 08:35:59 -030079static u8 vop_6110_pal_cif[] = {
Hans Verkuildcae5da2013-03-25 05:35:17 -030080 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
81 0x9a, 0x74, 0x0b, 0x04, 0xb2, 0x00, 0x00, 0x00,
82 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00,
83};
84
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -030085typedef __le32 vop_header[16];
Hans Verkuildcae5da2013-03-25 05:35:17 -030086
87struct solo_enc_buf {
88 enum solo_enc_types type;
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -030089 const vop_header *vh;
Hans Verkuildcae5da2013-03-25 05:35:17 -030090 int motion;
91};
92
Ben Collinsfaa4fd22010-06-17 13:27:26 -040093static int solo_is_motion_on(struct solo_enc_dev *solo_enc)
94{
Krzysztof Hałasadecebab2011-02-11 13:38:20 +010095 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -040096
Hans Verkuildcae5da2013-03-25 05:35:17 -030097 return (solo_dev->motion_mask >> solo_enc->ch) & 1;
98}
99
100static int solo_motion_detected(struct solo_enc_dev *solo_enc)
101{
102 struct solo_dev *solo_dev = solo_enc->solo_dev;
103 unsigned long flags;
104 u32 ch_mask = 1 << solo_enc->ch;
105 int ret = 0;
106
107 spin_lock_irqsave(&solo_enc->motion_lock, flags);
108 if (solo_reg_read(solo_dev, SOLO_VI_MOT_STATUS) & ch_mask) {
109 solo_reg_write(solo_dev, SOLO_VI_MOT_CLEAR, ch_mask);
110 ret = 1;
111 }
112 spin_unlock_irqrestore(&solo_enc->motion_lock, flags);
113
114 return ret;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400115}
116
117static void solo_motion_toggle(struct solo_enc_dev *solo_enc, int on)
118{
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100119 struct solo_dev *solo_dev = solo_enc->solo_dev;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300120 u32 mask = 1 << solo_enc->ch;
121 unsigned long flags;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400122
Hans Verkuildcae5da2013-03-25 05:35:17 -0300123 spin_lock_irqsave(&solo_enc->motion_lock, flags);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400124
125 if (on)
Hans Verkuildcae5da2013-03-25 05:35:17 -0300126 solo_dev->motion_mask |= mask;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400127 else
Hans Verkuildcae5da2013-03-25 05:35:17 -0300128 solo_dev->motion_mask &= ~mask;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400129
Hans Verkuildcae5da2013-03-25 05:35:17 -0300130 solo_reg_write(solo_dev, SOLO_VI_MOT_CLEAR, mask);
Ben Collinsf62de9b2010-11-04 22:51:17 -0400131
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400132 solo_reg_write(solo_dev, SOLO_VI_MOT_ADR,
133 SOLO_VI_MOTION_EN(solo_dev->motion_mask) |
134 (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
135
Hans Verkuildcae5da2013-03-25 05:35:17 -0300136 spin_unlock_irqrestore(&solo_enc->motion_lock, flags);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400137}
138
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300139void solo_update_mode(struct solo_enc_dev *solo_enc)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400140{
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100141 struct solo_dev *solo_dev = solo_enc->solo_dev;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300142 int vop_len;
Ismael Luceno8a4d9a92014-12-24 08:35:59 -0300143 u8 *vop;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400144
145 solo_enc->interlaced = (solo_enc->mode & 0x08) ? 1 : 0;
146 solo_enc->bw_weight = max(solo_dev->fps / solo_enc->interval, 1);
147
Hans Verkuildcae5da2013-03-25 05:35:17 -0300148 if (solo_enc->mode == SOLO_ENC_MODE_CIF) {
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400149 solo_enc->width = solo_dev->video_hsize >> 1;
150 solo_enc->height = solo_dev->video_vsize;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300151 if (solo_dev->type == SOLO_DEV_6110) {
152 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
153 vop = vop_6110_ntsc_cif;
154 vop_len = sizeof(vop_6110_ntsc_cif);
155 } else {
156 vop = vop_6110_pal_cif;
157 vop_len = sizeof(vop_6110_pal_cif);
158 }
159 } else {
160 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
161 vop = vop_6010_ntsc_cif;
162 vop_len = sizeof(vop_6010_ntsc_cif);
163 } else {
164 vop = vop_6010_pal_cif;
165 vop_len = sizeof(vop_6010_pal_cif);
166 }
167 }
168 } else {
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400169 solo_enc->width = solo_dev->video_hsize;
170 solo_enc->height = solo_dev->video_vsize << 1;
171 solo_enc->bw_weight <<= 2;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300172 if (solo_dev->type == SOLO_DEV_6110) {
173 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
174 vop = vop_6110_ntsc_d1;
175 vop_len = sizeof(vop_6110_ntsc_d1);
176 } else {
177 vop = vop_6110_pal_d1;
178 vop_len = sizeof(vop_6110_pal_d1);
179 }
180 } else {
181 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
182 vop = vop_6010_ntsc_d1;
183 vop_len = sizeof(vop_6010_ntsc_d1);
184 } else {
185 vop = vop_6010_pal_d1;
186 vop_len = sizeof(vop_6010_pal_d1);
187 }
188 }
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400189 }
Hans Verkuildcae5da2013-03-25 05:35:17 -0300190
191 memcpy(solo_enc->vop, vop, vop_len);
192
193 /* Some fixups for 6010/M4V */
194 if (solo_dev->type == SOLO_DEV_6010) {
195 u16 fps = solo_dev->fps * 1000;
196 u16 interval = solo_enc->interval * 1000;
197
198 vop = solo_enc->vop;
199
200 /* Frame rate and interval */
201 vop[22] = fps >> 4;
202 vop[23] = ((fps << 4) & 0xf0) | 0x0c
203 | ((interval >> 13) & 0x3);
204 vop[24] = (interval >> 5) & 0xff;
205 vop[25] = ((interval << 3) & 0xf8) | 0x04;
206 }
207
208 solo_enc->vop_len = vop_len;
209
210 /* Now handle the jpeg header */
211 vop = solo_enc->jpeg_header;
212 vop[SOF0_START + 5] = 0xff & (solo_enc->height >> 8);
213 vop[SOF0_START + 6] = 0xff & solo_enc->height;
214 vop[SOF0_START + 7] = 0xff & (solo_enc->width >> 8);
215 vop[SOF0_START + 8] = 0xff & solo_enc->width;
216
217 memcpy(vop + DQT_START,
218 jpeg_dqt[solo_g_jpeg_qp(solo_dev, solo_enc->ch)], DQT_LEN);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400219}
220
Hans Verkuil382c31a2013-03-15 12:04:14 -0300221static int solo_enc_on(struct solo_enc_dev *solo_enc)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400222{
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400223 u8 ch = solo_enc->ch;
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100224 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400225 u8 interval;
226
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400227 solo_update_mode(solo_enc);
228
Hans Verkuil382c31a2013-03-15 12:04:14 -0300229 /* Make sure to do a bandwidth check */
230 if (solo_enc->bw_weight > solo_dev->enc_bw_remain)
231 return -EBUSY;
Hans Verkuil15513c12013-03-15 13:16:49 -0300232 solo_enc->sequence = 0;
Hans Verkuil382c31a2013-03-15 12:04:14 -0300233 solo_dev->enc_bw_remain -= solo_enc->bw_weight;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400234
Hans Verkuila7eb9312013-03-18 08:41:13 -0300235 if (solo_enc->type == SOLO_ENC_TYPE_EXT)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400236 solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(ch), 1);
237
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400238 /* Disable all encoding for this channel */
239 solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), 0);
240
241 /* Common for both std and ext encoding */
242 solo_reg_write(solo_dev, SOLO_VE_CH_INTL(ch),
243 solo_enc->interlaced ? 1 : 0);
244
245 if (solo_enc->interlaced)
246 interval = solo_enc->interval - 1;
247 else
248 interval = solo_enc->interval;
249
250 /* Standard encoding only */
251 solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), solo_enc->gop);
252 solo_reg_write(solo_dev, SOLO_VE_CH_QP(ch), solo_enc->qp);
253 solo_reg_write(solo_dev, SOLO_CAP_CH_INTV(ch), interval);
254
255 /* Extended encoding only */
256 solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(ch), solo_enc->gop);
257 solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(ch), solo_enc->qp);
258 solo_reg_write(solo_dev, SOLO_CAP_CH_INTV_E(ch), interval);
259
260 /* Enables the standard encoder */
261 solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), solo_enc->mode);
262
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400263 return 0;
264}
265
Hans Verkuil382c31a2013-03-15 12:04:14 -0300266static void solo_enc_off(struct solo_enc_dev *solo_enc)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400267{
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100268 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400269
Hans Verkuildcae5da2013-03-25 05:35:17 -0300270 solo_dev->enc_bw_remain += solo_enc->bw_weight;
271
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400272 solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(solo_enc->ch), 0);
273 solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0);
274}
275
Hans Verkuildcae5da2013-03-25 05:35:17 -0300276static int enc_get_mpeg_dma(struct solo_dev *solo_dev, dma_addr_t dma,
277 unsigned int off, unsigned int size)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400278{
279 int ret;
280
281 if (off > SOLO_MP4E_EXT_SIZE(solo_dev))
282 return -EINVAL;
283
Hans Verkuildcae5da2013-03-25 05:35:17 -0300284 /* Single shot */
Ben Collinsf62de9b2010-11-04 22:51:17 -0400285 if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) {
Hans Verkuildcae5da2013-03-25 05:35:17 -0300286 return solo_p2m_dma_t(solo_dev, 0, dma,
287 SOLO_MP4E_EXT_ADDR(solo_dev) + off, size,
288 0, 0);
Ben Collinsf62de9b2010-11-04 22:51:17 -0400289 }
290
291 /* Buffer wrap */
Hans Verkuildcae5da2013-03-25 05:35:17 -0300292 ret = solo_p2m_dma_t(solo_dev, 0, dma,
Ben Collinsf62de9b2010-11-04 22:51:17 -0400293 SOLO_MP4E_EXT_ADDR(solo_dev) + off,
Hans Verkuildcae5da2013-03-25 05:35:17 -0300294 SOLO_MP4E_EXT_SIZE(solo_dev) - off, 0, 0);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400295
Hans Verkuildcae5da2013-03-25 05:35:17 -0300296 if (!ret) {
297 ret = solo_p2m_dma_t(solo_dev, 0,
298 dma + SOLO_MP4E_EXT_SIZE(solo_dev) - off,
299 SOLO_MP4E_EXT_ADDR(solo_dev),
300 size + off - SOLO_MP4E_EXT_SIZE(solo_dev), 0, 0);
Ben Collinsf62de9b2010-11-04 22:51:17 -0400301 }
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400302
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400303 return ret;
304}
305
Hans Verkuildcae5da2013-03-25 05:35:17 -0300306/* Build a descriptor queue out of an SG list and send it to the P2M for
307 * processing. */
Hans Verkuila7eb9312013-03-18 08:41:13 -0300308static int solo_send_desc(struct solo_enc_dev *solo_enc, int skip,
Ricardo Ribalda22301242013-08-02 10:20:00 -0300309 struct sg_table *vbuf, int off, int size,
Hans Verkuildcae5da2013-03-25 05:35:17 -0300310 unsigned int base, unsigned int base_size)
Ben Collinsf62de9b2010-11-04 22:51:17 -0400311{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300312 struct solo_dev *solo_dev = solo_enc->solo_dev;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300313 struct scatterlist *sg;
314 int i;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400315 int ret;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400316
Hans Verkuildcae5da2013-03-25 05:35:17 -0300317 if (WARN_ON_ONCE(size > FRAME_BUF_SIZE))
Ben Collinsf62de9b2010-11-04 22:51:17 -0400318 return -EINVAL;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400319
Hans Verkuila7eb9312013-03-18 08:41:13 -0300320 solo_enc->desc_count = 1;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400321
Ricardo Ribalda22301242013-08-02 10:20:00 -0300322 for_each_sg(vbuf->sgl, sg, vbuf->nents, i) {
Hans Verkuildcae5da2013-03-25 05:35:17 -0300323 struct solo_p2m_desc *desc;
324 dma_addr_t dma;
325 int len;
326 int left = base_size - off;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400327
Hans Verkuila7eb9312013-03-18 08:41:13 -0300328 desc = &solo_enc->desc_items[solo_enc->desc_count++];
Hans Verkuildcae5da2013-03-25 05:35:17 -0300329 dma = sg_dma_address(sg);
330 len = sg_dma_len(sg);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400331
Hans Verkuildcae5da2013-03-25 05:35:17 -0300332 /* We assume this is smaller than the scatter size */
333 BUG_ON(skip >= len);
334 if (skip) {
335 len -= skip;
336 dma += skip;
337 size -= skip;
338 skip = 0;
339 }
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400340
Hans Verkuildcae5da2013-03-25 05:35:17 -0300341 len = min(len, size);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400342
Hans Verkuildcae5da2013-03-25 05:35:17 -0300343 if (len <= left) {
344 /* Single descriptor */
345 solo_p2m_fill_desc(desc, 0, dma, base + off,
346 len, 0, 0);
Ben Collinsf62de9b2010-11-04 22:51:17 -0400347 } else {
Hans Verkuildcae5da2013-03-25 05:35:17 -0300348 /* Buffer wrap */
349 /* XXX: Do these as separate DMA requests, to avoid
350 timeout errors triggered by awkwardly sized
351 descriptors. See
352 <https://github.com/bluecherrydvr/solo6x10/issues/8>
353 */
354 ret = solo_p2m_dma_t(solo_dev, 0, dma, base + off,
355 left, 0, 0);
356 if (ret)
357 return ret;
358
359 ret = solo_p2m_dma_t(solo_dev, 0, dma + left, base,
360 len - left, 0, 0);
361 if (ret)
362 return ret;
363
Hans Verkuila7eb9312013-03-18 08:41:13 -0300364 solo_enc->desc_count--;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300365 }
366
367 size -= len;
368 if (size <= 0)
369 break;
370
371 off += len;
372 if (off >= base_size)
373 off -= base_size;
374
375 /* Because we may use two descriptors per loop */
Hans Verkuila7eb9312013-03-18 08:41:13 -0300376 if (solo_enc->desc_count >= (solo_enc->desc_nelts - 1)) {
377 ret = solo_p2m_dma_desc(solo_dev, solo_enc->desc_items,
378 solo_enc->desc_dma,
379 solo_enc->desc_count - 1);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300380 if (ret)
381 return ret;
Hans Verkuila7eb9312013-03-18 08:41:13 -0300382 solo_enc->desc_count = 1;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400383 }
384 }
385
Hans Verkuila7eb9312013-03-18 08:41:13 -0300386 if (solo_enc->desc_count <= 1)
Hans Verkuildcae5da2013-03-25 05:35:17 -0300387 return 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400388
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200389 return solo_p2m_dma_desc(solo_dev, solo_enc->desc_items,
390 solo_enc->desc_dma, solo_enc->desc_count - 1);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400391}
392
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300393/* Extract values from VOP header - VE_STATUSxx */
394static inline int vop_interlaced(const vop_header *vh)
395{
396 return (__le32_to_cpu((*vh)[0]) >> 30) & 1;
397}
398
399static inline u8 vop_channel(const vop_header *vh)
400{
401 return (__le32_to_cpu((*vh)[0]) >> 24) & 0x1F;
402}
403
404static inline u8 vop_type(const vop_header *vh)
405{
406 return (__le32_to_cpu((*vh)[0]) >> 22) & 3;
407}
408
409static inline u32 vop_mpeg_size(const vop_header *vh)
410{
411 return __le32_to_cpu((*vh)[0]) & 0xFFFFF;
412}
413
414static inline u8 vop_hsize(const vop_header *vh)
415{
416 return (__le32_to_cpu((*vh)[1]) >> 8) & 0xFF;
417}
418
419static inline u8 vop_vsize(const vop_header *vh)
420{
421 return __le32_to_cpu((*vh)[1]) & 0xFF;
422}
423
424static inline u32 vop_mpeg_offset(const vop_header *vh)
425{
426 return __le32_to_cpu((*vh)[2]);
427}
428
429static inline u32 vop_jpeg_offset(const vop_header *vh)
430{
431 return __le32_to_cpu((*vh)[3]);
432}
433
434static inline u32 vop_jpeg_size(const vop_header *vh)
435{
436 return __le32_to_cpu((*vh)[4]) & 0xFFFFF;
437}
438
439static inline u32 vop_sec(const vop_header *vh)
440{
441 return __le32_to_cpu((*vh)[5]);
442}
443
444static inline u32 vop_usec(const vop_header *vh)
445{
446 return __le32_to_cpu((*vh)[6]);
447}
448
Hans Verkuil382c31a2013-03-15 12:04:14 -0300449static int solo_fill_jpeg(struct solo_enc_dev *solo_enc,
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300450 struct vb2_buffer *vb, const vop_header *vh)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400451{
Junghak Sung2d700712015-09-22 10:30:30 -0300452 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100453 struct solo_dev *solo_dev = solo_enc->solo_dev;
Junghak Sung2d700712015-09-22 10:30:30 -0300454 struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300455 int frame_size;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400456
Junghak Sung2d700712015-09-22 10:30:30 -0300457 vbuf->flags |= V4L2_BUF_FLAG_KEYFRAME;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400458
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300459 if (vb2_plane_size(vb, 0) < vop_jpeg_size(vh) + solo_enc->jpeg_len)
Hans Verkuildcae5da2013-03-25 05:35:17 -0300460 return -EIO;
461
Andreea-Cristina Bernat0cb6dfd2014-03-16 18:00:01 -0700462 frame_size = ALIGN(vop_jpeg_size(vh) + solo_enc->jpeg_len, DMA_ALIGN);
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300463 vb2_set_plane_payload(vb, 0, vop_jpeg_size(vh) + solo_enc->jpeg_len);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300464
Junghak Sung2d700712015-09-22 10:30:30 -0300465 return solo_send_desc(solo_enc, solo_enc->jpeg_len, sgt,
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300466 vop_jpeg_offset(vh) - SOLO_JPEG_EXT_ADDR(solo_dev),
467 frame_size, SOLO_JPEG_EXT_ADDR(solo_dev),
468 SOLO_JPEG_EXT_SIZE(solo_dev));
Hans Verkuildcae5da2013-03-25 05:35:17 -0300469}
470
Hans Verkuil382c31a2013-03-15 12:04:14 -0300471static int solo_fill_mpeg(struct solo_enc_dev *solo_enc,
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300472 struct vb2_buffer *vb, const vop_header *vh)
Hans Verkuildcae5da2013-03-25 05:35:17 -0300473{
Junghak Sung2d700712015-09-22 10:30:30 -0300474 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300475 struct solo_dev *solo_dev = solo_enc->solo_dev;
Junghak Sung2d700712015-09-22 10:30:30 -0300476 struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300477 int frame_off, frame_size;
478 int skip = 0;
479
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300480 if (vb2_plane_size(vb, 0) < vop_mpeg_size(vh))
Hans Verkuildcae5da2013-03-25 05:35:17 -0300481 return -EIO;
482
Hans Verkuildcae5da2013-03-25 05:35:17 -0300483 /* If this is a key frame, add extra header */
Junghak Sung2d700712015-09-22 10:30:30 -0300484 vbuf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_PFRAME |
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200485 V4L2_BUF_FLAG_BFRAME);
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300486 if (!vop_type(vh)) {
Hans Verkuildcae5da2013-03-25 05:35:17 -0300487 skip = solo_enc->vop_len;
Junghak Sung2d700712015-09-22 10:30:30 -0300488 vbuf->flags |= V4L2_BUF_FLAG_KEYFRAME;
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200489 vb2_set_plane_payload(vb, 0, vop_mpeg_size(vh) +
490 solo_enc->vop_len);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300491 } else {
Junghak Sung2d700712015-09-22 10:30:30 -0300492 vbuf->flags |= V4L2_BUF_FLAG_PFRAME;
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300493 vb2_set_plane_payload(vb, 0, vop_mpeg_size(vh));
Hans Verkuildcae5da2013-03-25 05:35:17 -0300494 }
495
496 /* Now get the actual mpeg payload */
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200497 frame_off = (vop_mpeg_offset(vh) - SOLO_MP4E_EXT_ADDR(solo_dev) +
498 sizeof(*vh)) % SOLO_MP4E_EXT_SIZE(solo_dev);
Andreea-Cristina Bernat0cb6dfd2014-03-16 18:00:01 -0700499 frame_size = ALIGN(vop_mpeg_size(vh) + skip, DMA_ALIGN);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300500
Junghak Sung2d700712015-09-22 10:30:30 -0300501 return solo_send_desc(solo_enc, skip, sgt, frame_off, frame_size,
Hans Verkuil382c31a2013-03-15 12:04:14 -0300502 SOLO_MP4E_EXT_ADDR(solo_dev),
503 SOLO_MP4E_EXT_SIZE(solo_dev));
Hans Verkuildcae5da2013-03-25 05:35:17 -0300504}
505
Hans Verkuila7eb9312013-03-18 08:41:13 -0300506static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc,
Hans Verkuil382c31a2013-03-15 12:04:14 -0300507 struct vb2_buffer *vb, struct solo_enc_buf *enc_buf)
Hans Verkuildcae5da2013-03-25 05:35:17 -0300508{
Junghak Sung2d700712015-09-22 10:30:30 -0300509 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300510 const vop_header *vh = enc_buf->vh;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300511 int ret;
512
Ismael Luceno16af6902013-04-18 10:56:35 -0300513 switch (solo_enc->fmt) {
514 case V4L2_PIX_FMT_MPEG4:
515 case V4L2_PIX_FMT_H264:
Hans Verkuil382c31a2013-03-15 12:04:14 -0300516 ret = solo_fill_mpeg(solo_enc, vb, vh);
Ismael Luceno16af6902013-04-18 10:56:35 -0300517 break;
518 default: /* V4L2_PIX_FMT_MJPEG */
Hans Verkuil382c31a2013-03-15 12:04:14 -0300519 ret = solo_fill_jpeg(solo_enc, vb, vh);
Ismael Luceno16af6902013-04-18 10:56:35 -0300520 break;
521 }
Hans Verkuildcae5da2013-03-25 05:35:17 -0300522
Hans Verkuil382c31a2013-03-15 12:04:14 -0300523 if (!ret) {
Junghak Sung2d700712015-09-22 10:30:30 -0300524 vbuf->sequence = solo_enc->sequence++;
Junghak Sungd6dd6452015-11-03 08:16:37 -0200525 vb->timestamp = ktime_get_ns();
Hans Verkuil316d9e82014-01-27 11:16:05 -0300526
527 /* Check for motion flags */
Andrey Utkine476f4e2014-11-05 17:11:14 -0300528 if (solo_is_motion_on(solo_enc) && enc_buf->motion) {
Hans Verkuil316d9e82014-01-27 11:16:05 -0300529 struct v4l2_event ev = {
530 .type = V4L2_EVENT_MOTION_DET,
531 .u.motion_det = {
Junghak Sung2d700712015-09-22 10:30:30 -0300532 .flags
533 = V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ,
534 .frame_sequence = vbuf->sequence,
Hans Verkuil316d9e82014-01-27 11:16:05 -0300535 .region_mask = enc_buf->motion ? 1 : 0,
536 },
537 };
538
Hans Verkuil316d9e82014-01-27 11:16:05 -0300539 v4l2_event_queue(solo_enc->vfd, &ev);
540 }
Hans Verkuildcae5da2013-03-25 05:35:17 -0300541 }
542
Hans Verkuil382c31a2013-03-15 12:04:14 -0300543 vb2_buffer_done(vb, ret ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
544
Hans Verkuildcae5da2013-03-25 05:35:17 -0300545 return ret;
546}
547
548static void solo_enc_handle_one(struct solo_enc_dev *solo_enc,
549 struct solo_enc_buf *enc_buf)
550{
Hans Verkuil382c31a2013-03-15 12:04:14 -0300551 struct solo_vb2_buf *vb;
Hans Verkuila7eb9312013-03-18 08:41:13 -0300552 unsigned long flags;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300553
Hans Verkuil382c31a2013-03-15 12:04:14 -0300554 mutex_lock(&solo_enc->lock);
Hans Verkuila7eb9312013-03-18 08:41:13 -0300555 if (solo_enc->type != enc_buf->type)
556 goto unlock;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300557
Hans Verkuila7eb9312013-03-18 08:41:13 -0300558 spin_lock_irqsave(&solo_enc->av_lock, flags);
Hans Verkuil382c31a2013-03-15 12:04:14 -0300559 if (list_empty(&solo_enc->vidq_active)) {
560 spin_unlock_irqrestore(&solo_enc->av_lock, flags);
561 goto unlock;
562 }
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200563 vb = list_first_entry(&solo_enc->vidq_active, struct solo_vb2_buf,
564 list);
Hans Verkuil382c31a2013-03-15 12:04:14 -0300565 list_del(&vb->list);
Hans Verkuila7eb9312013-03-18 08:41:13 -0300566 spin_unlock_irqrestore(&solo_enc->av_lock, flags);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400567
Junghak Sung2d700712015-09-22 10:30:30 -0300568 solo_enc_fillbuf(solo_enc, &vb->vb.vb2_buf, enc_buf);
Hans Verkuila7eb9312013-03-18 08:41:13 -0300569unlock:
Hans Verkuil382c31a2013-03-15 12:04:14 -0300570 mutex_unlock(&solo_enc->lock);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400571}
572
Hans Verkuildcae5da2013-03-25 05:35:17 -0300573void solo_enc_v4l2_isr(struct solo_dev *solo_dev)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400574{
Hans Verkuildcae5da2013-03-25 05:35:17 -0300575 wake_up_interruptible_all(&solo_dev->ring_thread_wait);
576}
577
578static void solo_handle_ring(struct solo_dev *solo_dev)
579{
580 for (;;) {
581 struct solo_enc_dev *solo_enc;
582 struct solo_enc_buf enc_buf;
583 u32 mpeg_current, off;
584 u8 ch;
585 u8 cur_q;
586
587 /* Check if the hardware has any new ones in the queue */
588 cur_q = solo_reg_read(solo_dev, SOLO_VE_STATE(11)) & 0xff;
589 if (cur_q == solo_dev->enc_idx)
590 break;
591
592 mpeg_current = solo_reg_read(solo_dev,
593 SOLO_VE_MPEG4_QUE(solo_dev->enc_idx));
594 solo_dev->enc_idx = (solo_dev->enc_idx + 1) % MP4_QS;
595
596 ch = (mpeg_current >> 24) & 0x1f;
597 off = mpeg_current & 0x00ffffff;
598
599 if (ch >= SOLO_MAX_CHANNELS) {
600 ch -= SOLO_MAX_CHANNELS;
601 enc_buf.type = SOLO_ENC_TYPE_EXT;
602 } else
603 enc_buf.type = SOLO_ENC_TYPE_STD;
604
605 solo_enc = solo_dev->v4l2_enc[ch];
606 if (solo_enc == NULL) {
607 dev_err(&solo_dev->pdev->dev,
608 "Got spurious packet for channel %d\n", ch);
609 continue;
610 }
611
612 /* FAIL... */
613 if (enc_get_mpeg_dma(solo_dev, solo_dev->vh_dma, off,
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300614 sizeof(vop_header)))
Hans Verkuildcae5da2013-03-25 05:35:17 -0300615 continue;
616
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300617 enc_buf.vh = solo_dev->vh_buf;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300618
619 /* Sanity check */
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200620 if (vop_mpeg_offset(enc_buf.vh) !=
621 SOLO_MP4E_EXT_ADDR(solo_dev) + off)
Hans Verkuildcae5da2013-03-25 05:35:17 -0300622 continue;
623
624 if (solo_motion_detected(solo_enc))
625 enc_buf.motion = 1;
626 else
627 enc_buf.motion = 0;
628
629 solo_enc_handle_one(solo_enc, &enc_buf);
630 }
631}
632
633static int solo_ring_thread(void *data)
634{
635 struct solo_dev *solo_dev = data;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400636 DECLARE_WAITQUEUE(wait, current);
637
638 set_freezable();
Hans Verkuildcae5da2013-03-25 05:35:17 -0300639 add_wait_queue(&solo_dev->ring_thread_wait, &wait);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400640
641 for (;;) {
642 long timeout = schedule_timeout_interruptible(HZ);
Hans Verkuil1c6f3db2014-07-17 20:40:22 -0300643
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400644 if (timeout == -ERESTARTSYS || kthread_should_stop())
645 break;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300646 solo_handle_ring(solo_dev);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400647 try_to_freeze();
648 }
649
Hans Verkuildcae5da2013-03-25 05:35:17 -0300650 remove_wait_queue(&solo_dev->ring_thread_wait, &wait);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400651
Ben Collinsf62de9b2010-11-04 22:51:17 -0400652 return 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400653}
654
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200655static int solo_enc_queue_setup(struct vb2_queue *q,
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200656 unsigned int *num_buffers,
657 unsigned int *num_planes, unsigned int sizes[],
Hans Verkuil36c0f8b2016-04-15 09:15:05 -0300658 struct device *alloc_devs[])
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400659{
Hans Verkuil382c31a2013-03-15 12:04:14 -0300660 sizes[0] = FRAME_BUF_SIZE;
661 *num_planes = 1;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400662
Hans Verkuil382c31a2013-03-15 12:04:14 -0300663 if (*num_buffers < MIN_VID_BUFFERS)
664 *num_buffers = MIN_VID_BUFFERS;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400665
Ben Collinsf62de9b2010-11-04 22:51:17 -0400666 return 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400667}
668
Hans Verkuil382c31a2013-03-15 12:04:14 -0300669static void solo_enc_buf_queue(struct vb2_buffer *vb)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400670{
Junghak Sung2d700712015-09-22 10:30:30 -0300671 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
Hans Verkuil382c31a2013-03-15 12:04:14 -0300672 struct vb2_queue *vq = vb->vb2_queue;
673 struct solo_enc_dev *solo_enc = vb2_get_drv_priv(vq);
674 struct solo_vb2_buf *solo_vb =
Junghak Sung2d700712015-09-22 10:30:30 -0300675 container_of(vbuf, struct solo_vb2_buf, vb);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400676
Hans Verkuil382c31a2013-03-15 12:04:14 -0300677 spin_lock(&solo_enc->av_lock);
678 list_add_tail(&solo_vb->list, &solo_enc->vidq_active);
679 spin_unlock(&solo_enc->av_lock);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400680}
681
Hans Verkuildcae5da2013-03-25 05:35:17 -0300682static int solo_ring_start(struct solo_dev *solo_dev)
683{
Hans Verkuildcae5da2013-03-25 05:35:17 -0300684 solo_dev->ring_thread = kthread_run(solo_ring_thread, solo_dev,
685 SOLO6X10_NAME "_ring");
686 if (IS_ERR(solo_dev->ring_thread)) {
687 int err = PTR_ERR(solo_dev->ring_thread);
Hans Verkuil1c6f3db2014-07-17 20:40:22 -0300688
Hans Verkuildcae5da2013-03-25 05:35:17 -0300689 solo_dev->ring_thread = NULL;
690 return err;
691 }
692
693 solo_irq_on(solo_dev, SOLO_IRQ_ENCODER);
694
695 return 0;
696}
697
698static void solo_ring_stop(struct solo_dev *solo_dev)
699{
Hans Verkuildcae5da2013-03-25 05:35:17 -0300700 if (solo_dev->ring_thread) {
701 kthread_stop(solo_dev->ring_thread);
702 solo_dev->ring_thread = NULL;
703 }
704
705 solo_irq_off(solo_dev, SOLO_IRQ_ENCODER);
706}
707
Hans Verkuil382c31a2013-03-15 12:04:14 -0300708static int solo_enc_start_streaming(struct vb2_queue *q, unsigned int count)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400709{
Hans Verkuil382c31a2013-03-15 12:04:14 -0300710 struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400711
Andrey Utkin670390c2014-10-29 13:03:53 -0300712 return solo_enc_on(solo_enc);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400713}
714
Hans Verkuile37559b2014-04-17 02:47:21 -0300715static void solo_enc_stop_streaming(struct vb2_queue *q)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400716{
Hans Verkuil382c31a2013-03-15 12:04:14 -0300717 struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q);
Andrey Utkin9ccd1802014-11-06 18:06:18 -0300718 unsigned long flags;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300719
Andrey Utkin9ccd1802014-11-06 18:06:18 -0300720 spin_lock_irqsave(&solo_enc->av_lock, flags);
Hans Verkuila7eb9312013-03-18 08:41:13 -0300721 solo_enc_off(solo_enc);
Andrey Utkin9ccd1802014-11-06 18:06:18 -0300722 while (!list_empty(&solo_enc->vidq_active)) {
723 struct solo_vb2_buf *buf = list_entry(
724 solo_enc->vidq_active.next,
725 struct solo_vb2_buf, list);
726
727 list_del(&buf->list);
Junghak Sung2d700712015-09-22 10:30:30 -0300728 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
Andrey Utkin9ccd1802014-11-06 18:06:18 -0300729 }
730 spin_unlock_irqrestore(&solo_enc->av_lock, flags);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400731}
732
Hans Verkuild790b7e2014-11-24 08:50:31 -0300733static void solo_enc_buf_finish(struct vb2_buffer *vb)
734{
Junghak Sung2d700712015-09-22 10:30:30 -0300735 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
Hans Verkuild790b7e2014-11-24 08:50:31 -0300736 struct solo_enc_dev *solo_enc = vb2_get_drv_priv(vb->vb2_queue);
Junghak Sung2d700712015-09-22 10:30:30 -0300737 struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
Hans Verkuild790b7e2014-11-24 08:50:31 -0300738
739 switch (solo_enc->fmt) {
740 case V4L2_PIX_FMT_MPEG4:
741 case V4L2_PIX_FMT_H264:
Junghak Sung2d700712015-09-22 10:30:30 -0300742 if (vbuf->flags & V4L2_BUF_FLAG_KEYFRAME)
743 sg_copy_from_buffer(sgt->sgl, sgt->nents,
Hans Verkuild790b7e2014-11-24 08:50:31 -0300744 solo_enc->vop, solo_enc->vop_len);
745 break;
746 default: /* V4L2_PIX_FMT_MJPEG */
Junghak Sung2d700712015-09-22 10:30:30 -0300747 sg_copy_from_buffer(sgt->sgl, sgt->nents,
Hans Verkuild790b7e2014-11-24 08:50:31 -0300748 solo_enc->jpeg_header, solo_enc->jpeg_len);
749 break;
750 }
751}
752
Julia Lawall10accd22016-09-08 20:59:18 -0300753static const struct vb2_ops solo_enc_video_qops = {
Hans Verkuil382c31a2013-03-15 12:04:14 -0300754 .queue_setup = solo_enc_queue_setup,
755 .buf_queue = solo_enc_buf_queue,
Hans Verkuild790b7e2014-11-24 08:50:31 -0300756 .buf_finish = solo_enc_buf_finish,
Hans Verkuil382c31a2013-03-15 12:04:14 -0300757 .start_streaming = solo_enc_start_streaming,
758 .stop_streaming = solo_enc_stop_streaming,
759 .wait_prepare = vb2_ops_wait_prepare,
760 .wait_finish = vb2_ops_wait_finish,
761};
762
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400763static int solo_enc_querycap(struct file *file, void *priv,
764 struct v4l2_capability *cap)
765{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300766 struct solo_enc_dev *solo_enc = video_drvdata(file);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100767 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400768
Mauro Carvalho Chehabcc1e6312018-09-10 16:20:42 -0400769 strscpy(cap->driver, SOLO6X10_NAME, sizeof(cap->driver));
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100770 snprintf(cap->card, sizeof(cap->card), "Softlogic 6x10 Enc %d",
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400771 solo_enc->ch);
Hans Verkuil20c5f492013-03-12 18:03:20 -0300772 snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400773 pci_name(solo_dev->pdev));
Hans Verkuil20c5f492013-03-12 18:03:20 -0300774 cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
775 V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
776 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400777 return 0;
778}
779
780static int solo_enc_enum_input(struct file *file, void *priv,
781 struct v4l2_input *input)
782{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300783 struct solo_enc_dev *solo_enc = video_drvdata(file);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100784 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400785
786 if (input->index)
787 return -EINVAL;
788
789 snprintf(input->name, sizeof(input->name), "Encoder %d",
790 solo_enc->ch + 1);
791 input->type = V4L2_INPUT_TYPE_CAMERA;
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300792 input->std = solo_enc->vfd->tvnorms;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400793
794 if (!tw28_get_video_status(solo_dev, solo_enc->ch))
795 input->status = V4L2_IN_ST_NO_SIGNAL;
796
797 return 0;
798}
799
Hans Verkuildcae5da2013-03-25 05:35:17 -0300800static int solo_enc_set_input(struct file *file, void *priv,
801 unsigned int index)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400802{
803 if (index)
804 return -EINVAL;
805
806 return 0;
807}
808
809static int solo_enc_get_input(struct file *file, void *priv,
810 unsigned int *index)
811{
812 *index = 0;
813
814 return 0;
815}
816
817static int solo_enc_enum_fmt_cap(struct file *file, void *priv,
818 struct v4l2_fmtdesc *f)
819{
Ismael Luceno16af6902013-04-18 10:56:35 -0300820 struct solo_enc_dev *solo_enc = video_drvdata(file);
821 int dev_type = solo_enc->solo_dev->type;
822
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400823 switch (f->index) {
824 case 0:
Ismael Luceno16af6902013-04-18 10:56:35 -0300825 switch (dev_type) {
826 case SOLO_DEV_6010:
827 f->pixelformat = V4L2_PIX_FMT_MPEG4;
Mauro Carvalho Chehabcc1e6312018-09-10 16:20:42 -0400828 strscpy(f->description, "MPEG-4 part 2",
829 sizeof(f->description));
Ismael Luceno16af6902013-04-18 10:56:35 -0300830 break;
831 case SOLO_DEV_6110:
832 f->pixelformat = V4L2_PIX_FMT_H264;
Mauro Carvalho Chehabcc1e6312018-09-10 16:20:42 -0400833 strscpy(f->description, "H.264", sizeof(f->description));
Ismael Luceno16af6902013-04-18 10:56:35 -0300834 break;
835 }
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400836 break;
837 case 1:
838 f->pixelformat = V4L2_PIX_FMT_MJPEG;
Mauro Carvalho Chehabcc1e6312018-09-10 16:20:42 -0400839 strscpy(f->description, "MJPEG", sizeof(f->description));
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400840 break;
841 default:
842 return -EINVAL;
843 }
844
845 f->flags = V4L2_FMT_FLAG_COMPRESSED;
846
847 return 0;
848}
849
Ismael Luceno16af6902013-04-18 10:56:35 -0300850static inline int solo_valid_pixfmt(u32 pixfmt, int dev_type)
851{
852 return (pixfmt == V4L2_PIX_FMT_H264 && dev_type == SOLO_DEV_6110)
853 || (pixfmt == V4L2_PIX_FMT_MPEG4 && dev_type == SOLO_DEV_6010)
854 || pixfmt == V4L2_PIX_FMT_MJPEG ? 0 : -EINVAL;
855}
856
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400857static int solo_enc_try_fmt_cap(struct file *file, void *priv,
858 struct v4l2_format *f)
859{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300860 struct solo_enc_dev *solo_enc = video_drvdata(file);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100861 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400862 struct v4l2_pix_format *pix = &f->fmt.pix;
863
Ismael Luceno16af6902013-04-18 10:56:35 -0300864 if (solo_valid_pixfmt(pix->pixelformat, solo_dev->type))
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400865 return -EINVAL;
866
Krzysztof Hałasa98ab1c92011-02-11 13:10:30 +0100867 if (pix->width < solo_dev->video_hsize ||
868 pix->height < solo_dev->video_vsize << 1) {
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400869 /* Default to CIF 1/2 size */
870 pix->width = solo_dev->video_hsize >> 1;
871 pix->height = solo_dev->video_vsize;
Krzysztof Hałasa98ab1c92011-02-11 13:10:30 +0100872 } else {
873 /* Full frame */
874 pix->width = solo_dev->video_hsize;
875 pix->height = solo_dev->video_vsize << 1;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400876 }
877
Hans Verkuil016afda2013-03-12 18:43:21 -0300878 switch (pix->field) {
879 case V4L2_FIELD_NONE:
880 case V4L2_FIELD_INTERLACED:
881 break;
882 case V4L2_FIELD_ANY:
883 default:
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400884 pix->field = V4L2_FIELD_INTERLACED;
Hans Verkuil016afda2013-03-12 18:43:21 -0300885 break;
886 }
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400887
888 /* Just set these */
889 pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
890 pix->sizeimage = FRAME_BUF_SIZE;
Hans Verkuil94160492013-03-12 18:47:03 -0300891 pix->bytesperline = 0;
Hans Verkuil016afda2013-03-12 18:43:21 -0300892 pix->priv = 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400893
894 return 0;
895}
896
897static int solo_enc_set_fmt_cap(struct file *file, void *priv,
898 struct v4l2_format *f)
899{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300900 struct solo_enc_dev *solo_enc = video_drvdata(file);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100901 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400902 struct v4l2_pix_format *pix = &f->fmt.pix;
903 int ret;
904
Hans Verkuil382c31a2013-03-15 12:04:14 -0300905 if (vb2_is_busy(&solo_enc->vidq))
906 return -EBUSY;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400907
facugaichafabbe62010-11-10 10:39:33 -0300908 ret = solo_enc_try_fmt_cap(file, priv, f);
Hans Verkuil016afda2013-03-12 18:43:21 -0300909 if (ret)
910 return ret;
911
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400912 if (pix->width == solo_dev->video_hsize)
913 solo_enc->mode = SOLO_ENC_MODE_D1;
914 else
915 solo_enc->mode = SOLO_ENC_MODE_CIF;
916
917 /* This does not change the encoder at all */
Hans Verkuila7eb9312013-03-18 08:41:13 -0300918 solo_enc->fmt = pix->pixelformat;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400919
Hans Verkuil69996872013-03-15 16:35:28 -0300920 /*
921 * More information is needed about these 'extended' types. As far
922 * as I can tell these are basically additional video streams with
923 * different MPEG encoding attributes that can run in parallel with
924 * the main stream. If so, then this should be implemented as a
925 * second video node. Abusing priv like this is certainly not the
926 * right approach.
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400927 if (pix->priv)
Hans Verkuila7eb9312013-03-18 08:41:13 -0300928 solo_enc->type = SOLO_ENC_TYPE_EXT;
Hans Verkuil69996872013-03-15 16:35:28 -0300929 */
Ismael Lucenocdcfe402013-04-12 18:28:33 -0300930 solo_update_mode(solo_enc);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300931 return 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400932}
933
934static int solo_enc_get_fmt_cap(struct file *file, void *priv,
935 struct v4l2_format *f)
936{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300937 struct solo_enc_dev *solo_enc = video_drvdata(file);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400938 struct v4l2_pix_format *pix = &f->fmt.pix;
939
940 pix->width = solo_enc->width;
941 pix->height = solo_enc->height;
Hans Verkuila7eb9312013-03-18 08:41:13 -0300942 pix->pixelformat = solo_enc->fmt;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400943 pix->field = solo_enc->interlaced ? V4L2_FIELD_INTERLACED :
944 V4L2_FIELD_NONE;
945 pix->sizeimage = FRAME_BUF_SIZE;
946 pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
Hans Verkuil016afda2013-03-12 18:43:21 -0300947 pix->priv = 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400948
949 return 0;
950}
951
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300952static int solo_enc_g_std(struct file *file, void *priv, v4l2_std_id *i)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400953{
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300954 struct solo_enc_dev *solo_enc = video_drvdata(file);
955 struct solo_dev *solo_dev = solo_enc->solo_dev;
956
957 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
958 *i = V4L2_STD_NTSC_M;
959 else
960 *i = V4L2_STD_PAL;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400961 return 0;
962}
963
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300964static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id std)
965{
966 struct solo_enc_dev *solo_enc = video_drvdata(file);
967
Hans Verkuil429df502014-01-13 06:58:12 -0300968 return solo_set_video_type(solo_enc->solo_dev, std & V4L2_STD_625_50);
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300969}
970
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400971static int solo_enum_framesizes(struct file *file, void *priv,
972 struct v4l2_frmsizeenum *fsize)
973{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300974 struct solo_enc_dev *solo_enc = video_drvdata(file);
975 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400976
Ismael Luceno16af6902013-04-18 10:56:35 -0300977 if (solo_valid_pixfmt(fsize->pixel_format, solo_dev->type))
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400978 return -EINVAL;
979
980 switch (fsize->index) {
981 case 0:
982 fsize->discrete.width = solo_dev->video_hsize >> 1;
983 fsize->discrete.height = solo_dev->video_vsize;
984 break;
985 case 1:
986 fsize->discrete.width = solo_dev->video_hsize;
987 fsize->discrete.height = solo_dev->video_vsize << 1;
988 break;
989 default:
990 return -EINVAL;
991 }
992
993 fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
994
995 return 0;
996}
997
998static int solo_enum_frameintervals(struct file *file, void *priv,
999 struct v4l2_frmivalenum *fintv)
1000{
Hans Verkuila7eb9312013-03-18 08:41:13 -03001001 struct solo_enc_dev *solo_enc = video_drvdata(file);
1002 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001003
Ismael Luceno16af6902013-04-18 10:56:35 -03001004 if (solo_valid_pixfmt(fintv->pixel_format, solo_dev->type))
Hans Verkuil016afda2013-03-12 18:43:21 -03001005 return -EINVAL;
1006 if (fintv->index)
1007 return -EINVAL;
1008 if ((fintv->width != solo_dev->video_hsize >> 1 ||
1009 fintv->height != solo_dev->video_vsize) &&
1010 (fintv->width != solo_dev->video_hsize ||
1011 fintv->height != solo_dev->video_vsize << 1))
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001012 return -EINVAL;
1013
1014 fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE;
1015
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001016 fintv->stepwise.min.numerator = 1;
Hans Verkuil016afda2013-03-12 18:43:21 -03001017 fintv->stepwise.min.denominator = solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001018
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001019 fintv->stepwise.max.numerator = 15;
Hans Verkuil016afda2013-03-12 18:43:21 -03001020 fintv->stepwise.max.denominator = solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001021
1022 fintv->stepwise.step.numerator = 1;
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001023 fintv->stepwise.step.denominator = solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001024
1025 return 0;
1026}
1027
1028static int solo_g_parm(struct file *file, void *priv,
1029 struct v4l2_streamparm *sp)
1030{
Hans Verkuila7eb9312013-03-18 08:41:13 -03001031 struct solo_enc_dev *solo_enc = video_drvdata(file);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001032 struct v4l2_captureparm *cp = &sp->parm.capture;
1033
1034 cp->capability = V4L2_CAP_TIMEPERFRAME;
1035 cp->timeperframe.numerator = solo_enc->interval;
Ismael Luceno88107672013-05-03 15:54:57 -03001036 cp->timeperframe.denominator = solo_enc->solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001037 cp->capturemode = 0;
1038 /* XXX: Shouldn't we be able to get/set this from videobuf? */
1039 cp->readbuffers = 2;
1040
Ben Collinsf62de9b2010-11-04 22:51:17 -04001041 return 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001042}
1043
Ismael Luceno88107672013-05-03 15:54:57 -03001044static inline int calc_interval(u8 fps, u32 n, u32 d)
1045{
1046 if (!n || !d)
1047 return 1;
1048 if (d == fps)
1049 return n;
1050 n *= fps;
1051 return min(15U, n / d + (n % d >= (fps >> 1)));
1052}
1053
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001054static int solo_s_parm(struct file *file, void *priv,
1055 struct v4l2_streamparm *sp)
1056{
Hans Verkuila7eb9312013-03-18 08:41:13 -03001057 struct solo_enc_dev *solo_enc = video_drvdata(file);
Ismael Luceno88107672013-05-03 15:54:57 -03001058 struct v4l2_fract *t = &sp->parm.capture.timeperframe;
1059 u8 fps = solo_enc->solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001060
Hans Verkuil382c31a2013-03-15 12:04:14 -03001061 if (vb2_is_streaming(&solo_enc->vidq))
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001062 return -EBUSY;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001063
Ismael Luceno88107672013-05-03 15:54:57 -03001064 solo_enc->interval = calc_interval(fps, t->numerator, t->denominator);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001065 solo_update_mode(solo_enc);
Ismael Luceno88107672013-05-03 15:54:57 -03001066 return solo_g_parm(file, priv, sp);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001067}
1068
Hans Verkuilc813bd32013-03-25 05:38:14 -03001069static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001070{
Hans Verkuilc813bd32013-03-25 05:38:14 -03001071 struct solo_enc_dev *solo_enc =
1072 container_of(ctrl->handler, struct solo_enc_dev, hdl);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +01001073 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001074 int err;
1075
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001076 switch (ctrl->id) {
1077 case V4L2_CID_BRIGHTNESS:
1078 case V4L2_CID_CONTRAST:
1079 case V4L2_CID_SATURATION:
1080 case V4L2_CID_HUE:
1081 case V4L2_CID_SHARPNESS:
1082 return tw28_set_ctrl_val(solo_dev, ctrl->id, solo_enc->ch,
Hans Verkuilc813bd32013-03-25 05:38:14 -03001083 ctrl->val);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001084 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
Hans Verkuilc813bd32013-03-25 05:38:14 -03001085 solo_enc->gop = ctrl->val;
Andrey Utkin63e9b452014-07-08 12:23:33 -03001086 solo_reg_write(solo_dev, SOLO_VE_CH_GOP(solo_enc->ch), solo_enc->gop);
1087 solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(solo_enc->ch), solo_enc->gop);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001088 return 0;
Andrey Utkin56981112014-07-08 12:23:32 -03001089 case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
1090 solo_enc->qp = ctrl->val;
Andrey Utkin63e9b452014-07-08 12:23:33 -03001091 solo_reg_write(solo_dev, SOLO_VE_CH_QP(solo_enc->ch), solo_enc->qp);
1092 solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(solo_enc->ch), solo_enc->qp);
Andrey Utkin56981112014-07-08 12:23:32 -03001093 return 0;
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001094 case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD:
1095 solo_enc->motion_thresh = ctrl->val << 8;
Hans Verkuilf5df0b72013-03-18 08:43:14 -03001096 if (!solo_enc->motion_global || !solo_enc->motion_enabled)
1097 return 0;
Aybuke Ozdemirfa917832014-03-13 02:20:20 +02001098 return solo_set_motion_threshold(solo_dev, solo_enc->ch,
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001099 solo_enc->motion_thresh);
1100 case V4L2_CID_DETECT_MD_MODE:
1101 solo_enc->motion_global = ctrl->val == V4L2_DETECT_MD_MODE_GLOBAL;
1102 solo_enc->motion_enabled = ctrl->val > V4L2_DETECT_MD_MODE_DISABLED;
Hans Verkuilf5df0b72013-03-18 08:43:14 -03001103 if (ctrl->val) {
1104 if (solo_enc->motion_global)
Hans Verkuil0a128302014-07-25 08:19:54 -03001105 err = solo_set_motion_threshold(solo_dev, solo_enc->ch,
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001106 solo_enc->motion_thresh);
Hans Verkuilf5df0b72013-03-18 08:43:14 -03001107 else
Hans Verkuil0a128302014-07-25 08:19:54 -03001108 err = solo_set_motion_block(solo_dev, solo_enc->ch,
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001109 solo_enc->md_thresholds->p_cur.p_u16);
Hans Verkuil0a128302014-07-25 08:19:54 -03001110 if (err)
1111 return err;
Hans Verkuildcae5da2013-03-25 05:35:17 -03001112 }
Hans Verkuilc813bd32013-03-25 05:38:14 -03001113 solo_motion_toggle(solo_enc, ctrl->val);
1114 return 0;
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001115 case V4L2_CID_DETECT_MD_THRESHOLD_GRID:
1116 if (solo_enc->motion_enabled && !solo_enc->motion_global)
1117 return solo_set_motion_block(solo_dev, solo_enc->ch,
1118 solo_enc->md_thresholds->p_new.p_u16);
1119 break;
Hans Verkuilc813bd32013-03-25 05:38:14 -03001120 case V4L2_CID_OSD_TEXT:
Mauro Carvalho Chehabcc1e6312018-09-10 16:20:42 -04001121 strscpy(solo_enc->osd_text, ctrl->p_new.p_char,
1122 sizeof(solo_enc->osd_text));
Hans Verkuil0a128302014-07-25 08:19:54 -03001123 return solo_osd_print(solo_enc);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001124 default:
1125 return -EINVAL;
1126 }
1127
1128 return 0;
1129}
1130
Hans Verkuil316d9e82014-01-27 11:16:05 -03001131static int solo_subscribe_event(struct v4l2_fh *fh,
1132 const struct v4l2_event_subscription *sub)
1133{
1134
1135 switch (sub->type) {
Hans Verkuil316d9e82014-01-27 11:16:05 -03001136 case V4L2_EVENT_MOTION_DET:
1137 /* Allow for up to 30 events (1 second for NTSC) to be
1138 * stored. */
1139 return v4l2_event_subscribe(fh, sub, 30, NULL);
Gustavo Padovanf4fde9a2017-02-15 15:55:30 -02001140 default:
1141 return v4l2_ctrl_subscribe_event(fh, sub);
Hans Verkuil316d9e82014-01-27 11:16:05 -03001142 }
Hans Verkuil316d9e82014-01-27 11:16:05 -03001143}
1144
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001145static const struct v4l2_file_operations solo_enc_fops = {
1146 .owner = THIS_MODULE,
Hans Verkuil382c31a2013-03-15 12:04:14 -03001147 .open = v4l2_fh_open,
1148 .release = vb2_fop_release,
1149 .read = vb2_fop_read,
1150 .poll = vb2_fop_poll,
1151 .mmap = vb2_fop_mmap,
1152 .unlocked_ioctl = video_ioctl2,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001153};
1154
1155static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = {
1156 .vidioc_querycap = solo_enc_querycap,
1157 .vidioc_s_std = solo_enc_s_std,
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001158 .vidioc_g_std = solo_enc_g_std,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001159 /* Input callbacks */
1160 .vidioc_enum_input = solo_enc_enum_input,
1161 .vidioc_s_input = solo_enc_set_input,
1162 .vidioc_g_input = solo_enc_get_input,
1163 /* Video capture format callbacks */
1164 .vidioc_enum_fmt_vid_cap = solo_enc_enum_fmt_cap,
1165 .vidioc_try_fmt_vid_cap = solo_enc_try_fmt_cap,
1166 .vidioc_s_fmt_vid_cap = solo_enc_set_fmt_cap,
1167 .vidioc_g_fmt_vid_cap = solo_enc_get_fmt_cap,
1168 /* Streaming I/O */
Hans Verkuil382c31a2013-03-15 12:04:14 -03001169 .vidioc_reqbufs = vb2_ioctl_reqbufs,
1170 .vidioc_querybuf = vb2_ioctl_querybuf,
1171 .vidioc_qbuf = vb2_ioctl_qbuf,
1172 .vidioc_dqbuf = vb2_ioctl_dqbuf,
1173 .vidioc_streamon = vb2_ioctl_streamon,
1174 .vidioc_streamoff = vb2_ioctl_streamoff,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001175 /* Frame size and interval */
1176 .vidioc_enum_framesizes = solo_enum_framesizes,
1177 .vidioc_enum_frameintervals = solo_enum_frameintervals,
1178 /* Video capture parameters */
1179 .vidioc_s_parm = solo_s_parm,
1180 .vidioc_g_parm = solo_g_parm,
Hans Verkuil94160492013-03-12 18:47:03 -03001181 /* Logging and events */
1182 .vidioc_log_status = v4l2_ctrl_log_status,
Hans Verkuil316d9e82014-01-27 11:16:05 -03001183 .vidioc_subscribe_event = solo_subscribe_event,
Hans Verkuil94160492013-03-12 18:47:03 -03001184 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001185};
1186
Hans Verkuildcae5da2013-03-25 05:35:17 -03001187static const struct video_device solo_enc_template = {
Krzysztof Hałasadecebab2011-02-11 13:38:20 +01001188 .name = SOLO6X10_NAME,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001189 .fops = &solo_enc_fops,
1190 .ioctl_ops = &solo_enc_ioctl_ops,
1191 .minor = -1,
1192 .release = video_device_release,
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001193 .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001194};
1195
Hans Verkuilc813bd32013-03-25 05:38:14 -03001196static const struct v4l2_ctrl_ops solo_ctrl_ops = {
1197 .s_ctrl = solo_s_ctrl,
1198};
1199
Hans Verkuilc813bd32013-03-25 05:38:14 -03001200static const struct v4l2_ctrl_config solo_osd_text_ctrl = {
1201 .ops = &solo_ctrl_ops,
1202 .id = V4L2_CID_OSD_TEXT,
1203 .name = "OSD Text",
1204 .type = V4L2_CTRL_TYPE_STRING,
1205 .max = OSD_TEXT_MAX,
1206 .step = 1,
1207};
1208
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001209/* Motion Detection Threshold matrix */
1210static const struct v4l2_ctrl_config solo_md_thresholds = {
1211 .ops = &solo_ctrl_ops,
1212 .id = V4L2_CID_DETECT_MD_THRESHOLD_GRID,
1213 .dims = { SOLO_MOTION_SZ, SOLO_MOTION_SZ },
1214 .def = SOLO_DEF_MOT_THRESH,
1215 .max = 65535,
1216 .step = 1,
1217};
1218
Hans Verkuildcae5da2013-03-25 05:35:17 -03001219static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
1220 u8 ch, unsigned nr)
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001221{
1222 struct solo_enc_dev *solo_enc;
Hans Verkuilc813bd32013-03-25 05:38:14 -03001223 struct v4l2_ctrl_handler *hdl;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001224 int ret;
1225
1226 solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL);
1227 if (!solo_enc)
1228 return ERR_PTR(-ENOMEM);
1229
Hans Verkuilc813bd32013-03-25 05:38:14 -03001230 hdl = &solo_enc->hdl;
1231 v4l2_ctrl_handler_init(hdl, 10);
1232 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1233 V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
1234 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1235 V4L2_CID_CONTRAST, 0, 255, 1, 128);
1236 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1237 V4L2_CID_SATURATION, 0, 255, 1, 128);
1238 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1239 V4L2_CID_HUE, 0, 255, 1, 128);
1240 if (tw28_has_sharpness(solo_dev, ch))
1241 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1242 V4L2_CID_SHARPNESS, 0, 15, 1, 0);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001243 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1244 V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 255, 1, solo_dev->fps);
Andrey Utkin56981112014-07-08 12:23:32 -03001245 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1246 V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 31, 1, SOLO_DEFAULT_QP);
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001247 v4l2_ctrl_new_std_menu(hdl, &solo_ctrl_ops,
1248 V4L2_CID_DETECT_MD_MODE,
1249 V4L2_DETECT_MD_MODE_THRESHOLD_GRID, 0,
1250 V4L2_DETECT_MD_MODE_DISABLED);
1251 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1252 V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD, 0, 0xff, 1,
1253 SOLO_DEF_MOT_THRESH >> 8);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001254 v4l2_ctrl_new_custom(hdl, &solo_osd_text_ctrl, NULL);
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001255 solo_enc->md_thresholds =
1256 v4l2_ctrl_new_custom(hdl, &solo_md_thresholds, NULL);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001257 if (hdl->error) {
1258 ret = hdl->error;
Hans Verkuila7eb9312013-03-18 08:41:13 -03001259 goto hdl_free;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001260 }
1261
1262 solo_enc->solo_dev = solo_dev;
1263 solo_enc->ch = ch;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001264 mutex_init(&solo_enc->lock);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001265 spin_lock_init(&solo_enc->av_lock);
1266 INIT_LIST_HEAD(&solo_enc->vidq_active);
Ismael Luceno16af6902013-04-18 10:56:35 -03001267 solo_enc->fmt = (solo_dev->type == SOLO_DEV_6010) ?
1268 V4L2_PIX_FMT_MPEG4 : V4L2_PIX_FMT_H264;
Hans Verkuila7eb9312013-03-18 08:41:13 -03001269 solo_enc->type = SOLO_ENC_TYPE_STD;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001270
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001271 solo_enc->qp = SOLO_DEFAULT_QP;
Ben Collinsf62de9b2010-11-04 22:51:17 -04001272 solo_enc->gop = solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001273 solo_enc->interval = 1;
1274 solo_enc->mode = SOLO_ENC_MODE_CIF;
Hans Verkuilf5df0b72013-03-18 08:43:14 -03001275 solo_enc->motion_global = true;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001276 solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001277 solo_enc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1278 solo_enc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
1279 solo_enc->vidq.ops = &solo_enc_video_qops;
1280 solo_enc->vidq.mem_ops = &vb2_dma_sg_memops;
1281 solo_enc->vidq.drv_priv = solo_enc;
Mel Gormand0164ad2015-11-06 16:28:21 -08001282 solo_enc->vidq.gfp_flags = __GFP_DMA32 | __GFP_KSWAPD_RECLAIM;
Sakari Ailusade48682014-02-25 19:12:19 -03001283 solo_enc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001284 solo_enc->vidq.buf_struct_size = sizeof(struct solo_vb2_buf);
1285 solo_enc->vidq.lock = &solo_enc->lock;
Hans Verkuil2bc46b32016-02-15 12:37:15 -02001286 solo_enc->vidq.dev = &solo_dev->pdev->dev;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001287 ret = vb2_queue_init(&solo_enc->vidq);
1288 if (ret)
1289 goto hdl_free;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001290 solo_update_mode(solo_enc);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001291
Hans Verkuila7eb9312013-03-18 08:41:13 -03001292 spin_lock_init(&solo_enc->motion_lock);
1293
Hans Verkuildcae5da2013-03-25 05:35:17 -03001294 /* Initialize this per encoder */
1295 solo_enc->jpeg_len = sizeof(jpeg_header);
1296 memcpy(solo_enc->jpeg_header, jpeg_header, solo_enc->jpeg_len);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001297
Hans Verkuila7eb9312013-03-18 08:41:13 -03001298 solo_enc->desc_nelts = 32;
1299 solo_enc->desc_items = pci_alloc_consistent(solo_dev->pdev,
1300 sizeof(struct solo_p2m_desc) *
Aybuke Ozdemirfa917832014-03-13 02:20:20 +02001301 solo_enc->desc_nelts,
1302 &solo_enc->desc_dma);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001303 ret = -ENOMEM;
1304 if (solo_enc->desc_items == NULL)
1305 goto hdl_free;
1306
Hans Verkuila7eb9312013-03-18 08:41:13 -03001307 solo_enc->vfd = video_device_alloc();
1308 if (!solo_enc->vfd)
1309 goto pci_free;
1310
1311 *solo_enc->vfd = solo_enc_template;
1312 solo_enc->vfd->v4l2_dev = &solo_dev->v4l2_dev;
1313 solo_enc->vfd->ctrl_handler = hdl;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001314 solo_enc->vfd->queue = &solo_enc->vidq;
1315 solo_enc->vfd->lock = &solo_enc->lock;
Hans Verkuila7eb9312013-03-18 08:41:13 -03001316 video_set_drvdata(solo_enc->vfd, solo_enc);
1317 ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr);
1318 if (ret < 0)
1319 goto vdev_release;
1320
1321 snprintf(solo_enc->vfd->name, sizeof(solo_enc->vfd->name),
1322 "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num,
1323 solo_enc->vfd->num);
1324
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001325 return solo_enc;
Hans Verkuila7eb9312013-03-18 08:41:13 -03001326
1327vdev_release:
1328 video_device_release(solo_enc->vfd);
1329pci_free:
1330 pci_free_consistent(solo_enc->solo_dev->pdev,
1331 sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts,
1332 solo_enc->desc_items, solo_enc->desc_dma);
1333hdl_free:
1334 v4l2_ctrl_handler_free(hdl);
1335 kfree(solo_enc);
1336 return ERR_PTR(ret);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001337}
1338
1339static void solo_enc_free(struct solo_enc_dev *solo_enc)
1340{
1341 if (solo_enc == NULL)
1342 return;
1343
Andrey Utkin0cb2df32014-10-29 13:03:52 -03001344 pci_free_consistent(solo_enc->solo_dev->pdev,
1345 sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts,
1346 solo_enc->desc_items, solo_enc->desc_dma);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001347 video_unregister_device(solo_enc->vfd);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001348 v4l2_ctrl_handler_free(&solo_enc->hdl);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001349 kfree(solo_enc);
1350}
1351
Hans Verkuildcae5da2013-03-25 05:35:17 -03001352int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001353{
1354 int i;
1355
Hans Verkuildcae5da2013-03-25 05:35:17 -03001356 init_waitqueue_head(&solo_dev->ring_thread_wait);
1357
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -03001358 solo_dev->vh_size = sizeof(vop_header);
Hans Verkuildcae5da2013-03-25 05:35:17 -03001359 solo_dev->vh_buf = pci_alloc_consistent(solo_dev->pdev,
1360 solo_dev->vh_size,
1361 &solo_dev->vh_dma);
1362 if (solo_dev->vh_buf == NULL)
1363 return -ENOMEM;
1364
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001365 for (i = 0; i < solo_dev->nr_chans; i++) {
Hans Verkuildcae5da2013-03-25 05:35:17 -03001366 solo_dev->v4l2_enc[i] = solo_enc_alloc(solo_dev, i, nr);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001367 if (IS_ERR(solo_dev->v4l2_enc[i]))
1368 break;
1369 }
1370
1371 if (i != solo_dev->nr_chans) {
1372 int ret = PTR_ERR(solo_dev->v4l2_enc[i]);
Hans Verkuil1c6f3db2014-07-17 20:40:22 -03001373
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001374 while (i--)
1375 solo_enc_free(solo_dev->v4l2_enc[i]);
Hans Verkuildcae5da2013-03-25 05:35:17 -03001376 pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
1377 solo_dev->vh_buf, solo_dev->vh_dma);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001378 solo_dev->vh_buf = NULL;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001379 return ret;
1380 }
1381
Hans Verkuildcae5da2013-03-25 05:35:17 -03001382 if (solo_dev->type == SOLO_DEV_6010)
1383 solo_dev->enc_bw_remain = solo_dev->fps * 4 * 4;
1384 else
1385 solo_dev->enc_bw_remain = solo_dev->fps * 4 * 5;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001386
1387 dev_info(&solo_dev->pdev->dev, "Encoders as /dev/video%d-%d\n",
1388 solo_dev->v4l2_enc[0]->vfd->num,
1389 solo_dev->v4l2_enc[solo_dev->nr_chans - 1]->vfd->num);
1390
Andrey Utkin670390c2014-10-29 13:03:53 -03001391 return solo_ring_start(solo_dev);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001392}
1393
Krzysztof Hałasadecebab2011-02-11 13:38:20 +01001394void solo_enc_v4l2_exit(struct solo_dev *solo_dev)
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001395{
1396 int i;
1397
Andrey Utkin670390c2014-10-29 13:03:53 -03001398 solo_ring_stop(solo_dev);
1399
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001400 for (i = 0; i < solo_dev->nr_chans; i++)
1401 solo_enc_free(solo_dev->v4l2_enc[i]);
Hans Verkuildcae5da2013-03-25 05:35:17 -03001402
Hans Verkuila7eb9312013-03-18 08:41:13 -03001403 if (solo_dev->vh_buf)
1404 pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
Hans Verkuildcae5da2013-03-25 05:35:17 -03001405 solo_dev->vh_buf, solo_dev->vh_dma);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001406}