blob: 67a14c41c227ac3e44643202982eb1c6bf543ef3 [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{
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[],
667 void *alloc_ctxs[])
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400668{
Hans Verkuil0c3a14c2014-11-18 09:51:01 -0300669 struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q);
670
Hans Verkuil382c31a2013-03-15 12:04:14 -0300671 sizes[0] = FRAME_BUF_SIZE;
Hans Verkuil0c3a14c2014-11-18 09:51:01 -0300672 alloc_ctxs[0] = solo_enc->alloc_ctx;
Hans Verkuil382c31a2013-03-15 12:04:14 -0300673 *num_planes = 1;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400674
Hans Verkuil382c31a2013-03-15 12:04:14 -0300675 if (*num_buffers < MIN_VID_BUFFERS)
676 *num_buffers = MIN_VID_BUFFERS;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400677
Ben Collinsf62de9b2010-11-04 22:51:17 -0400678 return 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400679}
680
Hans Verkuil382c31a2013-03-15 12:04:14 -0300681static void solo_enc_buf_queue(struct vb2_buffer *vb)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400682{
Junghak Sung2d700712015-09-22 10:30:30 -0300683 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
Hans Verkuil382c31a2013-03-15 12:04:14 -0300684 struct vb2_queue *vq = vb->vb2_queue;
685 struct solo_enc_dev *solo_enc = vb2_get_drv_priv(vq);
686 struct solo_vb2_buf *solo_vb =
Junghak Sung2d700712015-09-22 10:30:30 -0300687 container_of(vbuf, struct solo_vb2_buf, vb);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400688
Hans Verkuil382c31a2013-03-15 12:04:14 -0300689 spin_lock(&solo_enc->av_lock);
690 list_add_tail(&solo_vb->list, &solo_enc->vidq_active);
691 spin_unlock(&solo_enc->av_lock);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400692}
693
Hans Verkuildcae5da2013-03-25 05:35:17 -0300694static int solo_ring_start(struct solo_dev *solo_dev)
695{
Hans Verkuildcae5da2013-03-25 05:35:17 -0300696 solo_dev->ring_thread = kthread_run(solo_ring_thread, solo_dev,
697 SOLO6X10_NAME "_ring");
698 if (IS_ERR(solo_dev->ring_thread)) {
699 int err = PTR_ERR(solo_dev->ring_thread);
Hans Verkuil1c6f3db2014-07-17 20:40:22 -0300700
Hans Verkuildcae5da2013-03-25 05:35:17 -0300701 solo_dev->ring_thread = NULL;
702 return err;
703 }
704
705 solo_irq_on(solo_dev, SOLO_IRQ_ENCODER);
706
707 return 0;
708}
709
710static void solo_ring_stop(struct solo_dev *solo_dev)
711{
Hans Verkuildcae5da2013-03-25 05:35:17 -0300712 if (solo_dev->ring_thread) {
713 kthread_stop(solo_dev->ring_thread);
714 solo_dev->ring_thread = NULL;
715 }
716
717 solo_irq_off(solo_dev, SOLO_IRQ_ENCODER);
718}
719
Hans Verkuil382c31a2013-03-15 12:04:14 -0300720static int solo_enc_start_streaming(struct vb2_queue *q, unsigned int count)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400721{
Hans Verkuil382c31a2013-03-15 12:04:14 -0300722 struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400723
Andrey Utkin670390c2014-10-29 13:03:53 -0300724 return solo_enc_on(solo_enc);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400725}
726
Hans Verkuile37559b2014-04-17 02:47:21 -0300727static void solo_enc_stop_streaming(struct vb2_queue *q)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400728{
Hans Verkuil382c31a2013-03-15 12:04:14 -0300729 struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q);
Andrey Utkin9ccd1802014-11-06 18:06:18 -0300730 unsigned long flags;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300731
Andrey Utkin9ccd1802014-11-06 18:06:18 -0300732 spin_lock_irqsave(&solo_enc->av_lock, flags);
Hans Verkuila7eb9312013-03-18 08:41:13 -0300733 solo_enc_off(solo_enc);
Andrey Utkin9ccd1802014-11-06 18:06:18 -0300734 while (!list_empty(&solo_enc->vidq_active)) {
735 struct solo_vb2_buf *buf = list_entry(
736 solo_enc->vidq_active.next,
737 struct solo_vb2_buf, list);
738
739 list_del(&buf->list);
Junghak Sung2d700712015-09-22 10:30:30 -0300740 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
Andrey Utkin9ccd1802014-11-06 18:06:18 -0300741 }
742 spin_unlock_irqrestore(&solo_enc->av_lock, flags);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400743}
744
Hans Verkuild790b7e2014-11-24 08:50:31 -0300745static void solo_enc_buf_finish(struct vb2_buffer *vb)
746{
Junghak Sung2d700712015-09-22 10:30:30 -0300747 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
Hans Verkuild790b7e2014-11-24 08:50:31 -0300748 struct solo_enc_dev *solo_enc = vb2_get_drv_priv(vb->vb2_queue);
Junghak Sung2d700712015-09-22 10:30:30 -0300749 struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
Hans Verkuild790b7e2014-11-24 08:50:31 -0300750
751 switch (solo_enc->fmt) {
752 case V4L2_PIX_FMT_MPEG4:
753 case V4L2_PIX_FMT_H264:
Junghak Sung2d700712015-09-22 10:30:30 -0300754 if (vbuf->flags & V4L2_BUF_FLAG_KEYFRAME)
755 sg_copy_from_buffer(sgt->sgl, sgt->nents,
Hans Verkuild790b7e2014-11-24 08:50:31 -0300756 solo_enc->vop, solo_enc->vop_len);
757 break;
758 default: /* V4L2_PIX_FMT_MJPEG */
Junghak Sung2d700712015-09-22 10:30:30 -0300759 sg_copy_from_buffer(sgt->sgl, sgt->nents,
Hans Verkuild790b7e2014-11-24 08:50:31 -0300760 solo_enc->jpeg_header, solo_enc->jpeg_len);
761 break;
762 }
763}
764
Hans Verkuil382c31a2013-03-15 12:04:14 -0300765static struct vb2_ops solo_enc_video_qops = {
766 .queue_setup = solo_enc_queue_setup,
767 .buf_queue = solo_enc_buf_queue,
Hans Verkuild790b7e2014-11-24 08:50:31 -0300768 .buf_finish = solo_enc_buf_finish,
Hans Verkuil382c31a2013-03-15 12:04:14 -0300769 .start_streaming = solo_enc_start_streaming,
770 .stop_streaming = solo_enc_stop_streaming,
771 .wait_prepare = vb2_ops_wait_prepare,
772 .wait_finish = vb2_ops_wait_finish,
773};
774
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400775static int solo_enc_querycap(struct file *file, void *priv,
776 struct v4l2_capability *cap)
777{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300778 struct solo_enc_dev *solo_enc = video_drvdata(file);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100779 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400780
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100781 strcpy(cap->driver, SOLO6X10_NAME);
782 snprintf(cap->card, sizeof(cap->card), "Softlogic 6x10 Enc %d",
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400783 solo_enc->ch);
Hans Verkuil20c5f492013-03-12 18:03:20 -0300784 snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400785 pci_name(solo_dev->pdev));
Hans Verkuil20c5f492013-03-12 18:03:20 -0300786 cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
787 V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
788 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400789 return 0;
790}
791
792static int solo_enc_enum_input(struct file *file, void *priv,
793 struct v4l2_input *input)
794{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300795 struct solo_enc_dev *solo_enc = video_drvdata(file);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100796 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400797
798 if (input->index)
799 return -EINVAL;
800
801 snprintf(input->name, sizeof(input->name), "Encoder %d",
802 solo_enc->ch + 1);
803 input->type = V4L2_INPUT_TYPE_CAMERA;
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300804 input->std = solo_enc->vfd->tvnorms;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400805
806 if (!tw28_get_video_status(solo_dev, solo_enc->ch))
807 input->status = V4L2_IN_ST_NO_SIGNAL;
808
809 return 0;
810}
811
Hans Verkuildcae5da2013-03-25 05:35:17 -0300812static int solo_enc_set_input(struct file *file, void *priv,
813 unsigned int index)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400814{
815 if (index)
816 return -EINVAL;
817
818 return 0;
819}
820
821static int solo_enc_get_input(struct file *file, void *priv,
822 unsigned int *index)
823{
824 *index = 0;
825
826 return 0;
827}
828
829static int solo_enc_enum_fmt_cap(struct file *file, void *priv,
830 struct v4l2_fmtdesc *f)
831{
Ismael Luceno16af6902013-04-18 10:56:35 -0300832 struct solo_enc_dev *solo_enc = video_drvdata(file);
833 int dev_type = solo_enc->solo_dev->type;
834
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400835 switch (f->index) {
836 case 0:
Ismael Luceno16af6902013-04-18 10:56:35 -0300837 switch (dev_type) {
838 case SOLO_DEV_6010:
839 f->pixelformat = V4L2_PIX_FMT_MPEG4;
840 strcpy(f->description, "MPEG-4 part 2");
841 break;
842 case SOLO_DEV_6110:
843 f->pixelformat = V4L2_PIX_FMT_H264;
844 strcpy(f->description, "H.264");
845 break;
846 }
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400847 break;
848 case 1:
849 f->pixelformat = V4L2_PIX_FMT_MJPEG;
850 strcpy(f->description, "MJPEG");
851 break;
852 default:
853 return -EINVAL;
854 }
855
856 f->flags = V4L2_FMT_FLAG_COMPRESSED;
857
858 return 0;
859}
860
Ismael Luceno16af6902013-04-18 10:56:35 -0300861static inline int solo_valid_pixfmt(u32 pixfmt, int dev_type)
862{
863 return (pixfmt == V4L2_PIX_FMT_H264 && dev_type == SOLO_DEV_6110)
864 || (pixfmt == V4L2_PIX_FMT_MPEG4 && dev_type == SOLO_DEV_6010)
865 || pixfmt == V4L2_PIX_FMT_MJPEG ? 0 : -EINVAL;
866}
867
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400868static int solo_enc_try_fmt_cap(struct file *file, void *priv,
869 struct v4l2_format *f)
870{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300871 struct solo_enc_dev *solo_enc = video_drvdata(file);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100872 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400873 struct v4l2_pix_format *pix = &f->fmt.pix;
874
Ismael Luceno16af6902013-04-18 10:56:35 -0300875 if (solo_valid_pixfmt(pix->pixelformat, solo_dev->type))
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400876 return -EINVAL;
877
Krzysztof Hałasa98ab1c92011-02-11 13:10:30 +0100878 if (pix->width < solo_dev->video_hsize ||
879 pix->height < solo_dev->video_vsize << 1) {
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400880 /* Default to CIF 1/2 size */
881 pix->width = solo_dev->video_hsize >> 1;
882 pix->height = solo_dev->video_vsize;
Krzysztof Hałasa98ab1c92011-02-11 13:10:30 +0100883 } else {
884 /* Full frame */
885 pix->width = solo_dev->video_hsize;
886 pix->height = solo_dev->video_vsize << 1;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400887 }
888
Hans Verkuil016afda2013-03-12 18:43:21 -0300889 switch (pix->field) {
890 case V4L2_FIELD_NONE:
891 case V4L2_FIELD_INTERLACED:
892 break;
893 case V4L2_FIELD_ANY:
894 default:
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400895 pix->field = V4L2_FIELD_INTERLACED;
Hans Verkuil016afda2013-03-12 18:43:21 -0300896 break;
897 }
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400898
899 /* Just set these */
900 pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
901 pix->sizeimage = FRAME_BUF_SIZE;
Hans Verkuil94160492013-03-12 18:47:03 -0300902 pix->bytesperline = 0;
Hans Verkuil016afda2013-03-12 18:43:21 -0300903 pix->priv = 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400904
905 return 0;
906}
907
908static int solo_enc_set_fmt_cap(struct file *file, void *priv,
909 struct v4l2_format *f)
910{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300911 struct solo_enc_dev *solo_enc = video_drvdata(file);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100912 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400913 struct v4l2_pix_format *pix = &f->fmt.pix;
914 int ret;
915
Hans Verkuil382c31a2013-03-15 12:04:14 -0300916 if (vb2_is_busy(&solo_enc->vidq))
917 return -EBUSY;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400918
facugaichafabbe62010-11-10 10:39:33 -0300919 ret = solo_enc_try_fmt_cap(file, priv, f);
Hans Verkuil016afda2013-03-12 18:43:21 -0300920 if (ret)
921 return ret;
922
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400923 if (pix->width == solo_dev->video_hsize)
924 solo_enc->mode = SOLO_ENC_MODE_D1;
925 else
926 solo_enc->mode = SOLO_ENC_MODE_CIF;
927
928 /* This does not change the encoder at all */
Hans Verkuila7eb9312013-03-18 08:41:13 -0300929 solo_enc->fmt = pix->pixelformat;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400930
Hans Verkuil69996872013-03-15 16:35:28 -0300931 /*
932 * More information is needed about these 'extended' types. As far
933 * as I can tell these are basically additional video streams with
934 * different MPEG encoding attributes that can run in parallel with
935 * the main stream. If so, then this should be implemented as a
936 * second video node. Abusing priv like this is certainly not the
937 * right approach.
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400938 if (pix->priv)
Hans Verkuila7eb9312013-03-18 08:41:13 -0300939 solo_enc->type = SOLO_ENC_TYPE_EXT;
Hans Verkuil69996872013-03-15 16:35:28 -0300940 */
Ismael Lucenocdcfe402013-04-12 18:28:33 -0300941 solo_update_mode(solo_enc);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300942 return 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400943}
944
945static int solo_enc_get_fmt_cap(struct file *file, void *priv,
946 struct v4l2_format *f)
947{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300948 struct solo_enc_dev *solo_enc = video_drvdata(file);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400949 struct v4l2_pix_format *pix = &f->fmt.pix;
950
951 pix->width = solo_enc->width;
952 pix->height = solo_enc->height;
Hans Verkuila7eb9312013-03-18 08:41:13 -0300953 pix->pixelformat = solo_enc->fmt;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400954 pix->field = solo_enc->interlaced ? V4L2_FIELD_INTERLACED :
955 V4L2_FIELD_NONE;
956 pix->sizeimage = FRAME_BUF_SIZE;
957 pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
Hans Verkuil016afda2013-03-12 18:43:21 -0300958 pix->priv = 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400959
960 return 0;
961}
962
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300963static int solo_enc_g_std(struct file *file, void *priv, v4l2_std_id *i)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400964{
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300965 struct solo_enc_dev *solo_enc = video_drvdata(file);
966 struct solo_dev *solo_dev = solo_enc->solo_dev;
967
968 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
969 *i = V4L2_STD_NTSC_M;
970 else
971 *i = V4L2_STD_PAL;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400972 return 0;
973}
974
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300975static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id std)
976{
977 struct solo_enc_dev *solo_enc = video_drvdata(file);
978
Hans Verkuil429df502014-01-13 06:58:12 -0300979 return solo_set_video_type(solo_enc->solo_dev, std & V4L2_STD_625_50);
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300980}
981
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400982static int solo_enum_framesizes(struct file *file, void *priv,
983 struct v4l2_frmsizeenum *fsize)
984{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300985 struct solo_enc_dev *solo_enc = video_drvdata(file);
986 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400987
Ismael Luceno16af6902013-04-18 10:56:35 -0300988 if (solo_valid_pixfmt(fsize->pixel_format, solo_dev->type))
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400989 return -EINVAL;
990
991 switch (fsize->index) {
992 case 0:
993 fsize->discrete.width = solo_dev->video_hsize >> 1;
994 fsize->discrete.height = solo_dev->video_vsize;
995 break;
996 case 1:
997 fsize->discrete.width = solo_dev->video_hsize;
998 fsize->discrete.height = solo_dev->video_vsize << 1;
999 break;
1000 default:
1001 return -EINVAL;
1002 }
1003
1004 fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1005
1006 return 0;
1007}
1008
1009static int solo_enum_frameintervals(struct file *file, void *priv,
1010 struct v4l2_frmivalenum *fintv)
1011{
Hans Verkuila7eb9312013-03-18 08:41:13 -03001012 struct solo_enc_dev *solo_enc = video_drvdata(file);
1013 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001014
Ismael Luceno16af6902013-04-18 10:56:35 -03001015 if (solo_valid_pixfmt(fintv->pixel_format, solo_dev->type))
Hans Verkuil016afda2013-03-12 18:43:21 -03001016 return -EINVAL;
1017 if (fintv->index)
1018 return -EINVAL;
1019 if ((fintv->width != solo_dev->video_hsize >> 1 ||
1020 fintv->height != solo_dev->video_vsize) &&
1021 (fintv->width != solo_dev->video_hsize ||
1022 fintv->height != solo_dev->video_vsize << 1))
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001023 return -EINVAL;
1024
1025 fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE;
1026
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001027 fintv->stepwise.min.numerator = 1;
Hans Verkuil016afda2013-03-12 18:43:21 -03001028 fintv->stepwise.min.denominator = solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001029
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001030 fintv->stepwise.max.numerator = 15;
Hans Verkuil016afda2013-03-12 18:43:21 -03001031 fintv->stepwise.max.denominator = solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001032
1033 fintv->stepwise.step.numerator = 1;
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001034 fintv->stepwise.step.denominator = solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001035
1036 return 0;
1037}
1038
1039static int solo_g_parm(struct file *file, void *priv,
1040 struct v4l2_streamparm *sp)
1041{
Hans Verkuila7eb9312013-03-18 08:41:13 -03001042 struct solo_enc_dev *solo_enc = video_drvdata(file);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001043 struct v4l2_captureparm *cp = &sp->parm.capture;
1044
1045 cp->capability = V4L2_CAP_TIMEPERFRAME;
1046 cp->timeperframe.numerator = solo_enc->interval;
Ismael Luceno88107672013-05-03 15:54:57 -03001047 cp->timeperframe.denominator = solo_enc->solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001048 cp->capturemode = 0;
1049 /* XXX: Shouldn't we be able to get/set this from videobuf? */
1050 cp->readbuffers = 2;
1051
Ben Collinsf62de9b2010-11-04 22:51:17 -04001052 return 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001053}
1054
Ismael Luceno88107672013-05-03 15:54:57 -03001055static inline int calc_interval(u8 fps, u32 n, u32 d)
1056{
1057 if (!n || !d)
1058 return 1;
1059 if (d == fps)
1060 return n;
1061 n *= fps;
1062 return min(15U, n / d + (n % d >= (fps >> 1)));
1063}
1064
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001065static int solo_s_parm(struct file *file, void *priv,
1066 struct v4l2_streamparm *sp)
1067{
Hans Verkuila7eb9312013-03-18 08:41:13 -03001068 struct solo_enc_dev *solo_enc = video_drvdata(file);
Ismael Luceno88107672013-05-03 15:54:57 -03001069 struct v4l2_fract *t = &sp->parm.capture.timeperframe;
1070 u8 fps = solo_enc->solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001071
Hans Verkuil382c31a2013-03-15 12:04:14 -03001072 if (vb2_is_streaming(&solo_enc->vidq))
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001073 return -EBUSY;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001074
Ismael Luceno88107672013-05-03 15:54:57 -03001075 solo_enc->interval = calc_interval(fps, t->numerator, t->denominator);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001076 solo_update_mode(solo_enc);
Ismael Luceno88107672013-05-03 15:54:57 -03001077 return solo_g_parm(file, priv, sp);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001078}
1079
Hans Verkuilc813bd32013-03-25 05:38:14 -03001080static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001081{
Hans Verkuilc813bd32013-03-25 05:38:14 -03001082 struct solo_enc_dev *solo_enc =
1083 container_of(ctrl->handler, struct solo_enc_dev, hdl);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +01001084 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001085 int err;
1086
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001087 switch (ctrl->id) {
1088 case V4L2_CID_BRIGHTNESS:
1089 case V4L2_CID_CONTRAST:
1090 case V4L2_CID_SATURATION:
1091 case V4L2_CID_HUE:
1092 case V4L2_CID_SHARPNESS:
1093 return tw28_set_ctrl_val(solo_dev, ctrl->id, solo_enc->ch,
Hans Verkuilc813bd32013-03-25 05:38:14 -03001094 ctrl->val);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001095 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
Hans Verkuilc813bd32013-03-25 05:38:14 -03001096 solo_enc->gop = ctrl->val;
Andrey Utkin63e9b452014-07-08 12:23:33 -03001097 solo_reg_write(solo_dev, SOLO_VE_CH_GOP(solo_enc->ch), solo_enc->gop);
1098 solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(solo_enc->ch), solo_enc->gop);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001099 return 0;
Andrey Utkin56981112014-07-08 12:23:32 -03001100 case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
1101 solo_enc->qp = ctrl->val;
Andrey Utkin63e9b452014-07-08 12:23:33 -03001102 solo_reg_write(solo_dev, SOLO_VE_CH_QP(solo_enc->ch), solo_enc->qp);
1103 solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(solo_enc->ch), solo_enc->qp);
Andrey Utkin56981112014-07-08 12:23:32 -03001104 return 0;
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001105 case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD:
1106 solo_enc->motion_thresh = ctrl->val << 8;
Hans Verkuilf5df0b72013-03-18 08:43:14 -03001107 if (!solo_enc->motion_global || !solo_enc->motion_enabled)
1108 return 0;
Aybuke Ozdemirfa917832014-03-13 02:20:20 +02001109 return solo_set_motion_threshold(solo_dev, solo_enc->ch,
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001110 solo_enc->motion_thresh);
1111 case V4L2_CID_DETECT_MD_MODE:
1112 solo_enc->motion_global = ctrl->val == V4L2_DETECT_MD_MODE_GLOBAL;
1113 solo_enc->motion_enabled = ctrl->val > V4L2_DETECT_MD_MODE_DISABLED;
Hans Verkuilf5df0b72013-03-18 08:43:14 -03001114 if (ctrl->val) {
1115 if (solo_enc->motion_global)
Hans Verkuil0a128302014-07-25 08:19:54 -03001116 err = solo_set_motion_threshold(solo_dev, solo_enc->ch,
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001117 solo_enc->motion_thresh);
Hans Verkuilf5df0b72013-03-18 08:43:14 -03001118 else
Hans Verkuil0a128302014-07-25 08:19:54 -03001119 err = solo_set_motion_block(solo_dev, solo_enc->ch,
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001120 solo_enc->md_thresholds->p_cur.p_u16);
Hans Verkuil0a128302014-07-25 08:19:54 -03001121 if (err)
1122 return err;
Hans Verkuildcae5da2013-03-25 05:35:17 -03001123 }
Hans Verkuilc813bd32013-03-25 05:38:14 -03001124 solo_motion_toggle(solo_enc, ctrl->val);
1125 return 0;
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001126 case V4L2_CID_DETECT_MD_THRESHOLD_GRID:
1127 if (solo_enc->motion_enabled && !solo_enc->motion_global)
1128 return solo_set_motion_block(solo_dev, solo_enc->ch,
1129 solo_enc->md_thresholds->p_new.p_u16);
1130 break;
Hans Verkuilc813bd32013-03-25 05:38:14 -03001131 case V4L2_CID_OSD_TEXT:
Hans Verkuil2a9ec372014-04-27 03:38:13 -03001132 strcpy(solo_enc->osd_text, ctrl->p_new.p_char);
Hans Verkuil0a128302014-07-25 08:19:54 -03001133 return solo_osd_print(solo_enc);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001134 default:
1135 return -EINVAL;
1136 }
1137
1138 return 0;
1139}
1140
Hans Verkuil316d9e82014-01-27 11:16:05 -03001141static int solo_subscribe_event(struct v4l2_fh *fh,
1142 const struct v4l2_event_subscription *sub)
1143{
1144
1145 switch (sub->type) {
1146 case V4L2_EVENT_CTRL:
1147 return v4l2_ctrl_subscribe_event(fh, sub);
1148 case V4L2_EVENT_MOTION_DET:
1149 /* Allow for up to 30 events (1 second for NTSC) to be
1150 * stored. */
1151 return v4l2_event_subscribe(fh, sub, 30, NULL);
1152 }
1153 return -EINVAL;
1154}
1155
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001156static const struct v4l2_file_operations solo_enc_fops = {
1157 .owner = THIS_MODULE,
Hans Verkuil382c31a2013-03-15 12:04:14 -03001158 .open = v4l2_fh_open,
1159 .release = vb2_fop_release,
1160 .read = vb2_fop_read,
1161 .poll = vb2_fop_poll,
1162 .mmap = vb2_fop_mmap,
1163 .unlocked_ioctl = video_ioctl2,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001164};
1165
1166static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = {
1167 .vidioc_querycap = solo_enc_querycap,
1168 .vidioc_s_std = solo_enc_s_std,
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001169 .vidioc_g_std = solo_enc_g_std,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001170 /* Input callbacks */
1171 .vidioc_enum_input = solo_enc_enum_input,
1172 .vidioc_s_input = solo_enc_set_input,
1173 .vidioc_g_input = solo_enc_get_input,
1174 /* Video capture format callbacks */
1175 .vidioc_enum_fmt_vid_cap = solo_enc_enum_fmt_cap,
1176 .vidioc_try_fmt_vid_cap = solo_enc_try_fmt_cap,
1177 .vidioc_s_fmt_vid_cap = solo_enc_set_fmt_cap,
1178 .vidioc_g_fmt_vid_cap = solo_enc_get_fmt_cap,
1179 /* Streaming I/O */
Hans Verkuil382c31a2013-03-15 12:04:14 -03001180 .vidioc_reqbufs = vb2_ioctl_reqbufs,
1181 .vidioc_querybuf = vb2_ioctl_querybuf,
1182 .vidioc_qbuf = vb2_ioctl_qbuf,
1183 .vidioc_dqbuf = vb2_ioctl_dqbuf,
1184 .vidioc_streamon = vb2_ioctl_streamon,
1185 .vidioc_streamoff = vb2_ioctl_streamoff,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001186 /* Frame size and interval */
1187 .vidioc_enum_framesizes = solo_enum_framesizes,
1188 .vidioc_enum_frameintervals = solo_enum_frameintervals,
1189 /* Video capture parameters */
1190 .vidioc_s_parm = solo_s_parm,
1191 .vidioc_g_parm = solo_g_parm,
Hans Verkuil94160492013-03-12 18:47:03 -03001192 /* Logging and events */
1193 .vidioc_log_status = v4l2_ctrl_log_status,
Hans Verkuil316d9e82014-01-27 11:16:05 -03001194 .vidioc_subscribe_event = solo_subscribe_event,
Hans Verkuil94160492013-03-12 18:47:03 -03001195 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001196};
1197
Hans Verkuildcae5da2013-03-25 05:35:17 -03001198static const struct video_device solo_enc_template = {
Krzysztof Hałasadecebab2011-02-11 13:38:20 +01001199 .name = SOLO6X10_NAME,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001200 .fops = &solo_enc_fops,
1201 .ioctl_ops = &solo_enc_ioctl_ops,
1202 .minor = -1,
1203 .release = video_device_release,
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001204 .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001205};
1206
Hans Verkuilc813bd32013-03-25 05:38:14 -03001207static const struct v4l2_ctrl_ops solo_ctrl_ops = {
1208 .s_ctrl = solo_s_ctrl,
1209};
1210
Hans Verkuilc813bd32013-03-25 05:38:14 -03001211static const struct v4l2_ctrl_config solo_osd_text_ctrl = {
1212 .ops = &solo_ctrl_ops,
1213 .id = V4L2_CID_OSD_TEXT,
1214 .name = "OSD Text",
1215 .type = V4L2_CTRL_TYPE_STRING,
1216 .max = OSD_TEXT_MAX,
1217 .step = 1,
1218};
1219
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001220/* Motion Detection Threshold matrix */
1221static const struct v4l2_ctrl_config solo_md_thresholds = {
1222 .ops = &solo_ctrl_ops,
1223 .id = V4L2_CID_DETECT_MD_THRESHOLD_GRID,
1224 .dims = { SOLO_MOTION_SZ, SOLO_MOTION_SZ },
1225 .def = SOLO_DEF_MOT_THRESH,
1226 .max = 65535,
1227 .step = 1,
1228};
1229
Hans Verkuildcae5da2013-03-25 05:35:17 -03001230static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
1231 u8 ch, unsigned nr)
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001232{
1233 struct solo_enc_dev *solo_enc;
Hans Verkuilc813bd32013-03-25 05:38:14 -03001234 struct v4l2_ctrl_handler *hdl;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001235 int ret;
1236
1237 solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL);
1238 if (!solo_enc)
1239 return ERR_PTR(-ENOMEM);
1240
Hans Verkuilc813bd32013-03-25 05:38:14 -03001241 hdl = &solo_enc->hdl;
Hans Verkuil0c3a14c2014-11-18 09:51:01 -03001242 solo_enc->alloc_ctx = vb2_dma_sg_init_ctx(&solo_dev->pdev->dev);
1243 if (IS_ERR(solo_enc->alloc_ctx)) {
1244 ret = PTR_ERR(solo_enc->alloc_ctx);
1245 goto hdl_free;
1246 }
Hans Verkuilc813bd32013-03-25 05:38:14 -03001247 v4l2_ctrl_handler_init(hdl, 10);
1248 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1249 V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
1250 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1251 V4L2_CID_CONTRAST, 0, 255, 1, 128);
1252 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1253 V4L2_CID_SATURATION, 0, 255, 1, 128);
1254 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1255 V4L2_CID_HUE, 0, 255, 1, 128);
1256 if (tw28_has_sharpness(solo_dev, ch))
1257 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1258 V4L2_CID_SHARPNESS, 0, 15, 1, 0);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001259 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1260 V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 255, 1, solo_dev->fps);
Andrey Utkin56981112014-07-08 12:23:32 -03001261 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1262 V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 31, 1, SOLO_DEFAULT_QP);
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001263 v4l2_ctrl_new_std_menu(hdl, &solo_ctrl_ops,
1264 V4L2_CID_DETECT_MD_MODE,
1265 V4L2_DETECT_MD_MODE_THRESHOLD_GRID, 0,
1266 V4L2_DETECT_MD_MODE_DISABLED);
1267 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1268 V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD, 0, 0xff, 1,
1269 SOLO_DEF_MOT_THRESH >> 8);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001270 v4l2_ctrl_new_custom(hdl, &solo_osd_text_ctrl, NULL);
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001271 solo_enc->md_thresholds =
1272 v4l2_ctrl_new_custom(hdl, &solo_md_thresholds, NULL);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001273 if (hdl->error) {
1274 ret = hdl->error;
Hans Verkuila7eb9312013-03-18 08:41:13 -03001275 goto hdl_free;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001276 }
1277
1278 solo_enc->solo_dev = solo_dev;
1279 solo_enc->ch = ch;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001280 mutex_init(&solo_enc->lock);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001281 spin_lock_init(&solo_enc->av_lock);
1282 INIT_LIST_HEAD(&solo_enc->vidq_active);
Ismael Luceno16af6902013-04-18 10:56:35 -03001283 solo_enc->fmt = (solo_dev->type == SOLO_DEV_6010) ?
1284 V4L2_PIX_FMT_MPEG4 : V4L2_PIX_FMT_H264;
Hans Verkuila7eb9312013-03-18 08:41:13 -03001285 solo_enc->type = SOLO_ENC_TYPE_STD;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001286
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001287 solo_enc->qp = SOLO_DEFAULT_QP;
Ben Collinsf62de9b2010-11-04 22:51:17 -04001288 solo_enc->gop = solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001289 solo_enc->interval = 1;
1290 solo_enc->mode = SOLO_ENC_MODE_CIF;
Hans Verkuilf5df0b72013-03-18 08:43:14 -03001291 solo_enc->motion_global = true;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001292 solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001293 solo_enc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1294 solo_enc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
1295 solo_enc->vidq.ops = &solo_enc_video_qops;
1296 solo_enc->vidq.mem_ops = &vb2_dma_sg_memops;
1297 solo_enc->vidq.drv_priv = solo_enc;
Mel Gormand0164ad2015-11-06 16:28:21 -08001298 solo_enc->vidq.gfp_flags = __GFP_DMA32 | __GFP_KSWAPD_RECLAIM;
Sakari Ailusade48682014-02-25 19:12:19 -03001299 solo_enc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001300 solo_enc->vidq.buf_struct_size = sizeof(struct solo_vb2_buf);
1301 solo_enc->vidq.lock = &solo_enc->lock;
1302 ret = vb2_queue_init(&solo_enc->vidq);
1303 if (ret)
1304 goto hdl_free;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001305 solo_update_mode(solo_enc);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001306
Hans Verkuila7eb9312013-03-18 08:41:13 -03001307 spin_lock_init(&solo_enc->motion_lock);
1308
Hans Verkuildcae5da2013-03-25 05:35:17 -03001309 /* Initialize this per encoder */
1310 solo_enc->jpeg_len = sizeof(jpeg_header);
1311 memcpy(solo_enc->jpeg_header, jpeg_header, solo_enc->jpeg_len);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001312
Hans Verkuila7eb9312013-03-18 08:41:13 -03001313 solo_enc->desc_nelts = 32;
1314 solo_enc->desc_items = pci_alloc_consistent(solo_dev->pdev,
1315 sizeof(struct solo_p2m_desc) *
Aybuke Ozdemirfa917832014-03-13 02:20:20 +02001316 solo_enc->desc_nelts,
1317 &solo_enc->desc_dma);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001318 ret = -ENOMEM;
1319 if (solo_enc->desc_items == NULL)
1320 goto hdl_free;
1321
Hans Verkuila7eb9312013-03-18 08:41:13 -03001322 solo_enc->vfd = video_device_alloc();
1323 if (!solo_enc->vfd)
1324 goto pci_free;
1325
1326 *solo_enc->vfd = solo_enc_template;
1327 solo_enc->vfd->v4l2_dev = &solo_dev->v4l2_dev;
1328 solo_enc->vfd->ctrl_handler = hdl;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001329 solo_enc->vfd->queue = &solo_enc->vidq;
1330 solo_enc->vfd->lock = &solo_enc->lock;
Hans Verkuila7eb9312013-03-18 08:41:13 -03001331 video_set_drvdata(solo_enc->vfd, solo_enc);
1332 ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr);
1333 if (ret < 0)
1334 goto vdev_release;
1335
1336 snprintf(solo_enc->vfd->name, sizeof(solo_enc->vfd->name),
1337 "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num,
1338 solo_enc->vfd->num);
1339
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001340 return solo_enc;
Hans Verkuila7eb9312013-03-18 08:41:13 -03001341
1342vdev_release:
1343 video_device_release(solo_enc->vfd);
1344pci_free:
1345 pci_free_consistent(solo_enc->solo_dev->pdev,
1346 sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts,
1347 solo_enc->desc_items, solo_enc->desc_dma);
1348hdl_free:
1349 v4l2_ctrl_handler_free(hdl);
Hans Verkuil0c3a14c2014-11-18 09:51:01 -03001350 vb2_dma_sg_cleanup_ctx(solo_enc->alloc_ctx);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001351 kfree(solo_enc);
1352 return ERR_PTR(ret);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001353}
1354
1355static void solo_enc_free(struct solo_enc_dev *solo_enc)
1356{
1357 if (solo_enc == NULL)
1358 return;
1359
Andrey Utkin0cb2df32014-10-29 13:03:52 -03001360 pci_free_consistent(solo_enc->solo_dev->pdev,
1361 sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts,
1362 solo_enc->desc_items, solo_enc->desc_dma);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001363 video_unregister_device(solo_enc->vfd);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001364 v4l2_ctrl_handler_free(&solo_enc->hdl);
Hans Verkuil0c3a14c2014-11-18 09:51:01 -03001365 vb2_dma_sg_cleanup_ctx(solo_enc->alloc_ctx);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001366 kfree(solo_enc);
1367}
1368
Hans Verkuildcae5da2013-03-25 05:35:17 -03001369int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001370{
1371 int i;
1372
Hans Verkuildcae5da2013-03-25 05:35:17 -03001373 init_waitqueue_head(&solo_dev->ring_thread_wait);
1374
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -03001375 solo_dev->vh_size = sizeof(vop_header);
Hans Verkuildcae5da2013-03-25 05:35:17 -03001376 solo_dev->vh_buf = pci_alloc_consistent(solo_dev->pdev,
1377 solo_dev->vh_size,
1378 &solo_dev->vh_dma);
1379 if (solo_dev->vh_buf == NULL)
1380 return -ENOMEM;
1381
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001382 for (i = 0; i < solo_dev->nr_chans; i++) {
Hans Verkuildcae5da2013-03-25 05:35:17 -03001383 solo_dev->v4l2_enc[i] = solo_enc_alloc(solo_dev, i, nr);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001384 if (IS_ERR(solo_dev->v4l2_enc[i]))
1385 break;
1386 }
1387
1388 if (i != solo_dev->nr_chans) {
1389 int ret = PTR_ERR(solo_dev->v4l2_enc[i]);
Hans Verkuil1c6f3db2014-07-17 20:40:22 -03001390
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001391 while (i--)
1392 solo_enc_free(solo_dev->v4l2_enc[i]);
Hans Verkuildcae5da2013-03-25 05:35:17 -03001393 pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
1394 solo_dev->vh_buf, solo_dev->vh_dma);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001395 solo_dev->vh_buf = NULL;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001396 return ret;
1397 }
1398
Hans Verkuildcae5da2013-03-25 05:35:17 -03001399 if (solo_dev->type == SOLO_DEV_6010)
1400 solo_dev->enc_bw_remain = solo_dev->fps * 4 * 4;
1401 else
1402 solo_dev->enc_bw_remain = solo_dev->fps * 4 * 5;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001403
1404 dev_info(&solo_dev->pdev->dev, "Encoders as /dev/video%d-%d\n",
1405 solo_dev->v4l2_enc[0]->vfd->num,
1406 solo_dev->v4l2_enc[solo_dev->nr_chans - 1]->vfd->num);
1407
Andrey Utkin670390c2014-10-29 13:03:53 -03001408 return solo_ring_start(solo_dev);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001409}
1410
Krzysztof Hałasadecebab2011-02-11 13:38:20 +01001411void solo_enc_v4l2_exit(struct solo_dev *solo_dev)
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001412{
1413 int i;
1414
Andrey Utkin670390c2014-10-29 13:03:53 -03001415 solo_ring_stop(solo_dev);
1416
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001417 for (i = 0; i < solo_dev->nr_chans; i++)
1418 solo_enc_free(solo_dev->v4l2_enc[i]);
Hans Verkuildcae5da2013-03-25 05:35:17 -03001419
Hans Verkuila7eb9312013-03-18 08:41:13 -03001420 if (solo_dev->vh_buf)
1421 pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
Hans Verkuildcae5da2013-03-25 05:35:17 -03001422 solo_dev->vh_buf, solo_dev->vh_dma);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001423}