blob: 9d27e7463070f3bc3821dfd1b91a0b68144528a0 [file] [log] [blame]
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001/*
Hans Verkuildcae5da2013-03-25 05:35:17 -03002 * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
3 *
4 * Original author:
5 * Ben Collins <bcollins@ubuntu.com>
6 *
7 * Additional work by:
8 * John Brooks <john.brooks@bluecherry.net>
Ben Collinsfaa4fd22010-06-17 13:27:26 -04009 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
Ben Collinsfaa4fd22010-06-17 13:27:26 -040019 */
20
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/kthread.h>
24#include <linux/freezer.h>
Hans Verkuildcae5da2013-03-25 05:35:17 -030025
Ben Collinsfaa4fd22010-06-17 13:27:26 -040026#include <media/v4l2-ioctl.h>
27#include <media/v4l2-common.h>
Hans Verkuil94160492013-03-12 18:47:03 -030028#include <media/v4l2-event.h>
Hans Verkuil382c31a2013-03-15 12:04:14 -030029#include <media/videobuf2-dma-sg.h>
Hans Verkuildcae5da2013-03-25 05:35:17 -030030
Krzysztof Hałasaae69b222011-02-11 13:36:27 +010031#include "solo6x10.h"
Hans Verkuildad7fab2013-03-25 05:42:46 -030032#include "solo6x10-tw28.h"
Hans Verkuilb3c7d452011-11-03 06:57:08 -030033#include "solo6x10-jpeg.h"
Ben Collinsfaa4fd22010-06-17 13:27:26 -040034
Hans Verkuildcae5da2013-03-25 05:35:17 -030035#define MIN_VID_BUFFERS 2
Andrey Utkine34f2a92016-07-09 21:44:50 -030036#define FRAME_BUF_SIZE (400 * 1024)
Ben Collinsfaa4fd22010-06-17 13:27:26 -040037#define MP4_QS 16
Hans Verkuildcae5da2013-03-25 05:35:17 -030038#define DMA_ALIGN 4096
Ben Collinsfaa4fd22010-06-17 13:27:26 -040039
Hans Verkuildcae5da2013-03-25 05:35:17 -030040/* 6010 M4V */
Ismael Luceno8a4d9a92014-12-24 08:35:59 -030041static u8 vop_6010_ntsc_d1[] = {
Hans Verkuildcae5da2013-03-25 05:35:17 -030042 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
43 0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40,
44 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
45 0x1f, 0x4c, 0x58, 0x10, 0xf0, 0x71, 0x18, 0x3f,
46};
47
Ismael Luceno8a4d9a92014-12-24 08:35:59 -030048static u8 vop_6010_ntsc_cif[] = {
Hans Verkuildcae5da2013-03-25 05:35:17 -030049 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
50 0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40,
51 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
52 0x1f, 0x4c, 0x2c, 0x10, 0x78, 0x51, 0x18, 0x3f,
53};
54
Ismael Luceno8a4d9a92014-12-24 08:35:59 -030055static u8 vop_6010_pal_d1[] = {
Hans Verkuildcae5da2013-03-25 05:35:17 -030056 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
57 0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40,
58 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
59 0x1f, 0x4c, 0x58, 0x11, 0x20, 0x71, 0x18, 0x3f,
60};
61
Ismael Luceno8a4d9a92014-12-24 08:35:59 -030062static u8 vop_6010_pal_cif[] = {
Hans Verkuildcae5da2013-03-25 05:35:17 -030063 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
64 0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40,
65 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
66 0x1f, 0x4c, 0x2c, 0x10, 0x90, 0x51, 0x18, 0x3f,
67};
68
69/* 6110 h.264 */
Ismael Luceno8a4d9a92014-12-24 08:35:59 -030070static u8 vop_6110_ntsc_d1[] = {
Hans Verkuildcae5da2013-03-25 05:35:17 -030071 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
72 0x9a, 0x74, 0x05, 0x81, 0xec, 0x80, 0x00, 0x00,
73 0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00,
74};
75
Ismael Luceno8a4d9a92014-12-24 08:35:59 -030076static u8 vop_6110_ntsc_cif[] = {
Hans Verkuildcae5da2013-03-25 05:35:17 -030077 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
78 0x9a, 0x74, 0x0b, 0x0f, 0xc8, 0x00, 0x00, 0x00,
79 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00,
80};
81
Ismael Luceno8a4d9a92014-12-24 08:35:59 -030082static u8 vop_6110_pal_d1[] = {
Hans Verkuildcae5da2013-03-25 05:35:17 -030083 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
84 0x9a, 0x74, 0x05, 0x80, 0x93, 0x20, 0x00, 0x00,
85 0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00,
86};
87
Ismael Luceno8a4d9a92014-12-24 08:35:59 -030088static u8 vop_6110_pal_cif[] = {
Hans Verkuildcae5da2013-03-25 05:35:17 -030089 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
90 0x9a, 0x74, 0x0b, 0x04, 0xb2, 0x00, 0x00, 0x00,
91 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00,
92};
93
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -030094typedef __le32 vop_header[16];
Hans Verkuildcae5da2013-03-25 05:35:17 -030095
96struct solo_enc_buf {
97 enum solo_enc_types type;
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -030098 const vop_header *vh;
Hans Verkuildcae5da2013-03-25 05:35:17 -030099 int motion;
100};
101
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400102static int solo_is_motion_on(struct solo_enc_dev *solo_enc)
103{
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100104 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400105
Hans Verkuildcae5da2013-03-25 05:35:17 -0300106 return (solo_dev->motion_mask >> solo_enc->ch) & 1;
107}
108
109static int solo_motion_detected(struct solo_enc_dev *solo_enc)
110{
111 struct solo_dev *solo_dev = solo_enc->solo_dev;
112 unsigned long flags;
113 u32 ch_mask = 1 << solo_enc->ch;
114 int ret = 0;
115
116 spin_lock_irqsave(&solo_enc->motion_lock, flags);
117 if (solo_reg_read(solo_dev, SOLO_VI_MOT_STATUS) & ch_mask) {
118 solo_reg_write(solo_dev, SOLO_VI_MOT_CLEAR, ch_mask);
119 ret = 1;
120 }
121 spin_unlock_irqrestore(&solo_enc->motion_lock, flags);
122
123 return ret;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400124}
125
126static void solo_motion_toggle(struct solo_enc_dev *solo_enc, int on)
127{
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100128 struct solo_dev *solo_dev = solo_enc->solo_dev;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300129 u32 mask = 1 << solo_enc->ch;
130 unsigned long flags;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400131
Hans Verkuildcae5da2013-03-25 05:35:17 -0300132 spin_lock_irqsave(&solo_enc->motion_lock, flags);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400133
134 if (on)
Hans Verkuildcae5da2013-03-25 05:35:17 -0300135 solo_dev->motion_mask |= mask;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400136 else
Hans Verkuildcae5da2013-03-25 05:35:17 -0300137 solo_dev->motion_mask &= ~mask;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400138
Hans Verkuildcae5da2013-03-25 05:35:17 -0300139 solo_reg_write(solo_dev, SOLO_VI_MOT_CLEAR, mask);
Ben Collinsf62de9b2010-11-04 22:51:17 -0400140
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400141 solo_reg_write(solo_dev, SOLO_VI_MOT_ADR,
142 SOLO_VI_MOTION_EN(solo_dev->motion_mask) |
143 (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
144
Hans Verkuildcae5da2013-03-25 05:35:17 -0300145 spin_unlock_irqrestore(&solo_enc->motion_lock, flags);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400146}
147
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300148void solo_update_mode(struct solo_enc_dev *solo_enc)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400149{
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100150 struct solo_dev *solo_dev = solo_enc->solo_dev;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300151 int vop_len;
Ismael Luceno8a4d9a92014-12-24 08:35:59 -0300152 u8 *vop;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400153
154 solo_enc->interlaced = (solo_enc->mode & 0x08) ? 1 : 0;
155 solo_enc->bw_weight = max(solo_dev->fps / solo_enc->interval, 1);
156
Hans Verkuildcae5da2013-03-25 05:35:17 -0300157 if (solo_enc->mode == SOLO_ENC_MODE_CIF) {
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400158 solo_enc->width = solo_dev->video_hsize >> 1;
159 solo_enc->height = solo_dev->video_vsize;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300160 if (solo_dev->type == SOLO_DEV_6110) {
161 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
162 vop = vop_6110_ntsc_cif;
163 vop_len = sizeof(vop_6110_ntsc_cif);
164 } else {
165 vop = vop_6110_pal_cif;
166 vop_len = sizeof(vop_6110_pal_cif);
167 }
168 } else {
169 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
170 vop = vop_6010_ntsc_cif;
171 vop_len = sizeof(vop_6010_ntsc_cif);
172 } else {
173 vop = vop_6010_pal_cif;
174 vop_len = sizeof(vop_6010_pal_cif);
175 }
176 }
177 } else {
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400178 solo_enc->width = solo_dev->video_hsize;
179 solo_enc->height = solo_dev->video_vsize << 1;
180 solo_enc->bw_weight <<= 2;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300181 if (solo_dev->type == SOLO_DEV_6110) {
182 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
183 vop = vop_6110_ntsc_d1;
184 vop_len = sizeof(vop_6110_ntsc_d1);
185 } else {
186 vop = vop_6110_pal_d1;
187 vop_len = sizeof(vop_6110_pal_d1);
188 }
189 } else {
190 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
191 vop = vop_6010_ntsc_d1;
192 vop_len = sizeof(vop_6010_ntsc_d1);
193 } else {
194 vop = vop_6010_pal_d1;
195 vop_len = sizeof(vop_6010_pal_d1);
196 }
197 }
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400198 }
Hans Verkuildcae5da2013-03-25 05:35:17 -0300199
200 memcpy(solo_enc->vop, vop, vop_len);
201
202 /* Some fixups for 6010/M4V */
203 if (solo_dev->type == SOLO_DEV_6010) {
204 u16 fps = solo_dev->fps * 1000;
205 u16 interval = solo_enc->interval * 1000;
206
207 vop = solo_enc->vop;
208
209 /* Frame rate and interval */
210 vop[22] = fps >> 4;
211 vop[23] = ((fps << 4) & 0xf0) | 0x0c
212 | ((interval >> 13) & 0x3);
213 vop[24] = (interval >> 5) & 0xff;
214 vop[25] = ((interval << 3) & 0xf8) | 0x04;
215 }
216
217 solo_enc->vop_len = vop_len;
218
219 /* Now handle the jpeg header */
220 vop = solo_enc->jpeg_header;
221 vop[SOF0_START + 5] = 0xff & (solo_enc->height >> 8);
222 vop[SOF0_START + 6] = 0xff & solo_enc->height;
223 vop[SOF0_START + 7] = 0xff & (solo_enc->width >> 8);
224 vop[SOF0_START + 8] = 0xff & solo_enc->width;
225
226 memcpy(vop + DQT_START,
227 jpeg_dqt[solo_g_jpeg_qp(solo_dev, solo_enc->ch)], DQT_LEN);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400228}
229
Hans Verkuil382c31a2013-03-15 12:04:14 -0300230static int solo_enc_on(struct solo_enc_dev *solo_enc)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400231{
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400232 u8 ch = solo_enc->ch;
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100233 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400234 u8 interval;
235
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400236 solo_update_mode(solo_enc);
237
Hans Verkuil382c31a2013-03-15 12:04:14 -0300238 /* Make sure to do a bandwidth check */
239 if (solo_enc->bw_weight > solo_dev->enc_bw_remain)
240 return -EBUSY;
Hans Verkuil15513c12013-03-15 13:16:49 -0300241 solo_enc->sequence = 0;
Hans Verkuil382c31a2013-03-15 12:04:14 -0300242 solo_dev->enc_bw_remain -= solo_enc->bw_weight;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400243
Hans Verkuila7eb9312013-03-18 08:41:13 -0300244 if (solo_enc->type == SOLO_ENC_TYPE_EXT)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400245 solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(ch), 1);
246
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400247 /* Disable all encoding for this channel */
248 solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), 0);
249
250 /* Common for both std and ext encoding */
251 solo_reg_write(solo_dev, SOLO_VE_CH_INTL(ch),
252 solo_enc->interlaced ? 1 : 0);
253
254 if (solo_enc->interlaced)
255 interval = solo_enc->interval - 1;
256 else
257 interval = solo_enc->interval;
258
259 /* Standard encoding only */
260 solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), solo_enc->gop);
261 solo_reg_write(solo_dev, SOLO_VE_CH_QP(ch), solo_enc->qp);
262 solo_reg_write(solo_dev, SOLO_CAP_CH_INTV(ch), interval);
263
264 /* Extended encoding only */
265 solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(ch), solo_enc->gop);
266 solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(ch), solo_enc->qp);
267 solo_reg_write(solo_dev, SOLO_CAP_CH_INTV_E(ch), interval);
268
269 /* Enables the standard encoder */
270 solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), solo_enc->mode);
271
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400272 return 0;
273}
274
Hans Verkuil382c31a2013-03-15 12:04:14 -0300275static void solo_enc_off(struct solo_enc_dev *solo_enc)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400276{
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100277 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400278
Hans Verkuildcae5da2013-03-25 05:35:17 -0300279 solo_dev->enc_bw_remain += solo_enc->bw_weight;
280
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400281 solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(solo_enc->ch), 0);
282 solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0);
283}
284
Hans Verkuildcae5da2013-03-25 05:35:17 -0300285static int enc_get_mpeg_dma(struct solo_dev *solo_dev, dma_addr_t dma,
286 unsigned int off, unsigned int size)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400287{
288 int ret;
289
290 if (off > SOLO_MP4E_EXT_SIZE(solo_dev))
291 return -EINVAL;
292
Hans Verkuildcae5da2013-03-25 05:35:17 -0300293 /* Single shot */
Ben Collinsf62de9b2010-11-04 22:51:17 -0400294 if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) {
Hans Verkuildcae5da2013-03-25 05:35:17 -0300295 return solo_p2m_dma_t(solo_dev, 0, dma,
296 SOLO_MP4E_EXT_ADDR(solo_dev) + off, size,
297 0, 0);
Ben Collinsf62de9b2010-11-04 22:51:17 -0400298 }
299
300 /* Buffer wrap */
Hans Verkuildcae5da2013-03-25 05:35:17 -0300301 ret = solo_p2m_dma_t(solo_dev, 0, dma,
Ben Collinsf62de9b2010-11-04 22:51:17 -0400302 SOLO_MP4E_EXT_ADDR(solo_dev) + off,
Hans Verkuildcae5da2013-03-25 05:35:17 -0300303 SOLO_MP4E_EXT_SIZE(solo_dev) - off, 0, 0);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400304
Hans Verkuildcae5da2013-03-25 05:35:17 -0300305 if (!ret) {
306 ret = solo_p2m_dma_t(solo_dev, 0,
307 dma + SOLO_MP4E_EXT_SIZE(solo_dev) - off,
308 SOLO_MP4E_EXT_ADDR(solo_dev),
309 size + off - SOLO_MP4E_EXT_SIZE(solo_dev), 0, 0);
Ben Collinsf62de9b2010-11-04 22:51:17 -0400310 }
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400311
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400312 return ret;
313}
314
Hans Verkuildcae5da2013-03-25 05:35:17 -0300315/* Build a descriptor queue out of an SG list and send it to the P2M for
316 * processing. */
Hans Verkuila7eb9312013-03-18 08:41:13 -0300317static int solo_send_desc(struct solo_enc_dev *solo_enc, int skip,
Ricardo Ribalda22301242013-08-02 10:20:00 -0300318 struct sg_table *vbuf, int off, int size,
Hans Verkuildcae5da2013-03-25 05:35:17 -0300319 unsigned int base, unsigned int base_size)
Ben Collinsf62de9b2010-11-04 22:51:17 -0400320{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300321 struct solo_dev *solo_dev = solo_enc->solo_dev;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300322 struct scatterlist *sg;
323 int i;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400324 int ret;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400325
Hans Verkuildcae5da2013-03-25 05:35:17 -0300326 if (WARN_ON_ONCE(size > FRAME_BUF_SIZE))
Ben Collinsf62de9b2010-11-04 22:51:17 -0400327 return -EINVAL;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400328
Hans Verkuila7eb9312013-03-18 08:41:13 -0300329 solo_enc->desc_count = 1;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400330
Ricardo Ribalda22301242013-08-02 10:20:00 -0300331 for_each_sg(vbuf->sgl, sg, vbuf->nents, i) {
Hans Verkuildcae5da2013-03-25 05:35:17 -0300332 struct solo_p2m_desc *desc;
333 dma_addr_t dma;
334 int len;
335 int left = base_size - off;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400336
Hans Verkuila7eb9312013-03-18 08:41:13 -0300337 desc = &solo_enc->desc_items[solo_enc->desc_count++];
Hans Verkuildcae5da2013-03-25 05:35:17 -0300338 dma = sg_dma_address(sg);
339 len = sg_dma_len(sg);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400340
Hans Verkuildcae5da2013-03-25 05:35:17 -0300341 /* We assume this is smaller than the scatter size */
342 BUG_ON(skip >= len);
343 if (skip) {
344 len -= skip;
345 dma += skip;
346 size -= skip;
347 skip = 0;
348 }
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400349
Hans Verkuildcae5da2013-03-25 05:35:17 -0300350 len = min(len, size);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400351
Hans Verkuildcae5da2013-03-25 05:35:17 -0300352 if (len <= left) {
353 /* Single descriptor */
354 solo_p2m_fill_desc(desc, 0, dma, base + off,
355 len, 0, 0);
Ben Collinsf62de9b2010-11-04 22:51:17 -0400356 } else {
Hans Verkuildcae5da2013-03-25 05:35:17 -0300357 /* Buffer wrap */
358 /* XXX: Do these as separate DMA requests, to avoid
359 timeout errors triggered by awkwardly sized
360 descriptors. See
361 <https://github.com/bluecherrydvr/solo6x10/issues/8>
362 */
363 ret = solo_p2m_dma_t(solo_dev, 0, dma, base + off,
364 left, 0, 0);
365 if (ret)
366 return ret;
367
368 ret = solo_p2m_dma_t(solo_dev, 0, dma + left, base,
369 len - left, 0, 0);
370 if (ret)
371 return ret;
372
Hans Verkuila7eb9312013-03-18 08:41:13 -0300373 solo_enc->desc_count--;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300374 }
375
376 size -= len;
377 if (size <= 0)
378 break;
379
380 off += len;
381 if (off >= base_size)
382 off -= base_size;
383
384 /* Because we may use two descriptors per loop */
Hans Verkuila7eb9312013-03-18 08:41:13 -0300385 if (solo_enc->desc_count >= (solo_enc->desc_nelts - 1)) {
386 ret = solo_p2m_dma_desc(solo_dev, solo_enc->desc_items,
387 solo_enc->desc_dma,
388 solo_enc->desc_count - 1);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300389 if (ret)
390 return ret;
Hans Verkuila7eb9312013-03-18 08:41:13 -0300391 solo_enc->desc_count = 1;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400392 }
393 }
394
Hans Verkuila7eb9312013-03-18 08:41:13 -0300395 if (solo_enc->desc_count <= 1)
Hans Verkuildcae5da2013-03-25 05:35:17 -0300396 return 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400397
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200398 return solo_p2m_dma_desc(solo_dev, solo_enc->desc_items,
399 solo_enc->desc_dma, solo_enc->desc_count - 1);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400400}
401
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300402/* Extract values from VOP header - VE_STATUSxx */
403static inline int vop_interlaced(const vop_header *vh)
404{
405 return (__le32_to_cpu((*vh)[0]) >> 30) & 1;
406}
407
408static inline u8 vop_channel(const vop_header *vh)
409{
410 return (__le32_to_cpu((*vh)[0]) >> 24) & 0x1F;
411}
412
413static inline u8 vop_type(const vop_header *vh)
414{
415 return (__le32_to_cpu((*vh)[0]) >> 22) & 3;
416}
417
418static inline u32 vop_mpeg_size(const vop_header *vh)
419{
420 return __le32_to_cpu((*vh)[0]) & 0xFFFFF;
421}
422
423static inline u8 vop_hsize(const vop_header *vh)
424{
425 return (__le32_to_cpu((*vh)[1]) >> 8) & 0xFF;
426}
427
428static inline u8 vop_vsize(const vop_header *vh)
429{
430 return __le32_to_cpu((*vh)[1]) & 0xFF;
431}
432
433static inline u32 vop_mpeg_offset(const vop_header *vh)
434{
435 return __le32_to_cpu((*vh)[2]);
436}
437
438static inline u32 vop_jpeg_offset(const vop_header *vh)
439{
440 return __le32_to_cpu((*vh)[3]);
441}
442
443static inline u32 vop_jpeg_size(const vop_header *vh)
444{
445 return __le32_to_cpu((*vh)[4]) & 0xFFFFF;
446}
447
448static inline u32 vop_sec(const vop_header *vh)
449{
450 return __le32_to_cpu((*vh)[5]);
451}
452
453static inline u32 vop_usec(const vop_header *vh)
454{
455 return __le32_to_cpu((*vh)[6]);
456}
457
Hans Verkuil382c31a2013-03-15 12:04:14 -0300458static int solo_fill_jpeg(struct solo_enc_dev *solo_enc,
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300459 struct vb2_buffer *vb, const vop_header *vh)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400460{
Junghak Sung2d700712015-09-22 10:30:30 -0300461 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100462 struct solo_dev *solo_dev = solo_enc->solo_dev;
Junghak Sung2d700712015-09-22 10:30:30 -0300463 struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300464 int frame_size;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400465
Junghak Sung2d700712015-09-22 10:30:30 -0300466 vbuf->flags |= V4L2_BUF_FLAG_KEYFRAME;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400467
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300468 if (vb2_plane_size(vb, 0) < vop_jpeg_size(vh) + solo_enc->jpeg_len)
Hans Verkuildcae5da2013-03-25 05:35:17 -0300469 return -EIO;
470
Andreea-Cristina Bernat0cb6dfd2014-03-16 18:00:01 -0700471 frame_size = ALIGN(vop_jpeg_size(vh) + solo_enc->jpeg_len, DMA_ALIGN);
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300472 vb2_set_plane_payload(vb, 0, vop_jpeg_size(vh) + solo_enc->jpeg_len);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300473
Junghak Sung2d700712015-09-22 10:30:30 -0300474 return solo_send_desc(solo_enc, solo_enc->jpeg_len, sgt,
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300475 vop_jpeg_offset(vh) - SOLO_JPEG_EXT_ADDR(solo_dev),
476 frame_size, SOLO_JPEG_EXT_ADDR(solo_dev),
477 SOLO_JPEG_EXT_SIZE(solo_dev));
Hans Verkuildcae5da2013-03-25 05:35:17 -0300478}
479
Hans Verkuil382c31a2013-03-15 12:04:14 -0300480static int solo_fill_mpeg(struct solo_enc_dev *solo_enc,
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300481 struct vb2_buffer *vb, const vop_header *vh)
Hans Verkuildcae5da2013-03-25 05:35:17 -0300482{
Junghak Sung2d700712015-09-22 10:30:30 -0300483 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300484 struct solo_dev *solo_dev = solo_enc->solo_dev;
Junghak Sung2d700712015-09-22 10:30:30 -0300485 struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300486 int frame_off, frame_size;
487 int skip = 0;
488
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300489 if (vb2_plane_size(vb, 0) < vop_mpeg_size(vh))
Hans Verkuildcae5da2013-03-25 05:35:17 -0300490 return -EIO;
491
Hans Verkuildcae5da2013-03-25 05:35:17 -0300492 /* If this is a key frame, add extra header */
Junghak Sung2d700712015-09-22 10:30:30 -0300493 vbuf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_PFRAME |
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200494 V4L2_BUF_FLAG_BFRAME);
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300495 if (!vop_type(vh)) {
Hans Verkuildcae5da2013-03-25 05:35:17 -0300496 skip = solo_enc->vop_len;
Junghak Sung2d700712015-09-22 10:30:30 -0300497 vbuf->flags |= V4L2_BUF_FLAG_KEYFRAME;
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200498 vb2_set_plane_payload(vb, 0, vop_mpeg_size(vh) +
499 solo_enc->vop_len);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300500 } else {
Junghak Sung2d700712015-09-22 10:30:30 -0300501 vbuf->flags |= V4L2_BUF_FLAG_PFRAME;
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300502 vb2_set_plane_payload(vb, 0, vop_mpeg_size(vh));
Hans Verkuildcae5da2013-03-25 05:35:17 -0300503 }
504
505 /* Now get the actual mpeg payload */
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200506 frame_off = (vop_mpeg_offset(vh) - SOLO_MP4E_EXT_ADDR(solo_dev) +
507 sizeof(*vh)) % SOLO_MP4E_EXT_SIZE(solo_dev);
Andreea-Cristina Bernat0cb6dfd2014-03-16 18:00:01 -0700508 frame_size = ALIGN(vop_mpeg_size(vh) + skip, DMA_ALIGN);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300509
Junghak Sung2d700712015-09-22 10:30:30 -0300510 return solo_send_desc(solo_enc, skip, sgt, frame_off, frame_size,
Hans Verkuil382c31a2013-03-15 12:04:14 -0300511 SOLO_MP4E_EXT_ADDR(solo_dev),
512 SOLO_MP4E_EXT_SIZE(solo_dev));
Hans Verkuildcae5da2013-03-25 05:35:17 -0300513}
514
Hans Verkuila7eb9312013-03-18 08:41:13 -0300515static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc,
Hans Verkuil382c31a2013-03-15 12:04:14 -0300516 struct vb2_buffer *vb, struct solo_enc_buf *enc_buf)
Hans Verkuildcae5da2013-03-25 05:35:17 -0300517{
Junghak Sung2d700712015-09-22 10:30:30 -0300518 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300519 const vop_header *vh = enc_buf->vh;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300520 int ret;
521
Ismael Luceno16af6902013-04-18 10:56:35 -0300522 switch (solo_enc->fmt) {
523 case V4L2_PIX_FMT_MPEG4:
524 case V4L2_PIX_FMT_H264:
Hans Verkuil382c31a2013-03-15 12:04:14 -0300525 ret = solo_fill_mpeg(solo_enc, vb, vh);
Ismael Luceno16af6902013-04-18 10:56:35 -0300526 break;
527 default: /* V4L2_PIX_FMT_MJPEG */
Hans Verkuil382c31a2013-03-15 12:04:14 -0300528 ret = solo_fill_jpeg(solo_enc, vb, vh);
Ismael Luceno16af6902013-04-18 10:56:35 -0300529 break;
530 }
Hans Verkuildcae5da2013-03-25 05:35:17 -0300531
Hans Verkuil382c31a2013-03-15 12:04:14 -0300532 if (!ret) {
Junghak Sung2d700712015-09-22 10:30:30 -0300533 vbuf->sequence = solo_enc->sequence++;
Junghak Sungd6dd6452015-11-03 08:16:37 -0200534 vb->timestamp = ktime_get_ns();
Hans Verkuil316d9e82014-01-27 11:16:05 -0300535
536 /* Check for motion flags */
Andrey Utkine476f4e2014-11-05 17:11:14 -0300537 if (solo_is_motion_on(solo_enc) && enc_buf->motion) {
Hans Verkuil316d9e82014-01-27 11:16:05 -0300538 struct v4l2_event ev = {
539 .type = V4L2_EVENT_MOTION_DET,
540 .u.motion_det = {
Junghak Sung2d700712015-09-22 10:30:30 -0300541 .flags
542 = V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ,
543 .frame_sequence = vbuf->sequence,
Hans Verkuil316d9e82014-01-27 11:16:05 -0300544 .region_mask = enc_buf->motion ? 1 : 0,
545 },
546 };
547
Hans Verkuil316d9e82014-01-27 11:16:05 -0300548 v4l2_event_queue(solo_enc->vfd, &ev);
549 }
Hans Verkuildcae5da2013-03-25 05:35:17 -0300550 }
551
Hans Verkuil382c31a2013-03-15 12:04:14 -0300552 vb2_buffer_done(vb, ret ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
553
Hans Verkuildcae5da2013-03-25 05:35:17 -0300554 return ret;
555}
556
557static void solo_enc_handle_one(struct solo_enc_dev *solo_enc,
558 struct solo_enc_buf *enc_buf)
559{
Hans Verkuil382c31a2013-03-15 12:04:14 -0300560 struct solo_vb2_buf *vb;
Hans Verkuila7eb9312013-03-18 08:41:13 -0300561 unsigned long flags;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300562
Hans Verkuil382c31a2013-03-15 12:04:14 -0300563 mutex_lock(&solo_enc->lock);
Hans Verkuila7eb9312013-03-18 08:41:13 -0300564 if (solo_enc->type != enc_buf->type)
565 goto unlock;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300566
Hans Verkuila7eb9312013-03-18 08:41:13 -0300567 spin_lock_irqsave(&solo_enc->av_lock, flags);
Hans Verkuil382c31a2013-03-15 12:04:14 -0300568 if (list_empty(&solo_enc->vidq_active)) {
569 spin_unlock_irqrestore(&solo_enc->av_lock, flags);
570 goto unlock;
571 }
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200572 vb = list_first_entry(&solo_enc->vidq_active, struct solo_vb2_buf,
573 list);
Hans Verkuil382c31a2013-03-15 12:04:14 -0300574 list_del(&vb->list);
Hans Verkuila7eb9312013-03-18 08:41:13 -0300575 spin_unlock_irqrestore(&solo_enc->av_lock, flags);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400576
Junghak Sung2d700712015-09-22 10:30:30 -0300577 solo_enc_fillbuf(solo_enc, &vb->vb.vb2_buf, enc_buf);
Hans Verkuila7eb9312013-03-18 08:41:13 -0300578unlock:
Hans Verkuil382c31a2013-03-15 12:04:14 -0300579 mutex_unlock(&solo_enc->lock);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400580}
581
Hans Verkuildcae5da2013-03-25 05:35:17 -0300582void solo_enc_v4l2_isr(struct solo_dev *solo_dev)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400583{
Hans Verkuildcae5da2013-03-25 05:35:17 -0300584 wake_up_interruptible_all(&solo_dev->ring_thread_wait);
585}
586
587static void solo_handle_ring(struct solo_dev *solo_dev)
588{
589 for (;;) {
590 struct solo_enc_dev *solo_enc;
591 struct solo_enc_buf enc_buf;
592 u32 mpeg_current, off;
593 u8 ch;
594 u8 cur_q;
595
596 /* Check if the hardware has any new ones in the queue */
597 cur_q = solo_reg_read(solo_dev, SOLO_VE_STATE(11)) & 0xff;
598 if (cur_q == solo_dev->enc_idx)
599 break;
600
601 mpeg_current = solo_reg_read(solo_dev,
602 SOLO_VE_MPEG4_QUE(solo_dev->enc_idx));
603 solo_dev->enc_idx = (solo_dev->enc_idx + 1) % MP4_QS;
604
605 ch = (mpeg_current >> 24) & 0x1f;
606 off = mpeg_current & 0x00ffffff;
607
608 if (ch >= SOLO_MAX_CHANNELS) {
609 ch -= SOLO_MAX_CHANNELS;
610 enc_buf.type = SOLO_ENC_TYPE_EXT;
611 } else
612 enc_buf.type = SOLO_ENC_TYPE_STD;
613
614 solo_enc = solo_dev->v4l2_enc[ch];
615 if (solo_enc == NULL) {
616 dev_err(&solo_dev->pdev->dev,
617 "Got spurious packet for channel %d\n", ch);
618 continue;
619 }
620
621 /* FAIL... */
622 if (enc_get_mpeg_dma(solo_dev, solo_dev->vh_dma, off,
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300623 sizeof(vop_header)))
Hans Verkuildcae5da2013-03-25 05:35:17 -0300624 continue;
625
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300626 enc_buf.vh = solo_dev->vh_buf;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300627
628 /* Sanity check */
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200629 if (vop_mpeg_offset(enc_buf.vh) !=
630 SOLO_MP4E_EXT_ADDR(solo_dev) + off)
Hans Verkuildcae5da2013-03-25 05:35:17 -0300631 continue;
632
633 if (solo_motion_detected(solo_enc))
634 enc_buf.motion = 1;
635 else
636 enc_buf.motion = 0;
637
638 solo_enc_handle_one(solo_enc, &enc_buf);
639 }
640}
641
642static int solo_ring_thread(void *data)
643{
644 struct solo_dev *solo_dev = data;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400645 DECLARE_WAITQUEUE(wait, current);
646
647 set_freezable();
Hans Verkuildcae5da2013-03-25 05:35:17 -0300648 add_wait_queue(&solo_dev->ring_thread_wait, &wait);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400649
650 for (;;) {
651 long timeout = schedule_timeout_interruptible(HZ);
Hans Verkuil1c6f3db2014-07-17 20:40:22 -0300652
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400653 if (timeout == -ERESTARTSYS || kthread_should_stop())
654 break;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300655 solo_handle_ring(solo_dev);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400656 try_to_freeze();
657 }
658
Hans Verkuildcae5da2013-03-25 05:35:17 -0300659 remove_wait_queue(&solo_dev->ring_thread_wait, &wait);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400660
Ben Collinsf62de9b2010-11-04 22:51:17 -0400661 return 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400662}
663
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200664static int solo_enc_queue_setup(struct vb2_queue *q,
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200665 unsigned int *num_buffers,
666 unsigned int *num_planes, unsigned int sizes[],
Hans Verkuil36c0f8b2016-04-15 09:15:05 -0300667 struct device *alloc_devs[])
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400668{
Hans Verkuil382c31a2013-03-15 12:04:14 -0300669 sizes[0] = FRAME_BUF_SIZE;
670 *num_planes = 1;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400671
Hans Verkuil382c31a2013-03-15 12:04:14 -0300672 if (*num_buffers < MIN_VID_BUFFERS)
673 *num_buffers = MIN_VID_BUFFERS;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400674
Ben Collinsf62de9b2010-11-04 22:51:17 -0400675 return 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400676}
677
Hans Verkuil382c31a2013-03-15 12:04:14 -0300678static void solo_enc_buf_queue(struct vb2_buffer *vb)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400679{
Junghak Sung2d700712015-09-22 10:30:30 -0300680 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
Hans Verkuil382c31a2013-03-15 12:04:14 -0300681 struct vb2_queue *vq = vb->vb2_queue;
682 struct solo_enc_dev *solo_enc = vb2_get_drv_priv(vq);
683 struct solo_vb2_buf *solo_vb =
Junghak Sung2d700712015-09-22 10:30:30 -0300684 container_of(vbuf, struct solo_vb2_buf, vb);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400685
Hans Verkuil382c31a2013-03-15 12:04:14 -0300686 spin_lock(&solo_enc->av_lock);
687 list_add_tail(&solo_vb->list, &solo_enc->vidq_active);
688 spin_unlock(&solo_enc->av_lock);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400689}
690
Hans Verkuildcae5da2013-03-25 05:35:17 -0300691static int solo_ring_start(struct solo_dev *solo_dev)
692{
Hans Verkuildcae5da2013-03-25 05:35:17 -0300693 solo_dev->ring_thread = kthread_run(solo_ring_thread, solo_dev,
694 SOLO6X10_NAME "_ring");
695 if (IS_ERR(solo_dev->ring_thread)) {
696 int err = PTR_ERR(solo_dev->ring_thread);
Hans Verkuil1c6f3db2014-07-17 20:40:22 -0300697
Hans Verkuildcae5da2013-03-25 05:35:17 -0300698 solo_dev->ring_thread = NULL;
699 return err;
700 }
701
702 solo_irq_on(solo_dev, SOLO_IRQ_ENCODER);
703
704 return 0;
705}
706
707static void solo_ring_stop(struct solo_dev *solo_dev)
708{
Hans Verkuildcae5da2013-03-25 05:35:17 -0300709 if (solo_dev->ring_thread) {
710 kthread_stop(solo_dev->ring_thread);
711 solo_dev->ring_thread = NULL;
712 }
713
714 solo_irq_off(solo_dev, SOLO_IRQ_ENCODER);
715}
716
Hans Verkuil382c31a2013-03-15 12:04:14 -0300717static int solo_enc_start_streaming(struct vb2_queue *q, unsigned int count)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400718{
Hans Verkuil382c31a2013-03-15 12:04:14 -0300719 struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400720
Andrey Utkin670390c2014-10-29 13:03:53 -0300721 return solo_enc_on(solo_enc);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400722}
723
Hans Verkuile37559b2014-04-17 02:47:21 -0300724static void solo_enc_stop_streaming(struct vb2_queue *q)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400725{
Hans Verkuil382c31a2013-03-15 12:04:14 -0300726 struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q);
Andrey Utkin9ccd1802014-11-06 18:06:18 -0300727 unsigned long flags;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300728
Andrey Utkin9ccd1802014-11-06 18:06:18 -0300729 spin_lock_irqsave(&solo_enc->av_lock, flags);
Hans Verkuila7eb9312013-03-18 08:41:13 -0300730 solo_enc_off(solo_enc);
Andrey Utkin9ccd1802014-11-06 18:06:18 -0300731 while (!list_empty(&solo_enc->vidq_active)) {
732 struct solo_vb2_buf *buf = list_entry(
733 solo_enc->vidq_active.next,
734 struct solo_vb2_buf, list);
735
736 list_del(&buf->list);
Junghak Sung2d700712015-09-22 10:30:30 -0300737 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
Andrey Utkin9ccd1802014-11-06 18:06:18 -0300738 }
739 spin_unlock_irqrestore(&solo_enc->av_lock, flags);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400740}
741
Hans Verkuild790b7e2014-11-24 08:50:31 -0300742static void solo_enc_buf_finish(struct vb2_buffer *vb)
743{
Junghak Sung2d700712015-09-22 10:30:30 -0300744 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
Hans Verkuild790b7e2014-11-24 08:50:31 -0300745 struct solo_enc_dev *solo_enc = vb2_get_drv_priv(vb->vb2_queue);
Junghak Sung2d700712015-09-22 10:30:30 -0300746 struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
Hans Verkuild790b7e2014-11-24 08:50:31 -0300747
748 switch (solo_enc->fmt) {
749 case V4L2_PIX_FMT_MPEG4:
750 case V4L2_PIX_FMT_H264:
Junghak Sung2d700712015-09-22 10:30:30 -0300751 if (vbuf->flags & V4L2_BUF_FLAG_KEYFRAME)
752 sg_copy_from_buffer(sgt->sgl, sgt->nents,
Hans Verkuild790b7e2014-11-24 08:50:31 -0300753 solo_enc->vop, solo_enc->vop_len);
754 break;
755 default: /* V4L2_PIX_FMT_MJPEG */
Junghak Sung2d700712015-09-22 10:30:30 -0300756 sg_copy_from_buffer(sgt->sgl, sgt->nents,
Hans Verkuild790b7e2014-11-24 08:50:31 -0300757 solo_enc->jpeg_header, solo_enc->jpeg_len);
758 break;
759 }
760}
761
Julia Lawall10accd22016-09-08 20:59:18 -0300762static const struct vb2_ops solo_enc_video_qops = {
Hans Verkuil382c31a2013-03-15 12:04:14 -0300763 .queue_setup = solo_enc_queue_setup,
764 .buf_queue = solo_enc_buf_queue,
Hans Verkuild790b7e2014-11-24 08:50:31 -0300765 .buf_finish = solo_enc_buf_finish,
Hans Verkuil382c31a2013-03-15 12:04:14 -0300766 .start_streaming = solo_enc_start_streaming,
767 .stop_streaming = solo_enc_stop_streaming,
768 .wait_prepare = vb2_ops_wait_prepare,
769 .wait_finish = vb2_ops_wait_finish,
770};
771
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400772static int solo_enc_querycap(struct file *file, void *priv,
773 struct v4l2_capability *cap)
774{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300775 struct solo_enc_dev *solo_enc = video_drvdata(file);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100776 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400777
Mauro Carvalho Chehabcc1e6312018-09-10 16:20:42 -0400778 strscpy(cap->driver, SOLO6X10_NAME, sizeof(cap->driver));
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100779 snprintf(cap->card, sizeof(cap->card), "Softlogic 6x10 Enc %d",
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400780 solo_enc->ch);
Hans Verkuil20c5f492013-03-12 18:03:20 -0300781 snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400782 pci_name(solo_dev->pdev));
Hans Verkuil20c5f492013-03-12 18:03:20 -0300783 cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
784 V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
785 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400786 return 0;
787}
788
789static int solo_enc_enum_input(struct file *file, void *priv,
790 struct v4l2_input *input)
791{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300792 struct solo_enc_dev *solo_enc = video_drvdata(file);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100793 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400794
795 if (input->index)
796 return -EINVAL;
797
798 snprintf(input->name, sizeof(input->name), "Encoder %d",
799 solo_enc->ch + 1);
800 input->type = V4L2_INPUT_TYPE_CAMERA;
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300801 input->std = solo_enc->vfd->tvnorms;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400802
803 if (!tw28_get_video_status(solo_dev, solo_enc->ch))
804 input->status = V4L2_IN_ST_NO_SIGNAL;
805
806 return 0;
807}
808
Hans Verkuildcae5da2013-03-25 05:35:17 -0300809static int solo_enc_set_input(struct file *file, void *priv,
810 unsigned int index)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400811{
812 if (index)
813 return -EINVAL;
814
815 return 0;
816}
817
818static int solo_enc_get_input(struct file *file, void *priv,
819 unsigned int *index)
820{
821 *index = 0;
822
823 return 0;
824}
825
826static int solo_enc_enum_fmt_cap(struct file *file, void *priv,
827 struct v4l2_fmtdesc *f)
828{
Ismael Luceno16af6902013-04-18 10:56:35 -0300829 struct solo_enc_dev *solo_enc = video_drvdata(file);
830 int dev_type = solo_enc->solo_dev->type;
831
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400832 switch (f->index) {
833 case 0:
Ismael Luceno16af6902013-04-18 10:56:35 -0300834 switch (dev_type) {
835 case SOLO_DEV_6010:
836 f->pixelformat = V4L2_PIX_FMT_MPEG4;
Mauro Carvalho Chehabcc1e6312018-09-10 16:20:42 -0400837 strscpy(f->description, "MPEG-4 part 2",
838 sizeof(f->description));
Ismael Luceno16af6902013-04-18 10:56:35 -0300839 break;
840 case SOLO_DEV_6110:
841 f->pixelformat = V4L2_PIX_FMT_H264;
Mauro Carvalho Chehabcc1e6312018-09-10 16:20:42 -0400842 strscpy(f->description, "H.264", sizeof(f->description));
Ismael Luceno16af6902013-04-18 10:56:35 -0300843 break;
844 }
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400845 break;
846 case 1:
847 f->pixelformat = V4L2_PIX_FMT_MJPEG;
Mauro Carvalho Chehabcc1e6312018-09-10 16:20:42 -0400848 strscpy(f->description, "MJPEG", sizeof(f->description));
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400849 break;
850 default:
851 return -EINVAL;
852 }
853
854 f->flags = V4L2_FMT_FLAG_COMPRESSED;
855
856 return 0;
857}
858
Ismael Luceno16af6902013-04-18 10:56:35 -0300859static inline int solo_valid_pixfmt(u32 pixfmt, int dev_type)
860{
861 return (pixfmt == V4L2_PIX_FMT_H264 && dev_type == SOLO_DEV_6110)
862 || (pixfmt == V4L2_PIX_FMT_MPEG4 && dev_type == SOLO_DEV_6010)
863 || pixfmt == V4L2_PIX_FMT_MJPEG ? 0 : -EINVAL;
864}
865
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400866static int solo_enc_try_fmt_cap(struct file *file, void *priv,
867 struct v4l2_format *f)
868{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300869 struct solo_enc_dev *solo_enc = video_drvdata(file);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100870 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400871 struct v4l2_pix_format *pix = &f->fmt.pix;
872
Ismael Luceno16af6902013-04-18 10:56:35 -0300873 if (solo_valid_pixfmt(pix->pixelformat, solo_dev->type))
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400874 return -EINVAL;
875
Krzysztof Hałasa98ab1c92011-02-11 13:10:30 +0100876 if (pix->width < solo_dev->video_hsize ||
877 pix->height < solo_dev->video_vsize << 1) {
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400878 /* Default to CIF 1/2 size */
879 pix->width = solo_dev->video_hsize >> 1;
880 pix->height = solo_dev->video_vsize;
Krzysztof Hałasa98ab1c92011-02-11 13:10:30 +0100881 } else {
882 /* Full frame */
883 pix->width = solo_dev->video_hsize;
884 pix->height = solo_dev->video_vsize << 1;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400885 }
886
Hans Verkuil016afda2013-03-12 18:43:21 -0300887 switch (pix->field) {
888 case V4L2_FIELD_NONE:
889 case V4L2_FIELD_INTERLACED:
890 break;
891 case V4L2_FIELD_ANY:
892 default:
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400893 pix->field = V4L2_FIELD_INTERLACED;
Hans Verkuil016afda2013-03-12 18:43:21 -0300894 break;
895 }
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400896
897 /* Just set these */
898 pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
899 pix->sizeimage = FRAME_BUF_SIZE;
Hans Verkuil94160492013-03-12 18:47:03 -0300900 pix->bytesperline = 0;
Hans Verkuil016afda2013-03-12 18:43:21 -0300901 pix->priv = 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400902
903 return 0;
904}
905
906static int solo_enc_set_fmt_cap(struct file *file, void *priv,
907 struct v4l2_format *f)
908{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300909 struct solo_enc_dev *solo_enc = video_drvdata(file);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100910 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400911 struct v4l2_pix_format *pix = &f->fmt.pix;
912 int ret;
913
Hans Verkuil382c31a2013-03-15 12:04:14 -0300914 if (vb2_is_busy(&solo_enc->vidq))
915 return -EBUSY;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400916
facugaichafabbe62010-11-10 10:39:33 -0300917 ret = solo_enc_try_fmt_cap(file, priv, f);
Hans Verkuil016afda2013-03-12 18:43:21 -0300918 if (ret)
919 return ret;
920
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400921 if (pix->width == solo_dev->video_hsize)
922 solo_enc->mode = SOLO_ENC_MODE_D1;
923 else
924 solo_enc->mode = SOLO_ENC_MODE_CIF;
925
926 /* This does not change the encoder at all */
Hans Verkuila7eb9312013-03-18 08:41:13 -0300927 solo_enc->fmt = pix->pixelformat;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400928
Hans Verkuil69996872013-03-15 16:35:28 -0300929 /*
930 * More information is needed about these 'extended' types. As far
931 * as I can tell these are basically additional video streams with
932 * different MPEG encoding attributes that can run in parallel with
933 * the main stream. If so, then this should be implemented as a
934 * second video node. Abusing priv like this is certainly not the
935 * right approach.
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400936 if (pix->priv)
Hans Verkuila7eb9312013-03-18 08:41:13 -0300937 solo_enc->type = SOLO_ENC_TYPE_EXT;
Hans Verkuil69996872013-03-15 16:35:28 -0300938 */
Ismael Lucenocdcfe402013-04-12 18:28:33 -0300939 solo_update_mode(solo_enc);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300940 return 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400941}
942
943static int solo_enc_get_fmt_cap(struct file *file, void *priv,
944 struct v4l2_format *f)
945{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300946 struct solo_enc_dev *solo_enc = video_drvdata(file);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400947 struct v4l2_pix_format *pix = &f->fmt.pix;
948
949 pix->width = solo_enc->width;
950 pix->height = solo_enc->height;
Hans Verkuila7eb9312013-03-18 08:41:13 -0300951 pix->pixelformat = solo_enc->fmt;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400952 pix->field = solo_enc->interlaced ? V4L2_FIELD_INTERLACED :
953 V4L2_FIELD_NONE;
954 pix->sizeimage = FRAME_BUF_SIZE;
955 pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
Hans Verkuil016afda2013-03-12 18:43:21 -0300956 pix->priv = 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400957
958 return 0;
959}
960
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300961static int solo_enc_g_std(struct file *file, void *priv, v4l2_std_id *i)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400962{
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300963 struct solo_enc_dev *solo_enc = video_drvdata(file);
964 struct solo_dev *solo_dev = solo_enc->solo_dev;
965
966 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
967 *i = V4L2_STD_NTSC_M;
968 else
969 *i = V4L2_STD_PAL;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400970 return 0;
971}
972
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300973static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id std)
974{
975 struct solo_enc_dev *solo_enc = video_drvdata(file);
976
Hans Verkuil429df502014-01-13 06:58:12 -0300977 return solo_set_video_type(solo_enc->solo_dev, std & V4L2_STD_625_50);
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300978}
979
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400980static int solo_enum_framesizes(struct file *file, void *priv,
981 struct v4l2_frmsizeenum *fsize)
982{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300983 struct solo_enc_dev *solo_enc = video_drvdata(file);
984 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400985
Ismael Luceno16af6902013-04-18 10:56:35 -0300986 if (solo_valid_pixfmt(fsize->pixel_format, solo_dev->type))
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400987 return -EINVAL;
988
989 switch (fsize->index) {
990 case 0:
991 fsize->discrete.width = solo_dev->video_hsize >> 1;
992 fsize->discrete.height = solo_dev->video_vsize;
993 break;
994 case 1:
995 fsize->discrete.width = solo_dev->video_hsize;
996 fsize->discrete.height = solo_dev->video_vsize << 1;
997 break;
998 default:
999 return -EINVAL;
1000 }
1001
1002 fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1003
1004 return 0;
1005}
1006
1007static int solo_enum_frameintervals(struct file *file, void *priv,
1008 struct v4l2_frmivalenum *fintv)
1009{
Hans Verkuila7eb9312013-03-18 08:41:13 -03001010 struct solo_enc_dev *solo_enc = video_drvdata(file);
1011 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001012
Ismael Luceno16af6902013-04-18 10:56:35 -03001013 if (solo_valid_pixfmt(fintv->pixel_format, solo_dev->type))
Hans Verkuil016afda2013-03-12 18:43:21 -03001014 return -EINVAL;
1015 if (fintv->index)
1016 return -EINVAL;
1017 if ((fintv->width != solo_dev->video_hsize >> 1 ||
1018 fintv->height != solo_dev->video_vsize) &&
1019 (fintv->width != solo_dev->video_hsize ||
1020 fintv->height != solo_dev->video_vsize << 1))
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001021 return -EINVAL;
1022
1023 fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE;
1024
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001025 fintv->stepwise.min.numerator = 1;
Hans Verkuil016afda2013-03-12 18:43:21 -03001026 fintv->stepwise.min.denominator = solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001027
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001028 fintv->stepwise.max.numerator = 15;
Hans Verkuil016afda2013-03-12 18:43:21 -03001029 fintv->stepwise.max.denominator = solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001030
1031 fintv->stepwise.step.numerator = 1;
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001032 fintv->stepwise.step.denominator = solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001033
1034 return 0;
1035}
1036
1037static int solo_g_parm(struct file *file, void *priv,
1038 struct v4l2_streamparm *sp)
1039{
Hans Verkuila7eb9312013-03-18 08:41:13 -03001040 struct solo_enc_dev *solo_enc = video_drvdata(file);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001041 struct v4l2_captureparm *cp = &sp->parm.capture;
1042
1043 cp->capability = V4L2_CAP_TIMEPERFRAME;
1044 cp->timeperframe.numerator = solo_enc->interval;
Ismael Luceno88107672013-05-03 15:54:57 -03001045 cp->timeperframe.denominator = solo_enc->solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001046 cp->capturemode = 0;
1047 /* XXX: Shouldn't we be able to get/set this from videobuf? */
1048 cp->readbuffers = 2;
1049
Ben Collinsf62de9b2010-11-04 22:51:17 -04001050 return 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001051}
1052
Ismael Luceno88107672013-05-03 15:54:57 -03001053static inline int calc_interval(u8 fps, u32 n, u32 d)
1054{
1055 if (!n || !d)
1056 return 1;
1057 if (d == fps)
1058 return n;
1059 n *= fps;
1060 return min(15U, n / d + (n % d >= (fps >> 1)));
1061}
1062
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001063static int solo_s_parm(struct file *file, void *priv,
1064 struct v4l2_streamparm *sp)
1065{
Hans Verkuila7eb9312013-03-18 08:41:13 -03001066 struct solo_enc_dev *solo_enc = video_drvdata(file);
Ismael Luceno88107672013-05-03 15:54:57 -03001067 struct v4l2_fract *t = &sp->parm.capture.timeperframe;
1068 u8 fps = solo_enc->solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001069
Hans Verkuil382c31a2013-03-15 12:04:14 -03001070 if (vb2_is_streaming(&solo_enc->vidq))
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001071 return -EBUSY;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001072
Ismael Luceno88107672013-05-03 15:54:57 -03001073 solo_enc->interval = calc_interval(fps, t->numerator, t->denominator);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001074 solo_update_mode(solo_enc);
Ismael Luceno88107672013-05-03 15:54:57 -03001075 return solo_g_parm(file, priv, sp);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001076}
1077
Hans Verkuilc813bd32013-03-25 05:38:14 -03001078static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001079{
Hans Verkuilc813bd32013-03-25 05:38:14 -03001080 struct solo_enc_dev *solo_enc =
1081 container_of(ctrl->handler, struct solo_enc_dev, hdl);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +01001082 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001083 int err;
1084
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001085 switch (ctrl->id) {
1086 case V4L2_CID_BRIGHTNESS:
1087 case V4L2_CID_CONTRAST:
1088 case V4L2_CID_SATURATION:
1089 case V4L2_CID_HUE:
1090 case V4L2_CID_SHARPNESS:
1091 return tw28_set_ctrl_val(solo_dev, ctrl->id, solo_enc->ch,
Hans Verkuilc813bd32013-03-25 05:38:14 -03001092 ctrl->val);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001093 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
Hans Verkuilc813bd32013-03-25 05:38:14 -03001094 solo_enc->gop = ctrl->val;
Andrey Utkin63e9b452014-07-08 12:23:33 -03001095 solo_reg_write(solo_dev, SOLO_VE_CH_GOP(solo_enc->ch), solo_enc->gop);
1096 solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(solo_enc->ch), solo_enc->gop);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001097 return 0;
Andrey Utkin56981112014-07-08 12:23:32 -03001098 case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
1099 solo_enc->qp = ctrl->val;
Andrey Utkin63e9b452014-07-08 12:23:33 -03001100 solo_reg_write(solo_dev, SOLO_VE_CH_QP(solo_enc->ch), solo_enc->qp);
1101 solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(solo_enc->ch), solo_enc->qp);
Andrey Utkin56981112014-07-08 12:23:32 -03001102 return 0;
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001103 case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD:
1104 solo_enc->motion_thresh = ctrl->val << 8;
Hans Verkuilf5df0b72013-03-18 08:43:14 -03001105 if (!solo_enc->motion_global || !solo_enc->motion_enabled)
1106 return 0;
Aybuke Ozdemirfa917832014-03-13 02:20:20 +02001107 return solo_set_motion_threshold(solo_dev, solo_enc->ch,
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001108 solo_enc->motion_thresh);
1109 case V4L2_CID_DETECT_MD_MODE:
1110 solo_enc->motion_global = ctrl->val == V4L2_DETECT_MD_MODE_GLOBAL;
1111 solo_enc->motion_enabled = ctrl->val > V4L2_DETECT_MD_MODE_DISABLED;
Hans Verkuilf5df0b72013-03-18 08:43:14 -03001112 if (ctrl->val) {
1113 if (solo_enc->motion_global)
Hans Verkuil0a128302014-07-25 08:19:54 -03001114 err = solo_set_motion_threshold(solo_dev, solo_enc->ch,
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001115 solo_enc->motion_thresh);
Hans Verkuilf5df0b72013-03-18 08:43:14 -03001116 else
Hans Verkuil0a128302014-07-25 08:19:54 -03001117 err = solo_set_motion_block(solo_dev, solo_enc->ch,
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001118 solo_enc->md_thresholds->p_cur.p_u16);
Hans Verkuil0a128302014-07-25 08:19:54 -03001119 if (err)
1120 return err;
Hans Verkuildcae5da2013-03-25 05:35:17 -03001121 }
Hans Verkuilc813bd32013-03-25 05:38:14 -03001122 solo_motion_toggle(solo_enc, ctrl->val);
1123 return 0;
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001124 case V4L2_CID_DETECT_MD_THRESHOLD_GRID:
1125 if (solo_enc->motion_enabled && !solo_enc->motion_global)
1126 return solo_set_motion_block(solo_dev, solo_enc->ch,
1127 solo_enc->md_thresholds->p_new.p_u16);
1128 break;
Hans Verkuilc813bd32013-03-25 05:38:14 -03001129 case V4L2_CID_OSD_TEXT:
Mauro Carvalho Chehabcc1e6312018-09-10 16:20:42 -04001130 strscpy(solo_enc->osd_text, ctrl->p_new.p_char,
1131 sizeof(solo_enc->osd_text));
Hans Verkuil0a128302014-07-25 08:19:54 -03001132 return solo_osd_print(solo_enc);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001133 default:
1134 return -EINVAL;
1135 }
1136
1137 return 0;
1138}
1139
Hans Verkuil316d9e82014-01-27 11:16:05 -03001140static int solo_subscribe_event(struct v4l2_fh *fh,
1141 const struct v4l2_event_subscription *sub)
1142{
1143
1144 switch (sub->type) {
Hans Verkuil316d9e82014-01-27 11:16:05 -03001145 case V4L2_EVENT_MOTION_DET:
1146 /* Allow for up to 30 events (1 second for NTSC) to be
1147 * stored. */
1148 return v4l2_event_subscribe(fh, sub, 30, NULL);
Gustavo Padovanf4fde9a2017-02-15 15:55:30 -02001149 default:
1150 return v4l2_ctrl_subscribe_event(fh, sub);
Hans Verkuil316d9e82014-01-27 11:16:05 -03001151 }
Hans Verkuil316d9e82014-01-27 11:16:05 -03001152}
1153
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001154static const struct v4l2_file_operations solo_enc_fops = {
1155 .owner = THIS_MODULE,
Hans Verkuil382c31a2013-03-15 12:04:14 -03001156 .open = v4l2_fh_open,
1157 .release = vb2_fop_release,
1158 .read = vb2_fop_read,
1159 .poll = vb2_fop_poll,
1160 .mmap = vb2_fop_mmap,
1161 .unlocked_ioctl = video_ioctl2,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001162};
1163
1164static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = {
1165 .vidioc_querycap = solo_enc_querycap,
1166 .vidioc_s_std = solo_enc_s_std,
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001167 .vidioc_g_std = solo_enc_g_std,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001168 /* Input callbacks */
1169 .vidioc_enum_input = solo_enc_enum_input,
1170 .vidioc_s_input = solo_enc_set_input,
1171 .vidioc_g_input = solo_enc_get_input,
1172 /* Video capture format callbacks */
1173 .vidioc_enum_fmt_vid_cap = solo_enc_enum_fmt_cap,
1174 .vidioc_try_fmt_vid_cap = solo_enc_try_fmt_cap,
1175 .vidioc_s_fmt_vid_cap = solo_enc_set_fmt_cap,
1176 .vidioc_g_fmt_vid_cap = solo_enc_get_fmt_cap,
1177 /* Streaming I/O */
Hans Verkuil382c31a2013-03-15 12:04:14 -03001178 .vidioc_reqbufs = vb2_ioctl_reqbufs,
1179 .vidioc_querybuf = vb2_ioctl_querybuf,
1180 .vidioc_qbuf = vb2_ioctl_qbuf,
1181 .vidioc_dqbuf = vb2_ioctl_dqbuf,
1182 .vidioc_streamon = vb2_ioctl_streamon,
1183 .vidioc_streamoff = vb2_ioctl_streamoff,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001184 /* Frame size and interval */
1185 .vidioc_enum_framesizes = solo_enum_framesizes,
1186 .vidioc_enum_frameintervals = solo_enum_frameintervals,
1187 /* Video capture parameters */
1188 .vidioc_s_parm = solo_s_parm,
1189 .vidioc_g_parm = solo_g_parm,
Hans Verkuil94160492013-03-12 18:47:03 -03001190 /* Logging and events */
1191 .vidioc_log_status = v4l2_ctrl_log_status,
Hans Verkuil316d9e82014-01-27 11:16:05 -03001192 .vidioc_subscribe_event = solo_subscribe_event,
Hans Verkuil94160492013-03-12 18:47:03 -03001193 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001194};
1195
Hans Verkuildcae5da2013-03-25 05:35:17 -03001196static const struct video_device solo_enc_template = {
Krzysztof Hałasadecebab2011-02-11 13:38:20 +01001197 .name = SOLO6X10_NAME,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001198 .fops = &solo_enc_fops,
1199 .ioctl_ops = &solo_enc_ioctl_ops,
1200 .minor = -1,
1201 .release = video_device_release,
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001202 .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001203};
1204
Hans Verkuilc813bd32013-03-25 05:38:14 -03001205static const struct v4l2_ctrl_ops solo_ctrl_ops = {
1206 .s_ctrl = solo_s_ctrl,
1207};
1208
Hans Verkuilc813bd32013-03-25 05:38:14 -03001209static const struct v4l2_ctrl_config solo_osd_text_ctrl = {
1210 .ops = &solo_ctrl_ops,
1211 .id = V4L2_CID_OSD_TEXT,
1212 .name = "OSD Text",
1213 .type = V4L2_CTRL_TYPE_STRING,
1214 .max = OSD_TEXT_MAX,
1215 .step = 1,
1216};
1217
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001218/* Motion Detection Threshold matrix */
1219static const struct v4l2_ctrl_config solo_md_thresholds = {
1220 .ops = &solo_ctrl_ops,
1221 .id = V4L2_CID_DETECT_MD_THRESHOLD_GRID,
1222 .dims = { SOLO_MOTION_SZ, SOLO_MOTION_SZ },
1223 .def = SOLO_DEF_MOT_THRESH,
1224 .max = 65535,
1225 .step = 1,
1226};
1227
Hans Verkuildcae5da2013-03-25 05:35:17 -03001228static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
1229 u8 ch, unsigned nr)
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001230{
1231 struct solo_enc_dev *solo_enc;
Hans Verkuilc813bd32013-03-25 05:38:14 -03001232 struct v4l2_ctrl_handler *hdl;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001233 int ret;
1234
1235 solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL);
1236 if (!solo_enc)
1237 return ERR_PTR(-ENOMEM);
1238
Hans Verkuilc813bd32013-03-25 05:38:14 -03001239 hdl = &solo_enc->hdl;
1240 v4l2_ctrl_handler_init(hdl, 10);
1241 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1242 V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
1243 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1244 V4L2_CID_CONTRAST, 0, 255, 1, 128);
1245 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1246 V4L2_CID_SATURATION, 0, 255, 1, 128);
1247 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1248 V4L2_CID_HUE, 0, 255, 1, 128);
1249 if (tw28_has_sharpness(solo_dev, ch))
1250 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1251 V4L2_CID_SHARPNESS, 0, 15, 1, 0);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001252 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1253 V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 255, 1, solo_dev->fps);
Andrey Utkin56981112014-07-08 12:23:32 -03001254 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1255 V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 31, 1, SOLO_DEFAULT_QP);
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001256 v4l2_ctrl_new_std_menu(hdl, &solo_ctrl_ops,
1257 V4L2_CID_DETECT_MD_MODE,
1258 V4L2_DETECT_MD_MODE_THRESHOLD_GRID, 0,
1259 V4L2_DETECT_MD_MODE_DISABLED);
1260 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1261 V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD, 0, 0xff, 1,
1262 SOLO_DEF_MOT_THRESH >> 8);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001263 v4l2_ctrl_new_custom(hdl, &solo_osd_text_ctrl, NULL);
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001264 solo_enc->md_thresholds =
1265 v4l2_ctrl_new_custom(hdl, &solo_md_thresholds, NULL);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001266 if (hdl->error) {
1267 ret = hdl->error;
Hans Verkuila7eb9312013-03-18 08:41:13 -03001268 goto hdl_free;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001269 }
1270
1271 solo_enc->solo_dev = solo_dev;
1272 solo_enc->ch = ch;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001273 mutex_init(&solo_enc->lock);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001274 spin_lock_init(&solo_enc->av_lock);
1275 INIT_LIST_HEAD(&solo_enc->vidq_active);
Ismael Luceno16af6902013-04-18 10:56:35 -03001276 solo_enc->fmt = (solo_dev->type == SOLO_DEV_6010) ?
1277 V4L2_PIX_FMT_MPEG4 : V4L2_PIX_FMT_H264;
Hans Verkuila7eb9312013-03-18 08:41:13 -03001278 solo_enc->type = SOLO_ENC_TYPE_STD;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001279
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001280 solo_enc->qp = SOLO_DEFAULT_QP;
Ben Collinsf62de9b2010-11-04 22:51:17 -04001281 solo_enc->gop = solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001282 solo_enc->interval = 1;
1283 solo_enc->mode = SOLO_ENC_MODE_CIF;
Hans Verkuilf5df0b72013-03-18 08:43:14 -03001284 solo_enc->motion_global = true;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001285 solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001286 solo_enc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1287 solo_enc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
1288 solo_enc->vidq.ops = &solo_enc_video_qops;
1289 solo_enc->vidq.mem_ops = &vb2_dma_sg_memops;
1290 solo_enc->vidq.drv_priv = solo_enc;
Mel Gormand0164ad2015-11-06 16:28:21 -08001291 solo_enc->vidq.gfp_flags = __GFP_DMA32 | __GFP_KSWAPD_RECLAIM;
Sakari Ailusade48682014-02-25 19:12:19 -03001292 solo_enc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001293 solo_enc->vidq.buf_struct_size = sizeof(struct solo_vb2_buf);
1294 solo_enc->vidq.lock = &solo_enc->lock;
Hans Verkuil2bc46b32016-02-15 12:37:15 -02001295 solo_enc->vidq.dev = &solo_dev->pdev->dev;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001296 ret = vb2_queue_init(&solo_enc->vidq);
1297 if (ret)
1298 goto hdl_free;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001299 solo_update_mode(solo_enc);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001300
Hans Verkuila7eb9312013-03-18 08:41:13 -03001301 spin_lock_init(&solo_enc->motion_lock);
1302
Hans Verkuildcae5da2013-03-25 05:35:17 -03001303 /* Initialize this per encoder */
1304 solo_enc->jpeg_len = sizeof(jpeg_header);
1305 memcpy(solo_enc->jpeg_header, jpeg_header, solo_enc->jpeg_len);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001306
Hans Verkuila7eb9312013-03-18 08:41:13 -03001307 solo_enc->desc_nelts = 32;
1308 solo_enc->desc_items = pci_alloc_consistent(solo_dev->pdev,
1309 sizeof(struct solo_p2m_desc) *
Aybuke Ozdemirfa917832014-03-13 02:20:20 +02001310 solo_enc->desc_nelts,
1311 &solo_enc->desc_dma);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001312 ret = -ENOMEM;
1313 if (solo_enc->desc_items == NULL)
1314 goto hdl_free;
1315
Hans Verkuila7eb9312013-03-18 08:41:13 -03001316 solo_enc->vfd = video_device_alloc();
1317 if (!solo_enc->vfd)
1318 goto pci_free;
1319
1320 *solo_enc->vfd = solo_enc_template;
1321 solo_enc->vfd->v4l2_dev = &solo_dev->v4l2_dev;
1322 solo_enc->vfd->ctrl_handler = hdl;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001323 solo_enc->vfd->queue = &solo_enc->vidq;
1324 solo_enc->vfd->lock = &solo_enc->lock;
Hans Verkuila7eb9312013-03-18 08:41:13 -03001325 video_set_drvdata(solo_enc->vfd, solo_enc);
1326 ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr);
1327 if (ret < 0)
1328 goto vdev_release;
1329
1330 snprintf(solo_enc->vfd->name, sizeof(solo_enc->vfd->name),
1331 "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num,
1332 solo_enc->vfd->num);
1333
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001334 return solo_enc;
Hans Verkuila7eb9312013-03-18 08:41:13 -03001335
1336vdev_release:
1337 video_device_release(solo_enc->vfd);
1338pci_free:
1339 pci_free_consistent(solo_enc->solo_dev->pdev,
1340 sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts,
1341 solo_enc->desc_items, solo_enc->desc_dma);
1342hdl_free:
1343 v4l2_ctrl_handler_free(hdl);
1344 kfree(solo_enc);
1345 return ERR_PTR(ret);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001346}
1347
1348static void solo_enc_free(struct solo_enc_dev *solo_enc)
1349{
1350 if (solo_enc == NULL)
1351 return;
1352
Andrey Utkin0cb2df32014-10-29 13:03:52 -03001353 pci_free_consistent(solo_enc->solo_dev->pdev,
1354 sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts,
1355 solo_enc->desc_items, solo_enc->desc_dma);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001356 video_unregister_device(solo_enc->vfd);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001357 v4l2_ctrl_handler_free(&solo_enc->hdl);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001358 kfree(solo_enc);
1359}
1360
Hans Verkuildcae5da2013-03-25 05:35:17 -03001361int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001362{
1363 int i;
1364
Hans Verkuildcae5da2013-03-25 05:35:17 -03001365 init_waitqueue_head(&solo_dev->ring_thread_wait);
1366
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -03001367 solo_dev->vh_size = sizeof(vop_header);
Hans Verkuildcae5da2013-03-25 05:35:17 -03001368 solo_dev->vh_buf = pci_alloc_consistent(solo_dev->pdev,
1369 solo_dev->vh_size,
1370 &solo_dev->vh_dma);
1371 if (solo_dev->vh_buf == NULL)
1372 return -ENOMEM;
1373
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001374 for (i = 0; i < solo_dev->nr_chans; i++) {
Hans Verkuildcae5da2013-03-25 05:35:17 -03001375 solo_dev->v4l2_enc[i] = solo_enc_alloc(solo_dev, i, nr);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001376 if (IS_ERR(solo_dev->v4l2_enc[i]))
1377 break;
1378 }
1379
1380 if (i != solo_dev->nr_chans) {
1381 int ret = PTR_ERR(solo_dev->v4l2_enc[i]);
Hans Verkuil1c6f3db2014-07-17 20:40:22 -03001382
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001383 while (i--)
1384 solo_enc_free(solo_dev->v4l2_enc[i]);
Hans Verkuildcae5da2013-03-25 05:35:17 -03001385 pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
1386 solo_dev->vh_buf, solo_dev->vh_dma);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001387 solo_dev->vh_buf = NULL;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001388 return ret;
1389 }
1390
Hans Verkuildcae5da2013-03-25 05:35:17 -03001391 if (solo_dev->type == SOLO_DEV_6010)
1392 solo_dev->enc_bw_remain = solo_dev->fps * 4 * 4;
1393 else
1394 solo_dev->enc_bw_remain = solo_dev->fps * 4 * 5;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001395
1396 dev_info(&solo_dev->pdev->dev, "Encoders as /dev/video%d-%d\n",
1397 solo_dev->v4l2_enc[0]->vfd->num,
1398 solo_dev->v4l2_enc[solo_dev->nr_chans - 1]->vfd->num);
1399
Andrey Utkin670390c2014-10-29 13:03:53 -03001400 return solo_ring_start(solo_dev);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001401}
1402
Krzysztof Hałasadecebab2011-02-11 13:38:20 +01001403void solo_enc_v4l2_exit(struct solo_dev *solo_dev)
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001404{
1405 int i;
1406
Andrey Utkin670390c2014-10-29 13:03:53 -03001407 solo_ring_stop(solo_dev);
1408
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001409 for (i = 0; i < solo_dev->nr_chans; i++)
1410 solo_enc_free(solo_dev->v4l2_enc[i]);
Hans Verkuildcae5da2013-03-25 05:35:17 -03001411
Hans Verkuila7eb9312013-03-18 08:41:13 -03001412 if (solo_dev->vh_buf)
1413 pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
Hans Verkuildcae5da2013-03-25 05:35:17 -03001414 solo_dev->vh_buf, solo_dev->vh_dma);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001415}