blob: 53fff5425c13817e1242f08dbf2f6365c2c8de48 [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
36#define FRAME_BUF_SIZE (196 * 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{
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100461 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ricardo Ribalda22301242013-08-02 10:20:00 -0300462 struct sg_table *vbuf = vb2_dma_sg_plane_desc(vb, 0);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300463 int frame_size;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400464
Hans Verkuil382c31a2013-03-15 12:04:14 -0300465 vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400466
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300467 if (vb2_plane_size(vb, 0) < vop_jpeg_size(vh) + solo_enc->jpeg_len)
Hans Verkuildcae5da2013-03-25 05:35:17 -0300468 return -EIO;
469
Andreea-Cristina Bernat0cb6dfd2014-03-16 18:00:01 -0700470 frame_size = ALIGN(vop_jpeg_size(vh) + solo_enc->jpeg_len, DMA_ALIGN);
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300471 vb2_set_plane_payload(vb, 0, vop_jpeg_size(vh) + solo_enc->jpeg_len);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300472
Hans Verkuild790b7e2014-11-24 08:50:31 -0300473 return solo_send_desc(solo_enc, solo_enc->jpeg_len, vbuf,
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300474 vop_jpeg_offset(vh) - SOLO_JPEG_EXT_ADDR(solo_dev),
475 frame_size, SOLO_JPEG_EXT_ADDR(solo_dev),
476 SOLO_JPEG_EXT_SIZE(solo_dev));
Hans Verkuildcae5da2013-03-25 05:35:17 -0300477}
478
Hans Verkuil382c31a2013-03-15 12:04:14 -0300479static int solo_fill_mpeg(struct solo_enc_dev *solo_enc,
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300480 struct vb2_buffer *vb, const vop_header *vh)
Hans Verkuildcae5da2013-03-25 05:35:17 -0300481{
Hans Verkuildcae5da2013-03-25 05:35:17 -0300482 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ricardo Ribalda22301242013-08-02 10:20:00 -0300483 struct sg_table *vbuf = vb2_dma_sg_plane_desc(vb, 0);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300484 int frame_off, frame_size;
485 int skip = 0;
486
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300487 if (vb2_plane_size(vb, 0) < vop_mpeg_size(vh))
Hans Verkuildcae5da2013-03-25 05:35:17 -0300488 return -EIO;
489
Hans Verkuildcae5da2013-03-25 05:35:17 -0300490 /* If this is a key frame, add extra header */
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200491 vb->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_PFRAME |
492 V4L2_BUF_FLAG_BFRAME);
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300493 if (!vop_type(vh)) {
Hans Verkuildcae5da2013-03-25 05:35:17 -0300494 skip = solo_enc->vop_len;
Hans Verkuil382c31a2013-03-15 12:04:14 -0300495 vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200496 vb2_set_plane_payload(vb, 0, vop_mpeg_size(vh) +
497 solo_enc->vop_len);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300498 } else {
Hans Verkuil382c31a2013-03-15 12:04:14 -0300499 vb->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300500 vb2_set_plane_payload(vb, 0, vop_mpeg_size(vh));
Hans Verkuildcae5da2013-03-25 05:35:17 -0300501 }
502
503 /* Now get the actual mpeg payload */
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200504 frame_off = (vop_mpeg_offset(vh) - SOLO_MP4E_EXT_ADDR(solo_dev) +
505 sizeof(*vh)) % SOLO_MP4E_EXT_SIZE(solo_dev);
Andreea-Cristina Bernat0cb6dfd2014-03-16 18:00:01 -0700506 frame_size = ALIGN(vop_mpeg_size(vh) + skip, DMA_ALIGN);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300507
Hans Verkuild790b7e2014-11-24 08:50:31 -0300508 return solo_send_desc(solo_enc, skip, vbuf, frame_off, frame_size,
Hans Verkuil382c31a2013-03-15 12:04:14 -0300509 SOLO_MP4E_EXT_ADDR(solo_dev),
510 SOLO_MP4E_EXT_SIZE(solo_dev));
Hans Verkuildcae5da2013-03-25 05:35:17 -0300511}
512
Hans Verkuila7eb9312013-03-18 08:41:13 -0300513static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc,
Hans Verkuil382c31a2013-03-15 12:04:14 -0300514 struct vb2_buffer *vb, struct solo_enc_buf *enc_buf)
Hans Verkuildcae5da2013-03-25 05:35:17 -0300515{
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300516 const vop_header *vh = enc_buf->vh;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300517 int ret;
518
Ismael Luceno16af6902013-04-18 10:56:35 -0300519 switch (solo_enc->fmt) {
520 case V4L2_PIX_FMT_MPEG4:
521 case V4L2_PIX_FMT_H264:
Hans Verkuil382c31a2013-03-15 12:04:14 -0300522 ret = solo_fill_mpeg(solo_enc, vb, vh);
Ismael Luceno16af6902013-04-18 10:56:35 -0300523 break;
524 default: /* V4L2_PIX_FMT_MJPEG */
Hans Verkuil382c31a2013-03-15 12:04:14 -0300525 ret = solo_fill_jpeg(solo_enc, vb, vh);
Ismael Luceno16af6902013-04-18 10:56:35 -0300526 break;
527 }
Hans Verkuildcae5da2013-03-25 05:35:17 -0300528
Hans Verkuil382c31a2013-03-15 12:04:14 -0300529 if (!ret) {
Hans Verkuil15513c12013-03-15 13:16:49 -0300530 vb->v4l2_buf.sequence = solo_enc->sequence++;
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300531 vb->v4l2_buf.timestamp.tv_sec = vop_sec(vh);
532 vb->v4l2_buf.timestamp.tv_usec = vop_usec(vh);
Hans Verkuil316d9e82014-01-27 11:16:05 -0300533
534 /* Check for motion flags */
Andrey Utkine476f4e2014-11-05 17:11:14 -0300535 if (solo_is_motion_on(solo_enc) && enc_buf->motion) {
Hans Verkuil316d9e82014-01-27 11:16:05 -0300536 struct v4l2_event ev = {
537 .type = V4L2_EVENT_MOTION_DET,
538 .u.motion_det = {
539 .flags = V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ,
540 .frame_sequence = vb->v4l2_buf.sequence,
541 .region_mask = enc_buf->motion ? 1 : 0,
542 },
543 };
544
Hans Verkuil316d9e82014-01-27 11:16:05 -0300545 v4l2_event_queue(solo_enc->vfd, &ev);
546 }
Hans Verkuildcae5da2013-03-25 05:35:17 -0300547 }
548
Hans Verkuil382c31a2013-03-15 12:04:14 -0300549 vb2_buffer_done(vb, ret ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
550
Hans Verkuildcae5da2013-03-25 05:35:17 -0300551 return ret;
552}
553
554static void solo_enc_handle_one(struct solo_enc_dev *solo_enc,
555 struct solo_enc_buf *enc_buf)
556{
Hans Verkuil382c31a2013-03-15 12:04:14 -0300557 struct solo_vb2_buf *vb;
Hans Verkuila7eb9312013-03-18 08:41:13 -0300558 unsigned long flags;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300559
Hans Verkuil382c31a2013-03-15 12:04:14 -0300560 mutex_lock(&solo_enc->lock);
Hans Verkuila7eb9312013-03-18 08:41:13 -0300561 if (solo_enc->type != enc_buf->type)
562 goto unlock;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300563
Hans Verkuila7eb9312013-03-18 08:41:13 -0300564 spin_lock_irqsave(&solo_enc->av_lock, flags);
Hans Verkuil382c31a2013-03-15 12:04:14 -0300565 if (list_empty(&solo_enc->vidq_active)) {
566 spin_unlock_irqrestore(&solo_enc->av_lock, flags);
567 goto unlock;
568 }
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200569 vb = list_first_entry(&solo_enc->vidq_active, struct solo_vb2_buf,
570 list);
Hans Verkuil382c31a2013-03-15 12:04:14 -0300571 list_del(&vb->list);
Hans Verkuila7eb9312013-03-18 08:41:13 -0300572 spin_unlock_irqrestore(&solo_enc->av_lock, flags);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400573
Hans Verkuil382c31a2013-03-15 12:04:14 -0300574 solo_enc_fillbuf(solo_enc, &vb->vb, enc_buf);
Hans Verkuila7eb9312013-03-18 08:41:13 -0300575unlock:
Hans Verkuil382c31a2013-03-15 12:04:14 -0300576 mutex_unlock(&solo_enc->lock);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400577}
578
Hans Verkuildcae5da2013-03-25 05:35:17 -0300579void solo_enc_v4l2_isr(struct solo_dev *solo_dev)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400580{
Hans Verkuildcae5da2013-03-25 05:35:17 -0300581 wake_up_interruptible_all(&solo_dev->ring_thread_wait);
582}
583
584static void solo_handle_ring(struct solo_dev *solo_dev)
585{
586 for (;;) {
587 struct solo_enc_dev *solo_enc;
588 struct solo_enc_buf enc_buf;
589 u32 mpeg_current, off;
590 u8 ch;
591 u8 cur_q;
592
593 /* Check if the hardware has any new ones in the queue */
594 cur_q = solo_reg_read(solo_dev, SOLO_VE_STATE(11)) & 0xff;
595 if (cur_q == solo_dev->enc_idx)
596 break;
597
598 mpeg_current = solo_reg_read(solo_dev,
599 SOLO_VE_MPEG4_QUE(solo_dev->enc_idx));
600 solo_dev->enc_idx = (solo_dev->enc_idx + 1) % MP4_QS;
601
602 ch = (mpeg_current >> 24) & 0x1f;
603 off = mpeg_current & 0x00ffffff;
604
605 if (ch >= SOLO_MAX_CHANNELS) {
606 ch -= SOLO_MAX_CHANNELS;
607 enc_buf.type = SOLO_ENC_TYPE_EXT;
608 } else
609 enc_buf.type = SOLO_ENC_TYPE_STD;
610
611 solo_enc = solo_dev->v4l2_enc[ch];
612 if (solo_enc == NULL) {
613 dev_err(&solo_dev->pdev->dev,
614 "Got spurious packet for channel %d\n", ch);
615 continue;
616 }
617
618 /* FAIL... */
619 if (enc_get_mpeg_dma(solo_dev, solo_dev->vh_dma, off,
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300620 sizeof(vop_header)))
Hans Verkuildcae5da2013-03-25 05:35:17 -0300621 continue;
622
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -0300623 enc_buf.vh = solo_dev->vh_buf;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300624
625 /* Sanity check */
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200626 if (vop_mpeg_offset(enc_buf.vh) !=
627 SOLO_MP4E_EXT_ADDR(solo_dev) + off)
Hans Verkuildcae5da2013-03-25 05:35:17 -0300628 continue;
629
630 if (solo_motion_detected(solo_enc))
631 enc_buf.motion = 1;
632 else
633 enc_buf.motion = 0;
634
635 solo_enc_handle_one(solo_enc, &enc_buf);
636 }
637}
638
639static int solo_ring_thread(void *data)
640{
641 struct solo_dev *solo_dev = data;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400642 DECLARE_WAITQUEUE(wait, current);
643
644 set_freezable();
Hans Verkuildcae5da2013-03-25 05:35:17 -0300645 add_wait_queue(&solo_dev->ring_thread_wait, &wait);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400646
647 for (;;) {
648 long timeout = schedule_timeout_interruptible(HZ);
Hans Verkuil1c6f3db2014-07-17 20:40:22 -0300649
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400650 if (timeout == -ERESTARTSYS || kthread_should_stop())
651 break;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300652 solo_handle_ring(solo_dev);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400653 try_to_freeze();
654 }
655
Hans Verkuildcae5da2013-03-25 05:35:17 -0300656 remove_wait_queue(&solo_dev->ring_thread_wait, &wait);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400657
Ben Collinsf62de9b2010-11-04 22:51:17 -0400658 return 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400659}
660
Aybuke Ozdemirfa917832014-03-13 02:20:20 +0200661static int solo_enc_queue_setup(struct vb2_queue *q,
662 const struct v4l2_format *fmt,
663 unsigned int *num_buffers,
664 unsigned int *num_planes, unsigned int sizes[],
665 void *alloc_ctxs[])
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400666{
Hans Verkuil0c3a14c2014-11-18 09:51:01 -0300667 struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q);
668
Hans Verkuil382c31a2013-03-15 12:04:14 -0300669 sizes[0] = FRAME_BUF_SIZE;
Hans Verkuil0c3a14c2014-11-18 09:51:01 -0300670 alloc_ctxs[0] = solo_enc->alloc_ctx;
Hans Verkuil382c31a2013-03-15 12:04:14 -0300671 *num_planes = 1;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400672
Hans Verkuil382c31a2013-03-15 12:04:14 -0300673 if (*num_buffers < MIN_VID_BUFFERS)
674 *num_buffers = MIN_VID_BUFFERS;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400675
Ben Collinsf62de9b2010-11-04 22:51:17 -0400676 return 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400677}
678
Hans Verkuil382c31a2013-03-15 12:04:14 -0300679static void solo_enc_buf_queue(struct vb2_buffer *vb)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400680{
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 =
684 container_of(vb, 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);
737 vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
738 }
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{
744 struct solo_enc_dev *solo_enc = vb2_get_drv_priv(vb->vb2_queue);
745 struct sg_table *vbuf = vb2_dma_sg_plane_desc(vb, 0);
746
747 switch (solo_enc->fmt) {
748 case V4L2_PIX_FMT_MPEG4:
749 case V4L2_PIX_FMT_H264:
750 if (vb->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME)
751 sg_copy_from_buffer(vbuf->sgl, vbuf->nents,
752 solo_enc->vop, solo_enc->vop_len);
753 break;
754 default: /* V4L2_PIX_FMT_MJPEG */
755 sg_copy_from_buffer(vbuf->sgl, vbuf->nents,
756 solo_enc->jpeg_header, solo_enc->jpeg_len);
757 break;
758 }
759}
760
Hans Verkuil382c31a2013-03-15 12:04:14 -0300761static struct vb2_ops solo_enc_video_qops = {
762 .queue_setup = solo_enc_queue_setup,
763 .buf_queue = solo_enc_buf_queue,
Hans Verkuild790b7e2014-11-24 08:50:31 -0300764 .buf_finish = solo_enc_buf_finish,
Hans Verkuil382c31a2013-03-15 12:04:14 -0300765 .start_streaming = solo_enc_start_streaming,
766 .stop_streaming = solo_enc_stop_streaming,
767 .wait_prepare = vb2_ops_wait_prepare,
768 .wait_finish = vb2_ops_wait_finish,
769};
770
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400771static int solo_enc_querycap(struct file *file, void *priv,
772 struct v4l2_capability *cap)
773{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300774 struct solo_enc_dev *solo_enc = video_drvdata(file);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100775 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400776
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100777 strcpy(cap->driver, SOLO6X10_NAME);
778 snprintf(cap->card, sizeof(cap->card), "Softlogic 6x10 Enc %d",
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400779 solo_enc->ch);
Hans Verkuil20c5f492013-03-12 18:03:20 -0300780 snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400781 pci_name(solo_dev->pdev));
Hans Verkuil20c5f492013-03-12 18:03:20 -0300782 cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
783 V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
784 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400785 return 0;
786}
787
788static int solo_enc_enum_input(struct file *file, void *priv,
789 struct v4l2_input *input)
790{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300791 struct solo_enc_dev *solo_enc = video_drvdata(file);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100792 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400793
794 if (input->index)
795 return -EINVAL;
796
797 snprintf(input->name, sizeof(input->name), "Encoder %d",
798 solo_enc->ch + 1);
799 input->type = V4L2_INPUT_TYPE_CAMERA;
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300800 input->std = solo_enc->vfd->tvnorms;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400801
802 if (!tw28_get_video_status(solo_dev, solo_enc->ch))
803 input->status = V4L2_IN_ST_NO_SIGNAL;
804
805 return 0;
806}
807
Hans Verkuildcae5da2013-03-25 05:35:17 -0300808static int solo_enc_set_input(struct file *file, void *priv,
809 unsigned int index)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400810{
811 if (index)
812 return -EINVAL;
813
814 return 0;
815}
816
817static int solo_enc_get_input(struct file *file, void *priv,
818 unsigned int *index)
819{
820 *index = 0;
821
822 return 0;
823}
824
825static int solo_enc_enum_fmt_cap(struct file *file, void *priv,
826 struct v4l2_fmtdesc *f)
827{
Ismael Luceno16af6902013-04-18 10:56:35 -0300828 struct solo_enc_dev *solo_enc = video_drvdata(file);
829 int dev_type = solo_enc->solo_dev->type;
830
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400831 switch (f->index) {
832 case 0:
Ismael Luceno16af6902013-04-18 10:56:35 -0300833 switch (dev_type) {
834 case SOLO_DEV_6010:
835 f->pixelformat = V4L2_PIX_FMT_MPEG4;
836 strcpy(f->description, "MPEG-4 part 2");
837 break;
838 case SOLO_DEV_6110:
839 f->pixelformat = V4L2_PIX_FMT_H264;
840 strcpy(f->description, "H.264");
841 break;
842 }
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400843 break;
844 case 1:
845 f->pixelformat = V4L2_PIX_FMT_MJPEG;
846 strcpy(f->description, "MJPEG");
847 break;
848 default:
849 return -EINVAL;
850 }
851
852 f->flags = V4L2_FMT_FLAG_COMPRESSED;
853
854 return 0;
855}
856
Ismael Luceno16af6902013-04-18 10:56:35 -0300857static inline int solo_valid_pixfmt(u32 pixfmt, int dev_type)
858{
859 return (pixfmt == V4L2_PIX_FMT_H264 && dev_type == SOLO_DEV_6110)
860 || (pixfmt == V4L2_PIX_FMT_MPEG4 && dev_type == SOLO_DEV_6010)
861 || pixfmt == V4L2_PIX_FMT_MJPEG ? 0 : -EINVAL;
862}
863
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400864static int solo_enc_try_fmt_cap(struct file *file, void *priv,
865 struct v4l2_format *f)
866{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300867 struct solo_enc_dev *solo_enc = video_drvdata(file);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100868 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400869 struct v4l2_pix_format *pix = &f->fmt.pix;
870
Ismael Luceno16af6902013-04-18 10:56:35 -0300871 if (solo_valid_pixfmt(pix->pixelformat, solo_dev->type))
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400872 return -EINVAL;
873
Krzysztof Hałasa98ab1c92011-02-11 13:10:30 +0100874 if (pix->width < solo_dev->video_hsize ||
875 pix->height < solo_dev->video_vsize << 1) {
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400876 /* Default to CIF 1/2 size */
877 pix->width = solo_dev->video_hsize >> 1;
878 pix->height = solo_dev->video_vsize;
Krzysztof Hałasa98ab1c92011-02-11 13:10:30 +0100879 } else {
880 /* Full frame */
881 pix->width = solo_dev->video_hsize;
882 pix->height = solo_dev->video_vsize << 1;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400883 }
884
Hans Verkuil016afda2013-03-12 18:43:21 -0300885 switch (pix->field) {
886 case V4L2_FIELD_NONE:
887 case V4L2_FIELD_INTERLACED:
888 break;
889 case V4L2_FIELD_ANY:
890 default:
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400891 pix->field = V4L2_FIELD_INTERLACED;
Hans Verkuil016afda2013-03-12 18:43:21 -0300892 break;
893 }
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400894
895 /* Just set these */
896 pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
897 pix->sizeimage = FRAME_BUF_SIZE;
Hans Verkuil94160492013-03-12 18:47:03 -0300898 pix->bytesperline = 0;
Hans Verkuil016afda2013-03-12 18:43:21 -0300899 pix->priv = 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400900
901 return 0;
902}
903
904static int solo_enc_set_fmt_cap(struct file *file, void *priv,
905 struct v4l2_format *f)
906{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300907 struct solo_enc_dev *solo_enc = video_drvdata(file);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100908 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400909 struct v4l2_pix_format *pix = &f->fmt.pix;
910 int ret;
911
Hans Verkuil382c31a2013-03-15 12:04:14 -0300912 if (vb2_is_busy(&solo_enc->vidq))
913 return -EBUSY;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400914
facugaichafabbe62010-11-10 10:39:33 -0300915 ret = solo_enc_try_fmt_cap(file, priv, f);
Hans Verkuil016afda2013-03-12 18:43:21 -0300916 if (ret)
917 return ret;
918
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400919 if (pix->width == solo_dev->video_hsize)
920 solo_enc->mode = SOLO_ENC_MODE_D1;
921 else
922 solo_enc->mode = SOLO_ENC_MODE_CIF;
923
924 /* This does not change the encoder at all */
Hans Verkuila7eb9312013-03-18 08:41:13 -0300925 solo_enc->fmt = pix->pixelformat;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400926
Hans Verkuil69996872013-03-15 16:35:28 -0300927 /*
928 * More information is needed about these 'extended' types. As far
929 * as I can tell these are basically additional video streams with
930 * different MPEG encoding attributes that can run in parallel with
931 * the main stream. If so, then this should be implemented as a
932 * second video node. Abusing priv like this is certainly not the
933 * right approach.
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400934 if (pix->priv)
Hans Verkuila7eb9312013-03-18 08:41:13 -0300935 solo_enc->type = SOLO_ENC_TYPE_EXT;
Hans Verkuil69996872013-03-15 16:35:28 -0300936 */
Ismael Lucenocdcfe402013-04-12 18:28:33 -0300937 solo_update_mode(solo_enc);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300938 return 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400939}
940
941static int solo_enc_get_fmt_cap(struct file *file, void *priv,
942 struct v4l2_format *f)
943{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300944 struct solo_enc_dev *solo_enc = video_drvdata(file);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400945 struct v4l2_pix_format *pix = &f->fmt.pix;
946
947 pix->width = solo_enc->width;
948 pix->height = solo_enc->height;
Hans Verkuila7eb9312013-03-18 08:41:13 -0300949 pix->pixelformat = solo_enc->fmt;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400950 pix->field = solo_enc->interlaced ? V4L2_FIELD_INTERLACED :
951 V4L2_FIELD_NONE;
952 pix->sizeimage = FRAME_BUF_SIZE;
953 pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
Hans Verkuil016afda2013-03-12 18:43:21 -0300954 pix->priv = 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400955
956 return 0;
957}
958
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300959static int solo_enc_g_std(struct file *file, void *priv, v4l2_std_id *i)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400960{
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300961 struct solo_enc_dev *solo_enc = video_drvdata(file);
962 struct solo_dev *solo_dev = solo_enc->solo_dev;
963
964 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
965 *i = V4L2_STD_NTSC_M;
966 else
967 *i = V4L2_STD_PAL;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400968 return 0;
969}
970
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300971static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id std)
972{
973 struct solo_enc_dev *solo_enc = video_drvdata(file);
974
Hans Verkuil429df502014-01-13 06:58:12 -0300975 return solo_set_video_type(solo_enc->solo_dev, std & V4L2_STD_625_50);
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300976}
977
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400978static int solo_enum_framesizes(struct file *file, void *priv,
979 struct v4l2_frmsizeenum *fsize)
980{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300981 struct solo_enc_dev *solo_enc = video_drvdata(file);
982 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400983
Ismael Luceno16af6902013-04-18 10:56:35 -0300984 if (solo_valid_pixfmt(fsize->pixel_format, solo_dev->type))
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400985 return -EINVAL;
986
987 switch (fsize->index) {
988 case 0:
989 fsize->discrete.width = solo_dev->video_hsize >> 1;
990 fsize->discrete.height = solo_dev->video_vsize;
991 break;
992 case 1:
993 fsize->discrete.width = solo_dev->video_hsize;
994 fsize->discrete.height = solo_dev->video_vsize << 1;
995 break;
996 default:
997 return -EINVAL;
998 }
999
1000 fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1001
1002 return 0;
1003}
1004
1005static int solo_enum_frameintervals(struct file *file, void *priv,
1006 struct v4l2_frmivalenum *fintv)
1007{
Hans Verkuila7eb9312013-03-18 08:41:13 -03001008 struct solo_enc_dev *solo_enc = video_drvdata(file);
1009 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001010
Ismael Luceno16af6902013-04-18 10:56:35 -03001011 if (solo_valid_pixfmt(fintv->pixel_format, solo_dev->type))
Hans Verkuil016afda2013-03-12 18:43:21 -03001012 return -EINVAL;
1013 if (fintv->index)
1014 return -EINVAL;
1015 if ((fintv->width != solo_dev->video_hsize >> 1 ||
1016 fintv->height != solo_dev->video_vsize) &&
1017 (fintv->width != solo_dev->video_hsize ||
1018 fintv->height != solo_dev->video_vsize << 1))
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001019 return -EINVAL;
1020
1021 fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE;
1022
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001023 fintv->stepwise.min.numerator = 1;
Hans Verkuil016afda2013-03-12 18:43:21 -03001024 fintv->stepwise.min.denominator = solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001025
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001026 fintv->stepwise.max.numerator = 15;
Hans Verkuil016afda2013-03-12 18:43:21 -03001027 fintv->stepwise.max.denominator = solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001028
1029 fintv->stepwise.step.numerator = 1;
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001030 fintv->stepwise.step.denominator = solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001031
1032 return 0;
1033}
1034
1035static int solo_g_parm(struct file *file, void *priv,
1036 struct v4l2_streamparm *sp)
1037{
Hans Verkuila7eb9312013-03-18 08:41:13 -03001038 struct solo_enc_dev *solo_enc = video_drvdata(file);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001039 struct v4l2_captureparm *cp = &sp->parm.capture;
1040
1041 cp->capability = V4L2_CAP_TIMEPERFRAME;
1042 cp->timeperframe.numerator = solo_enc->interval;
Ismael Luceno88107672013-05-03 15:54:57 -03001043 cp->timeperframe.denominator = solo_enc->solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001044 cp->capturemode = 0;
1045 /* XXX: Shouldn't we be able to get/set this from videobuf? */
1046 cp->readbuffers = 2;
1047
Ben Collinsf62de9b2010-11-04 22:51:17 -04001048 return 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001049}
1050
Ismael Luceno88107672013-05-03 15:54:57 -03001051static inline int calc_interval(u8 fps, u32 n, u32 d)
1052{
1053 if (!n || !d)
1054 return 1;
1055 if (d == fps)
1056 return n;
1057 n *= fps;
1058 return min(15U, n / d + (n % d >= (fps >> 1)));
1059}
1060
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001061static int solo_s_parm(struct file *file, void *priv,
1062 struct v4l2_streamparm *sp)
1063{
Hans Verkuila7eb9312013-03-18 08:41:13 -03001064 struct solo_enc_dev *solo_enc = video_drvdata(file);
Ismael Luceno88107672013-05-03 15:54:57 -03001065 struct v4l2_fract *t = &sp->parm.capture.timeperframe;
1066 u8 fps = solo_enc->solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001067
Hans Verkuil382c31a2013-03-15 12:04:14 -03001068 if (vb2_is_streaming(&solo_enc->vidq))
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001069 return -EBUSY;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001070
Ismael Luceno88107672013-05-03 15:54:57 -03001071 solo_enc->interval = calc_interval(fps, t->numerator, t->denominator);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001072 solo_update_mode(solo_enc);
Ismael Luceno88107672013-05-03 15:54:57 -03001073 return solo_g_parm(file, priv, sp);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001074}
1075
Hans Verkuilc813bd32013-03-25 05:38:14 -03001076static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001077{
Hans Verkuilc813bd32013-03-25 05:38:14 -03001078 struct solo_enc_dev *solo_enc =
1079 container_of(ctrl->handler, struct solo_enc_dev, hdl);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +01001080 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001081 int err;
1082
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001083 switch (ctrl->id) {
1084 case V4L2_CID_BRIGHTNESS:
1085 case V4L2_CID_CONTRAST:
1086 case V4L2_CID_SATURATION:
1087 case V4L2_CID_HUE:
1088 case V4L2_CID_SHARPNESS:
1089 return tw28_set_ctrl_val(solo_dev, ctrl->id, solo_enc->ch,
Hans Verkuilc813bd32013-03-25 05:38:14 -03001090 ctrl->val);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001091 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
Hans Verkuilc813bd32013-03-25 05:38:14 -03001092 solo_enc->gop = ctrl->val;
Andrey Utkin63e9b452014-07-08 12:23:33 -03001093 solo_reg_write(solo_dev, SOLO_VE_CH_GOP(solo_enc->ch), solo_enc->gop);
1094 solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(solo_enc->ch), solo_enc->gop);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001095 return 0;
Andrey Utkin569811162014-07-08 12:23:32 -03001096 case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
1097 solo_enc->qp = ctrl->val;
Andrey Utkin63e9b452014-07-08 12:23:33 -03001098 solo_reg_write(solo_dev, SOLO_VE_CH_QP(solo_enc->ch), solo_enc->qp);
1099 solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(solo_enc->ch), solo_enc->qp);
Andrey Utkin569811162014-07-08 12:23:32 -03001100 return 0;
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001101 case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD:
1102 solo_enc->motion_thresh = ctrl->val << 8;
Hans Verkuilf5df0b72013-03-18 08:43:14 -03001103 if (!solo_enc->motion_global || !solo_enc->motion_enabled)
1104 return 0;
Aybuke Ozdemirfa917832014-03-13 02:20:20 +02001105 return solo_set_motion_threshold(solo_dev, solo_enc->ch,
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001106 solo_enc->motion_thresh);
1107 case V4L2_CID_DETECT_MD_MODE:
1108 solo_enc->motion_global = ctrl->val == V4L2_DETECT_MD_MODE_GLOBAL;
1109 solo_enc->motion_enabled = ctrl->val > V4L2_DETECT_MD_MODE_DISABLED;
Hans Verkuilf5df0b72013-03-18 08:43:14 -03001110 if (ctrl->val) {
1111 if (solo_enc->motion_global)
Hans Verkuil0a128302014-07-25 08:19:54 -03001112 err = solo_set_motion_threshold(solo_dev, solo_enc->ch,
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001113 solo_enc->motion_thresh);
Hans Verkuilf5df0b72013-03-18 08:43:14 -03001114 else
Hans Verkuil0a128302014-07-25 08:19:54 -03001115 err = solo_set_motion_block(solo_dev, solo_enc->ch,
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001116 solo_enc->md_thresholds->p_cur.p_u16);
Hans Verkuil0a128302014-07-25 08:19:54 -03001117 if (err)
1118 return err;
Hans Verkuildcae5da2013-03-25 05:35:17 -03001119 }
Hans Verkuilc813bd32013-03-25 05:38:14 -03001120 solo_motion_toggle(solo_enc, ctrl->val);
1121 return 0;
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001122 case V4L2_CID_DETECT_MD_THRESHOLD_GRID:
1123 if (solo_enc->motion_enabled && !solo_enc->motion_global)
1124 return solo_set_motion_block(solo_dev, solo_enc->ch,
1125 solo_enc->md_thresholds->p_new.p_u16);
1126 break;
Hans Verkuilc813bd32013-03-25 05:38:14 -03001127 case V4L2_CID_OSD_TEXT:
Hans Verkuil2a9ec372014-04-27 03:38:13 -03001128 strcpy(solo_enc->osd_text, ctrl->p_new.p_char);
Hans Verkuil0a128302014-07-25 08:19:54 -03001129 return solo_osd_print(solo_enc);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001130 default:
1131 return -EINVAL;
1132 }
1133
1134 return 0;
1135}
1136
Hans Verkuil316d9e82014-01-27 11:16:05 -03001137static int solo_subscribe_event(struct v4l2_fh *fh,
1138 const struct v4l2_event_subscription *sub)
1139{
1140
1141 switch (sub->type) {
1142 case V4L2_EVENT_CTRL:
1143 return v4l2_ctrl_subscribe_event(fh, sub);
1144 case V4L2_EVENT_MOTION_DET:
1145 /* Allow for up to 30 events (1 second for NTSC) to be
1146 * stored. */
1147 return v4l2_event_subscribe(fh, sub, 30, NULL);
1148 }
1149 return -EINVAL;
1150}
1151
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001152static const struct v4l2_file_operations solo_enc_fops = {
1153 .owner = THIS_MODULE,
Hans Verkuil382c31a2013-03-15 12:04:14 -03001154 .open = v4l2_fh_open,
1155 .release = vb2_fop_release,
1156 .read = vb2_fop_read,
1157 .poll = vb2_fop_poll,
1158 .mmap = vb2_fop_mmap,
1159 .unlocked_ioctl = video_ioctl2,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001160};
1161
1162static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = {
1163 .vidioc_querycap = solo_enc_querycap,
1164 .vidioc_s_std = solo_enc_s_std,
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001165 .vidioc_g_std = solo_enc_g_std,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001166 /* Input callbacks */
1167 .vidioc_enum_input = solo_enc_enum_input,
1168 .vidioc_s_input = solo_enc_set_input,
1169 .vidioc_g_input = solo_enc_get_input,
1170 /* Video capture format callbacks */
1171 .vidioc_enum_fmt_vid_cap = solo_enc_enum_fmt_cap,
1172 .vidioc_try_fmt_vid_cap = solo_enc_try_fmt_cap,
1173 .vidioc_s_fmt_vid_cap = solo_enc_set_fmt_cap,
1174 .vidioc_g_fmt_vid_cap = solo_enc_get_fmt_cap,
1175 /* Streaming I/O */
Hans Verkuil382c31a2013-03-15 12:04:14 -03001176 .vidioc_reqbufs = vb2_ioctl_reqbufs,
1177 .vidioc_querybuf = vb2_ioctl_querybuf,
1178 .vidioc_qbuf = vb2_ioctl_qbuf,
1179 .vidioc_dqbuf = vb2_ioctl_dqbuf,
1180 .vidioc_streamon = vb2_ioctl_streamon,
1181 .vidioc_streamoff = vb2_ioctl_streamoff,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001182 /* Frame size and interval */
1183 .vidioc_enum_framesizes = solo_enum_framesizes,
1184 .vidioc_enum_frameintervals = solo_enum_frameintervals,
1185 /* Video capture parameters */
1186 .vidioc_s_parm = solo_s_parm,
1187 .vidioc_g_parm = solo_g_parm,
Hans Verkuil94160492013-03-12 18:47:03 -03001188 /* Logging and events */
1189 .vidioc_log_status = v4l2_ctrl_log_status,
Hans Verkuil316d9e82014-01-27 11:16:05 -03001190 .vidioc_subscribe_event = solo_subscribe_event,
Hans Verkuil94160492013-03-12 18:47:03 -03001191 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001192};
1193
Hans Verkuildcae5da2013-03-25 05:35:17 -03001194static const struct video_device solo_enc_template = {
Krzysztof Hałasadecebab2011-02-11 13:38:20 +01001195 .name = SOLO6X10_NAME,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001196 .fops = &solo_enc_fops,
1197 .ioctl_ops = &solo_enc_ioctl_ops,
1198 .minor = -1,
1199 .release = video_device_release,
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001200 .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001201};
1202
Hans Verkuilc813bd32013-03-25 05:38:14 -03001203static const struct v4l2_ctrl_ops solo_ctrl_ops = {
1204 .s_ctrl = solo_s_ctrl,
1205};
1206
Hans Verkuilc813bd32013-03-25 05:38:14 -03001207static const struct v4l2_ctrl_config solo_osd_text_ctrl = {
1208 .ops = &solo_ctrl_ops,
1209 .id = V4L2_CID_OSD_TEXT,
1210 .name = "OSD Text",
1211 .type = V4L2_CTRL_TYPE_STRING,
1212 .max = OSD_TEXT_MAX,
1213 .step = 1,
1214};
1215
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001216/* Motion Detection Threshold matrix */
1217static const struct v4l2_ctrl_config solo_md_thresholds = {
1218 .ops = &solo_ctrl_ops,
1219 .id = V4L2_CID_DETECT_MD_THRESHOLD_GRID,
1220 .dims = { SOLO_MOTION_SZ, SOLO_MOTION_SZ },
1221 .def = SOLO_DEF_MOT_THRESH,
1222 .max = 65535,
1223 .step = 1,
1224};
1225
Hans Verkuildcae5da2013-03-25 05:35:17 -03001226static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
1227 u8 ch, unsigned nr)
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001228{
1229 struct solo_enc_dev *solo_enc;
Hans Verkuilc813bd32013-03-25 05:38:14 -03001230 struct v4l2_ctrl_handler *hdl;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001231 int ret;
1232
1233 solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL);
1234 if (!solo_enc)
1235 return ERR_PTR(-ENOMEM);
1236
Hans Verkuilc813bd32013-03-25 05:38:14 -03001237 hdl = &solo_enc->hdl;
Hans Verkuil0c3a14c2014-11-18 09:51:01 -03001238 solo_enc->alloc_ctx = vb2_dma_sg_init_ctx(&solo_dev->pdev->dev);
1239 if (IS_ERR(solo_enc->alloc_ctx)) {
1240 ret = PTR_ERR(solo_enc->alloc_ctx);
1241 goto hdl_free;
1242 }
Hans Verkuilc813bd32013-03-25 05:38:14 -03001243 v4l2_ctrl_handler_init(hdl, 10);
1244 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1245 V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
1246 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1247 V4L2_CID_CONTRAST, 0, 255, 1, 128);
1248 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1249 V4L2_CID_SATURATION, 0, 255, 1, 128);
1250 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1251 V4L2_CID_HUE, 0, 255, 1, 128);
1252 if (tw28_has_sharpness(solo_dev, ch))
1253 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1254 V4L2_CID_SHARPNESS, 0, 15, 1, 0);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001255 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1256 V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 255, 1, solo_dev->fps);
Andrey Utkin569811162014-07-08 12:23:32 -03001257 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1258 V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 31, 1, SOLO_DEFAULT_QP);
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001259 v4l2_ctrl_new_std_menu(hdl, &solo_ctrl_ops,
1260 V4L2_CID_DETECT_MD_MODE,
1261 V4L2_DETECT_MD_MODE_THRESHOLD_GRID, 0,
1262 V4L2_DETECT_MD_MODE_DISABLED);
1263 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1264 V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD, 0, 0xff, 1,
1265 SOLO_DEF_MOT_THRESH >> 8);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001266 v4l2_ctrl_new_custom(hdl, &solo_osd_text_ctrl, NULL);
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001267 solo_enc->md_thresholds =
1268 v4l2_ctrl_new_custom(hdl, &solo_md_thresholds, NULL);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001269 if (hdl->error) {
1270 ret = hdl->error;
Hans Verkuila7eb9312013-03-18 08:41:13 -03001271 goto hdl_free;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001272 }
1273
1274 solo_enc->solo_dev = solo_dev;
1275 solo_enc->ch = ch;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001276 mutex_init(&solo_enc->lock);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001277 spin_lock_init(&solo_enc->av_lock);
1278 INIT_LIST_HEAD(&solo_enc->vidq_active);
Ismael Luceno16af6902013-04-18 10:56:35 -03001279 solo_enc->fmt = (solo_dev->type == SOLO_DEV_6010) ?
1280 V4L2_PIX_FMT_MPEG4 : V4L2_PIX_FMT_H264;
Hans Verkuila7eb9312013-03-18 08:41:13 -03001281 solo_enc->type = SOLO_ENC_TYPE_STD;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001282
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001283 solo_enc->qp = SOLO_DEFAULT_QP;
Ben Collinsf62de9b2010-11-04 22:51:17 -04001284 solo_enc->gop = solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001285 solo_enc->interval = 1;
1286 solo_enc->mode = SOLO_ENC_MODE_CIF;
Hans Verkuilf5df0b72013-03-18 08:43:14 -03001287 solo_enc->motion_global = true;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001288 solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001289 solo_enc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1290 solo_enc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
1291 solo_enc->vidq.ops = &solo_enc_video_qops;
1292 solo_enc->vidq.mem_ops = &vb2_dma_sg_memops;
1293 solo_enc->vidq.drv_priv = solo_enc;
1294 solo_enc->vidq.gfp_flags = __GFP_DMA32;
Sakari Ailusade48682014-02-25 19:12:19 -03001295 solo_enc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001296 solo_enc->vidq.buf_struct_size = sizeof(struct solo_vb2_buf);
1297 solo_enc->vidq.lock = &solo_enc->lock;
1298 ret = vb2_queue_init(&solo_enc->vidq);
1299 if (ret)
1300 goto hdl_free;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001301 solo_update_mode(solo_enc);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001302
Hans Verkuila7eb9312013-03-18 08:41:13 -03001303 spin_lock_init(&solo_enc->motion_lock);
1304
Hans Verkuildcae5da2013-03-25 05:35:17 -03001305 /* Initialize this per encoder */
1306 solo_enc->jpeg_len = sizeof(jpeg_header);
1307 memcpy(solo_enc->jpeg_header, jpeg_header, solo_enc->jpeg_len);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001308
Hans Verkuila7eb9312013-03-18 08:41:13 -03001309 solo_enc->desc_nelts = 32;
1310 solo_enc->desc_items = pci_alloc_consistent(solo_dev->pdev,
1311 sizeof(struct solo_p2m_desc) *
Aybuke Ozdemirfa917832014-03-13 02:20:20 +02001312 solo_enc->desc_nelts,
1313 &solo_enc->desc_dma);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001314 ret = -ENOMEM;
1315 if (solo_enc->desc_items == NULL)
1316 goto hdl_free;
1317
Hans Verkuila7eb9312013-03-18 08:41:13 -03001318 solo_enc->vfd = video_device_alloc();
1319 if (!solo_enc->vfd)
1320 goto pci_free;
1321
1322 *solo_enc->vfd = solo_enc_template;
1323 solo_enc->vfd->v4l2_dev = &solo_dev->v4l2_dev;
1324 solo_enc->vfd->ctrl_handler = hdl;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001325 solo_enc->vfd->queue = &solo_enc->vidq;
1326 solo_enc->vfd->lock = &solo_enc->lock;
Hans Verkuila7eb9312013-03-18 08:41:13 -03001327 video_set_drvdata(solo_enc->vfd, solo_enc);
1328 ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr);
1329 if (ret < 0)
1330 goto vdev_release;
1331
1332 snprintf(solo_enc->vfd->name, sizeof(solo_enc->vfd->name),
1333 "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num,
1334 solo_enc->vfd->num);
1335
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001336 return solo_enc;
Hans Verkuila7eb9312013-03-18 08:41:13 -03001337
1338vdev_release:
1339 video_device_release(solo_enc->vfd);
1340pci_free:
1341 pci_free_consistent(solo_enc->solo_dev->pdev,
1342 sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts,
1343 solo_enc->desc_items, solo_enc->desc_dma);
1344hdl_free:
1345 v4l2_ctrl_handler_free(hdl);
Hans Verkuil0c3a14c2014-11-18 09:51:01 -03001346 vb2_dma_sg_cleanup_ctx(solo_enc->alloc_ctx);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001347 kfree(solo_enc);
1348 return ERR_PTR(ret);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001349}
1350
1351static void solo_enc_free(struct solo_enc_dev *solo_enc)
1352{
1353 if (solo_enc == NULL)
1354 return;
1355
Andrey Utkin0cb2df32014-10-29 13:03:52 -03001356 pci_free_consistent(solo_enc->solo_dev->pdev,
1357 sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts,
1358 solo_enc->desc_items, solo_enc->desc_dma);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001359 video_unregister_device(solo_enc->vfd);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001360 v4l2_ctrl_handler_free(&solo_enc->hdl);
Hans Verkuil0c3a14c2014-11-18 09:51:01 -03001361 vb2_dma_sg_cleanup_ctx(solo_enc->alloc_ctx);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001362 kfree(solo_enc);
1363}
1364
Hans Verkuildcae5da2013-03-25 05:35:17 -03001365int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001366{
1367 int i;
1368
Hans Verkuildcae5da2013-03-25 05:35:17 -03001369 init_waitqueue_head(&solo_dev->ring_thread_wait);
1370
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -03001371 solo_dev->vh_size = sizeof(vop_header);
Hans Verkuildcae5da2013-03-25 05:35:17 -03001372 solo_dev->vh_buf = pci_alloc_consistent(solo_dev->pdev,
1373 solo_dev->vh_size,
1374 &solo_dev->vh_dma);
1375 if (solo_dev->vh_buf == NULL)
1376 return -ENOMEM;
1377
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001378 for (i = 0; i < solo_dev->nr_chans; i++) {
Hans Verkuildcae5da2013-03-25 05:35:17 -03001379 solo_dev->v4l2_enc[i] = solo_enc_alloc(solo_dev, i, nr);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001380 if (IS_ERR(solo_dev->v4l2_enc[i]))
1381 break;
1382 }
1383
1384 if (i != solo_dev->nr_chans) {
1385 int ret = PTR_ERR(solo_dev->v4l2_enc[i]);
Hans Verkuil1c6f3db2014-07-17 20:40:22 -03001386
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001387 while (i--)
1388 solo_enc_free(solo_dev->v4l2_enc[i]);
Hans Verkuildcae5da2013-03-25 05:35:17 -03001389 pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
1390 solo_dev->vh_buf, solo_dev->vh_dma);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001391 solo_dev->vh_buf = NULL;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001392 return ret;
1393 }
1394
Hans Verkuildcae5da2013-03-25 05:35:17 -03001395 if (solo_dev->type == SOLO_DEV_6010)
1396 solo_dev->enc_bw_remain = solo_dev->fps * 4 * 4;
1397 else
1398 solo_dev->enc_bw_remain = solo_dev->fps * 4 * 5;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001399
1400 dev_info(&solo_dev->pdev->dev, "Encoders as /dev/video%d-%d\n",
1401 solo_dev->v4l2_enc[0]->vfd->num,
1402 solo_dev->v4l2_enc[solo_dev->nr_chans - 1]->vfd->num);
1403
Andrey Utkin670390c2014-10-29 13:03:53 -03001404 return solo_ring_start(solo_dev);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001405}
1406
Krzysztof Hałasadecebab2011-02-11 13:38:20 +01001407void solo_enc_v4l2_exit(struct solo_dev *solo_dev)
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001408{
1409 int i;
1410
Andrey Utkin670390c2014-10-29 13:03:53 -03001411 solo_ring_stop(solo_dev);
1412
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001413 for (i = 0; i < solo_dev->nr_chans; i++)
1414 solo_enc_free(solo_dev->v4l2_enc[i]);
Hans Verkuildcae5da2013-03-25 05:35:17 -03001415
Hans Verkuila7eb9312013-03-18 08:41:13 -03001416 if (solo_dev->vh_buf)
1417 pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
Hans Verkuildcae5da2013-03-25 05:35:17 -03001418 solo_dev->vh_buf, solo_dev->vh_dma);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001419}