blob: 8b1cde57c8177131c6309d9f6768a2714076f611 [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[],
Hans Verkuil36c0f8b2016-04-15 09:15:05 -0300667 struct device *alloc_devs[])
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400668{
Hans Verkuil382c31a2013-03-15 12:04:14 -0300669 sizes[0] = FRAME_BUF_SIZE;
670 *num_planes = 1;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400671
Hans Verkuil382c31a2013-03-15 12:04:14 -0300672 if (*num_buffers < MIN_VID_BUFFERS)
673 *num_buffers = MIN_VID_BUFFERS;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400674
Ben Collinsf62de9b2010-11-04 22:51:17 -0400675 return 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400676}
677
Hans Verkuil382c31a2013-03-15 12:04:14 -0300678static void solo_enc_buf_queue(struct vb2_buffer *vb)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400679{
Junghak Sung2d700712015-09-22 10:30:30 -0300680 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
Hans Verkuil382c31a2013-03-15 12:04:14 -0300681 struct vb2_queue *vq = vb->vb2_queue;
682 struct solo_enc_dev *solo_enc = vb2_get_drv_priv(vq);
683 struct solo_vb2_buf *solo_vb =
Junghak Sung2d700712015-09-22 10:30:30 -0300684 container_of(vbuf, struct solo_vb2_buf, vb);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400685
Hans Verkuil382c31a2013-03-15 12:04:14 -0300686 spin_lock(&solo_enc->av_lock);
687 list_add_tail(&solo_vb->list, &solo_enc->vidq_active);
688 spin_unlock(&solo_enc->av_lock);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400689}
690
Hans Verkuildcae5da2013-03-25 05:35:17 -0300691static int solo_ring_start(struct solo_dev *solo_dev)
692{
Hans Verkuildcae5da2013-03-25 05:35:17 -0300693 solo_dev->ring_thread = kthread_run(solo_ring_thread, solo_dev,
694 SOLO6X10_NAME "_ring");
695 if (IS_ERR(solo_dev->ring_thread)) {
696 int err = PTR_ERR(solo_dev->ring_thread);
Hans Verkuil1c6f3db2014-07-17 20:40:22 -0300697
Hans Verkuildcae5da2013-03-25 05:35:17 -0300698 solo_dev->ring_thread = NULL;
699 return err;
700 }
701
702 solo_irq_on(solo_dev, SOLO_IRQ_ENCODER);
703
704 return 0;
705}
706
707static void solo_ring_stop(struct solo_dev *solo_dev)
708{
Hans Verkuildcae5da2013-03-25 05:35:17 -0300709 if (solo_dev->ring_thread) {
710 kthread_stop(solo_dev->ring_thread);
711 solo_dev->ring_thread = NULL;
712 }
713
714 solo_irq_off(solo_dev, SOLO_IRQ_ENCODER);
715}
716
Hans Verkuil382c31a2013-03-15 12:04:14 -0300717static int solo_enc_start_streaming(struct vb2_queue *q, unsigned int count)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400718{
Hans Verkuil382c31a2013-03-15 12:04:14 -0300719 struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400720
Andrey Utkin670390c2014-10-29 13:03:53 -0300721 return solo_enc_on(solo_enc);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400722}
723
Hans Verkuile37559b2014-04-17 02:47:21 -0300724static void solo_enc_stop_streaming(struct vb2_queue *q)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400725{
Hans Verkuil382c31a2013-03-15 12:04:14 -0300726 struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q);
Andrey Utkin9ccd1802014-11-06 18:06:18 -0300727 unsigned long flags;
Hans Verkuildcae5da2013-03-25 05:35:17 -0300728
Andrey Utkin9ccd1802014-11-06 18:06:18 -0300729 spin_lock_irqsave(&solo_enc->av_lock, flags);
Hans Verkuila7eb9312013-03-18 08:41:13 -0300730 solo_enc_off(solo_enc);
Andrey Utkin9ccd1802014-11-06 18:06:18 -0300731 while (!list_empty(&solo_enc->vidq_active)) {
732 struct solo_vb2_buf *buf = list_entry(
733 solo_enc->vidq_active.next,
734 struct solo_vb2_buf, list);
735
736 list_del(&buf->list);
Junghak Sung2d700712015-09-22 10:30:30 -0300737 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
Andrey Utkin9ccd1802014-11-06 18:06:18 -0300738 }
739 spin_unlock_irqrestore(&solo_enc->av_lock, flags);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400740}
741
Hans Verkuild790b7e2014-11-24 08:50:31 -0300742static void solo_enc_buf_finish(struct vb2_buffer *vb)
743{
Junghak Sung2d700712015-09-22 10:30:30 -0300744 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
Hans Verkuild790b7e2014-11-24 08:50:31 -0300745 struct solo_enc_dev *solo_enc = vb2_get_drv_priv(vb->vb2_queue);
Junghak Sung2d700712015-09-22 10:30:30 -0300746 struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
Hans Verkuild790b7e2014-11-24 08:50:31 -0300747
748 switch (solo_enc->fmt) {
749 case V4L2_PIX_FMT_MPEG4:
750 case V4L2_PIX_FMT_H264:
Junghak Sung2d700712015-09-22 10:30:30 -0300751 if (vbuf->flags & V4L2_BUF_FLAG_KEYFRAME)
752 sg_copy_from_buffer(sgt->sgl, sgt->nents,
Hans Verkuild790b7e2014-11-24 08:50:31 -0300753 solo_enc->vop, solo_enc->vop_len);
754 break;
755 default: /* V4L2_PIX_FMT_MJPEG */
Junghak Sung2d700712015-09-22 10:30:30 -0300756 sg_copy_from_buffer(sgt->sgl, sgt->nents,
Hans Verkuild790b7e2014-11-24 08:50:31 -0300757 solo_enc->jpeg_header, solo_enc->jpeg_len);
758 break;
759 }
760}
761
Hans Verkuil382c31a2013-03-15 12:04:14 -0300762static struct vb2_ops solo_enc_video_qops = {
763 .queue_setup = solo_enc_queue_setup,
764 .buf_queue = solo_enc_buf_queue,
Hans Verkuild790b7e2014-11-24 08:50:31 -0300765 .buf_finish = solo_enc_buf_finish,
Hans Verkuil382c31a2013-03-15 12:04:14 -0300766 .start_streaming = solo_enc_start_streaming,
767 .stop_streaming = solo_enc_stop_streaming,
768 .wait_prepare = vb2_ops_wait_prepare,
769 .wait_finish = vb2_ops_wait_finish,
770};
771
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400772static int solo_enc_querycap(struct file *file, void *priv,
773 struct v4l2_capability *cap)
774{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300775 struct solo_enc_dev *solo_enc = video_drvdata(file);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100776 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400777
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100778 strcpy(cap->driver, SOLO6X10_NAME);
779 snprintf(cap->card, sizeof(cap->card), "Softlogic 6x10 Enc %d",
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400780 solo_enc->ch);
Hans Verkuil20c5f492013-03-12 18:03:20 -0300781 snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400782 pci_name(solo_dev->pdev));
Hans Verkuil20c5f492013-03-12 18:03:20 -0300783 cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
784 V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
785 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400786 return 0;
787}
788
789static int solo_enc_enum_input(struct file *file, void *priv,
790 struct v4l2_input *input)
791{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300792 struct solo_enc_dev *solo_enc = video_drvdata(file);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100793 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400794
795 if (input->index)
796 return -EINVAL;
797
798 snprintf(input->name, sizeof(input->name), "Encoder %d",
799 solo_enc->ch + 1);
800 input->type = V4L2_INPUT_TYPE_CAMERA;
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300801 input->std = solo_enc->vfd->tvnorms;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400802
803 if (!tw28_get_video_status(solo_dev, solo_enc->ch))
804 input->status = V4L2_IN_ST_NO_SIGNAL;
805
806 return 0;
807}
808
Hans Verkuildcae5da2013-03-25 05:35:17 -0300809static int solo_enc_set_input(struct file *file, void *priv,
810 unsigned int index)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400811{
812 if (index)
813 return -EINVAL;
814
815 return 0;
816}
817
818static int solo_enc_get_input(struct file *file, void *priv,
819 unsigned int *index)
820{
821 *index = 0;
822
823 return 0;
824}
825
826static int solo_enc_enum_fmt_cap(struct file *file, void *priv,
827 struct v4l2_fmtdesc *f)
828{
Ismael Luceno16af6902013-04-18 10:56:35 -0300829 struct solo_enc_dev *solo_enc = video_drvdata(file);
830 int dev_type = solo_enc->solo_dev->type;
831
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400832 switch (f->index) {
833 case 0:
Ismael Luceno16af6902013-04-18 10:56:35 -0300834 switch (dev_type) {
835 case SOLO_DEV_6010:
836 f->pixelformat = V4L2_PIX_FMT_MPEG4;
837 strcpy(f->description, "MPEG-4 part 2");
838 break;
839 case SOLO_DEV_6110:
840 f->pixelformat = V4L2_PIX_FMT_H264;
841 strcpy(f->description, "H.264");
842 break;
843 }
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400844 break;
845 case 1:
846 f->pixelformat = V4L2_PIX_FMT_MJPEG;
847 strcpy(f->description, "MJPEG");
848 break;
849 default:
850 return -EINVAL;
851 }
852
853 f->flags = V4L2_FMT_FLAG_COMPRESSED;
854
855 return 0;
856}
857
Ismael Luceno16af6902013-04-18 10:56:35 -0300858static inline int solo_valid_pixfmt(u32 pixfmt, int dev_type)
859{
860 return (pixfmt == V4L2_PIX_FMT_H264 && dev_type == SOLO_DEV_6110)
861 || (pixfmt == V4L2_PIX_FMT_MPEG4 && dev_type == SOLO_DEV_6010)
862 || pixfmt == V4L2_PIX_FMT_MJPEG ? 0 : -EINVAL;
863}
864
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400865static int solo_enc_try_fmt_cap(struct file *file, void *priv,
866 struct v4l2_format *f)
867{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300868 struct solo_enc_dev *solo_enc = video_drvdata(file);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100869 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400870 struct v4l2_pix_format *pix = &f->fmt.pix;
871
Ismael Luceno16af6902013-04-18 10:56:35 -0300872 if (solo_valid_pixfmt(pix->pixelformat, solo_dev->type))
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400873 return -EINVAL;
874
Krzysztof Hałasa98ab1c92011-02-11 13:10:30 +0100875 if (pix->width < solo_dev->video_hsize ||
876 pix->height < solo_dev->video_vsize << 1) {
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400877 /* Default to CIF 1/2 size */
878 pix->width = solo_dev->video_hsize >> 1;
879 pix->height = solo_dev->video_vsize;
Krzysztof Hałasa98ab1c92011-02-11 13:10:30 +0100880 } else {
881 /* Full frame */
882 pix->width = solo_dev->video_hsize;
883 pix->height = solo_dev->video_vsize << 1;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400884 }
885
Hans Verkuil016afda2013-03-12 18:43:21 -0300886 switch (pix->field) {
887 case V4L2_FIELD_NONE:
888 case V4L2_FIELD_INTERLACED:
889 break;
890 case V4L2_FIELD_ANY:
891 default:
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400892 pix->field = V4L2_FIELD_INTERLACED;
Hans Verkuil016afda2013-03-12 18:43:21 -0300893 break;
894 }
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400895
896 /* Just set these */
897 pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
898 pix->sizeimage = FRAME_BUF_SIZE;
Hans Verkuil94160492013-03-12 18:47:03 -0300899 pix->bytesperline = 0;
Hans Verkuil016afda2013-03-12 18:43:21 -0300900 pix->priv = 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400901
902 return 0;
903}
904
905static int solo_enc_set_fmt_cap(struct file *file, void *priv,
906 struct v4l2_format *f)
907{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300908 struct solo_enc_dev *solo_enc = video_drvdata(file);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +0100909 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400910 struct v4l2_pix_format *pix = &f->fmt.pix;
911 int ret;
912
Hans Verkuil382c31a2013-03-15 12:04:14 -0300913 if (vb2_is_busy(&solo_enc->vidq))
914 return -EBUSY;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400915
facugaichafabbe62010-11-10 10:39:33 -0300916 ret = solo_enc_try_fmt_cap(file, priv, f);
Hans Verkuil016afda2013-03-12 18:43:21 -0300917 if (ret)
918 return ret;
919
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400920 if (pix->width == solo_dev->video_hsize)
921 solo_enc->mode = SOLO_ENC_MODE_D1;
922 else
923 solo_enc->mode = SOLO_ENC_MODE_CIF;
924
925 /* This does not change the encoder at all */
Hans Verkuila7eb9312013-03-18 08:41:13 -0300926 solo_enc->fmt = pix->pixelformat;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400927
Hans Verkuil69996872013-03-15 16:35:28 -0300928 /*
929 * More information is needed about these 'extended' types. As far
930 * as I can tell these are basically additional video streams with
931 * different MPEG encoding attributes that can run in parallel with
932 * the main stream. If so, then this should be implemented as a
933 * second video node. Abusing priv like this is certainly not the
934 * right approach.
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400935 if (pix->priv)
Hans Verkuila7eb9312013-03-18 08:41:13 -0300936 solo_enc->type = SOLO_ENC_TYPE_EXT;
Hans Verkuil69996872013-03-15 16:35:28 -0300937 */
Ismael Lucenocdcfe402013-04-12 18:28:33 -0300938 solo_update_mode(solo_enc);
Hans Verkuildcae5da2013-03-25 05:35:17 -0300939 return 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400940}
941
942static int solo_enc_get_fmt_cap(struct file *file, void *priv,
943 struct v4l2_format *f)
944{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300945 struct solo_enc_dev *solo_enc = video_drvdata(file);
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400946 struct v4l2_pix_format *pix = &f->fmt.pix;
947
948 pix->width = solo_enc->width;
949 pix->height = solo_enc->height;
Hans Verkuila7eb9312013-03-18 08:41:13 -0300950 pix->pixelformat = solo_enc->fmt;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400951 pix->field = solo_enc->interlaced ? V4L2_FIELD_INTERLACED :
952 V4L2_FIELD_NONE;
953 pix->sizeimage = FRAME_BUF_SIZE;
954 pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
Hans Verkuil016afda2013-03-12 18:43:21 -0300955 pix->priv = 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400956
957 return 0;
958}
959
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300960static int solo_enc_g_std(struct file *file, void *priv, v4l2_std_id *i)
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400961{
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300962 struct solo_enc_dev *solo_enc = video_drvdata(file);
963 struct solo_dev *solo_dev = solo_enc->solo_dev;
964
965 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
966 *i = V4L2_STD_NTSC_M;
967 else
968 *i = V4L2_STD_PAL;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400969 return 0;
970}
971
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300972static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id std)
973{
974 struct solo_enc_dev *solo_enc = video_drvdata(file);
975
Hans Verkuil429df502014-01-13 06:58:12 -0300976 return solo_set_video_type(solo_enc->solo_dev, std & V4L2_STD_625_50);
Hans Verkuil4c211ed2013-03-15 12:53:17 -0300977}
978
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400979static int solo_enum_framesizes(struct file *file, void *priv,
980 struct v4l2_frmsizeenum *fsize)
981{
Hans Verkuila7eb9312013-03-18 08:41:13 -0300982 struct solo_enc_dev *solo_enc = video_drvdata(file);
983 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400984
Ismael Luceno16af6902013-04-18 10:56:35 -0300985 if (solo_valid_pixfmt(fsize->pixel_format, solo_dev->type))
Ben Collinsfaa4fd22010-06-17 13:27:26 -0400986 return -EINVAL;
987
988 switch (fsize->index) {
989 case 0:
990 fsize->discrete.width = solo_dev->video_hsize >> 1;
991 fsize->discrete.height = solo_dev->video_vsize;
992 break;
993 case 1:
994 fsize->discrete.width = solo_dev->video_hsize;
995 fsize->discrete.height = solo_dev->video_vsize << 1;
996 break;
997 default:
998 return -EINVAL;
999 }
1000
1001 fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1002
1003 return 0;
1004}
1005
1006static int solo_enum_frameintervals(struct file *file, void *priv,
1007 struct v4l2_frmivalenum *fintv)
1008{
Hans Verkuila7eb9312013-03-18 08:41:13 -03001009 struct solo_enc_dev *solo_enc = video_drvdata(file);
1010 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001011
Ismael Luceno16af6902013-04-18 10:56:35 -03001012 if (solo_valid_pixfmt(fintv->pixel_format, solo_dev->type))
Hans Verkuil016afda2013-03-12 18:43:21 -03001013 return -EINVAL;
1014 if (fintv->index)
1015 return -EINVAL;
1016 if ((fintv->width != solo_dev->video_hsize >> 1 ||
1017 fintv->height != solo_dev->video_vsize) &&
1018 (fintv->width != solo_dev->video_hsize ||
1019 fintv->height != solo_dev->video_vsize << 1))
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001020 return -EINVAL;
1021
1022 fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE;
1023
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001024 fintv->stepwise.min.numerator = 1;
Hans Verkuil016afda2013-03-12 18:43:21 -03001025 fintv->stepwise.min.denominator = solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001026
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001027 fintv->stepwise.max.numerator = 15;
Hans Verkuil016afda2013-03-12 18:43:21 -03001028 fintv->stepwise.max.denominator = solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001029
1030 fintv->stepwise.step.numerator = 1;
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001031 fintv->stepwise.step.denominator = solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001032
1033 return 0;
1034}
1035
1036static int solo_g_parm(struct file *file, void *priv,
1037 struct v4l2_streamparm *sp)
1038{
Hans Verkuila7eb9312013-03-18 08:41:13 -03001039 struct solo_enc_dev *solo_enc = video_drvdata(file);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001040 struct v4l2_captureparm *cp = &sp->parm.capture;
1041
1042 cp->capability = V4L2_CAP_TIMEPERFRAME;
1043 cp->timeperframe.numerator = solo_enc->interval;
Ismael Luceno88107672013-05-03 15:54:57 -03001044 cp->timeperframe.denominator = solo_enc->solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001045 cp->capturemode = 0;
1046 /* XXX: Shouldn't we be able to get/set this from videobuf? */
1047 cp->readbuffers = 2;
1048
Ben Collinsf62de9b2010-11-04 22:51:17 -04001049 return 0;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001050}
1051
Ismael Luceno88107672013-05-03 15:54:57 -03001052static inline int calc_interval(u8 fps, u32 n, u32 d)
1053{
1054 if (!n || !d)
1055 return 1;
1056 if (d == fps)
1057 return n;
1058 n *= fps;
1059 return min(15U, n / d + (n % d >= (fps >> 1)));
1060}
1061
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001062static int solo_s_parm(struct file *file, void *priv,
1063 struct v4l2_streamparm *sp)
1064{
Hans Verkuila7eb9312013-03-18 08:41:13 -03001065 struct solo_enc_dev *solo_enc = video_drvdata(file);
Ismael Luceno88107672013-05-03 15:54:57 -03001066 struct v4l2_fract *t = &sp->parm.capture.timeperframe;
1067 u8 fps = solo_enc->solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001068
Hans Verkuil382c31a2013-03-15 12:04:14 -03001069 if (vb2_is_streaming(&solo_enc->vidq))
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001070 return -EBUSY;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001071
Ismael Luceno88107672013-05-03 15:54:57 -03001072 solo_enc->interval = calc_interval(fps, t->numerator, t->denominator);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001073 solo_update_mode(solo_enc);
Ismael Luceno88107672013-05-03 15:54:57 -03001074 return solo_g_parm(file, priv, sp);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001075}
1076
Hans Verkuilc813bd32013-03-25 05:38:14 -03001077static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001078{
Hans Verkuilc813bd32013-03-25 05:38:14 -03001079 struct solo_enc_dev *solo_enc =
1080 container_of(ctrl->handler, struct solo_enc_dev, hdl);
Krzysztof Hałasadecebab2011-02-11 13:38:20 +01001081 struct solo_dev *solo_dev = solo_enc->solo_dev;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001082 int err;
1083
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001084 switch (ctrl->id) {
1085 case V4L2_CID_BRIGHTNESS:
1086 case V4L2_CID_CONTRAST:
1087 case V4L2_CID_SATURATION:
1088 case V4L2_CID_HUE:
1089 case V4L2_CID_SHARPNESS:
1090 return tw28_set_ctrl_val(solo_dev, ctrl->id, solo_enc->ch,
Hans Verkuilc813bd32013-03-25 05:38:14 -03001091 ctrl->val);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001092 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
Hans Verkuilc813bd32013-03-25 05:38:14 -03001093 solo_enc->gop = ctrl->val;
Andrey Utkin63e9b452014-07-08 12:23:33 -03001094 solo_reg_write(solo_dev, SOLO_VE_CH_GOP(solo_enc->ch), solo_enc->gop);
1095 solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(solo_enc->ch), solo_enc->gop);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001096 return 0;
Andrey Utkin56981112014-07-08 12:23:32 -03001097 case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
1098 solo_enc->qp = ctrl->val;
Andrey Utkin63e9b452014-07-08 12:23:33 -03001099 solo_reg_write(solo_dev, SOLO_VE_CH_QP(solo_enc->ch), solo_enc->qp);
1100 solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(solo_enc->ch), solo_enc->qp);
Andrey Utkin56981112014-07-08 12:23:32 -03001101 return 0;
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001102 case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD:
1103 solo_enc->motion_thresh = ctrl->val << 8;
Hans Verkuilf5df0b72013-03-18 08:43:14 -03001104 if (!solo_enc->motion_global || !solo_enc->motion_enabled)
1105 return 0;
Aybuke Ozdemirfa917832014-03-13 02:20:20 +02001106 return solo_set_motion_threshold(solo_dev, solo_enc->ch,
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001107 solo_enc->motion_thresh);
1108 case V4L2_CID_DETECT_MD_MODE:
1109 solo_enc->motion_global = ctrl->val == V4L2_DETECT_MD_MODE_GLOBAL;
1110 solo_enc->motion_enabled = ctrl->val > V4L2_DETECT_MD_MODE_DISABLED;
Hans Verkuilf5df0b72013-03-18 08:43:14 -03001111 if (ctrl->val) {
1112 if (solo_enc->motion_global)
Hans Verkuil0a128302014-07-25 08:19:54 -03001113 err = solo_set_motion_threshold(solo_dev, solo_enc->ch,
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001114 solo_enc->motion_thresh);
Hans Verkuilf5df0b72013-03-18 08:43:14 -03001115 else
Hans Verkuil0a128302014-07-25 08:19:54 -03001116 err = solo_set_motion_block(solo_dev, solo_enc->ch,
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001117 solo_enc->md_thresholds->p_cur.p_u16);
Hans Verkuil0a128302014-07-25 08:19:54 -03001118 if (err)
1119 return err;
Hans Verkuildcae5da2013-03-25 05:35:17 -03001120 }
Hans Verkuilc813bd32013-03-25 05:38:14 -03001121 solo_motion_toggle(solo_enc, ctrl->val);
1122 return 0;
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001123 case V4L2_CID_DETECT_MD_THRESHOLD_GRID:
1124 if (solo_enc->motion_enabled && !solo_enc->motion_global)
1125 return solo_set_motion_block(solo_dev, solo_enc->ch,
1126 solo_enc->md_thresholds->p_new.p_u16);
1127 break;
Hans Verkuilc813bd32013-03-25 05:38:14 -03001128 case V4L2_CID_OSD_TEXT:
Hans Verkuil2a9ec372014-04-27 03:38:13 -03001129 strcpy(solo_enc->osd_text, ctrl->p_new.p_char);
Hans Verkuil0a128302014-07-25 08:19:54 -03001130 return solo_osd_print(solo_enc);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001131 default:
1132 return -EINVAL;
1133 }
1134
1135 return 0;
1136}
1137
Hans Verkuil316d9e82014-01-27 11:16:05 -03001138static int solo_subscribe_event(struct v4l2_fh *fh,
1139 const struct v4l2_event_subscription *sub)
1140{
1141
1142 switch (sub->type) {
1143 case V4L2_EVENT_CTRL:
1144 return v4l2_ctrl_subscribe_event(fh, sub);
1145 case V4L2_EVENT_MOTION_DET:
1146 /* Allow for up to 30 events (1 second for NTSC) to be
1147 * stored. */
1148 return v4l2_event_subscribe(fh, sub, 30, NULL);
1149 }
1150 return -EINVAL;
1151}
1152
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001153static const struct v4l2_file_operations solo_enc_fops = {
1154 .owner = THIS_MODULE,
Hans Verkuil382c31a2013-03-15 12:04:14 -03001155 .open = v4l2_fh_open,
1156 .release = vb2_fop_release,
1157 .read = vb2_fop_read,
1158 .poll = vb2_fop_poll,
1159 .mmap = vb2_fop_mmap,
1160 .unlocked_ioctl = video_ioctl2,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001161};
1162
1163static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = {
1164 .vidioc_querycap = solo_enc_querycap,
1165 .vidioc_s_std = solo_enc_s_std,
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001166 .vidioc_g_std = solo_enc_g_std,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001167 /* Input callbacks */
1168 .vidioc_enum_input = solo_enc_enum_input,
1169 .vidioc_s_input = solo_enc_set_input,
1170 .vidioc_g_input = solo_enc_get_input,
1171 /* Video capture format callbacks */
1172 .vidioc_enum_fmt_vid_cap = solo_enc_enum_fmt_cap,
1173 .vidioc_try_fmt_vid_cap = solo_enc_try_fmt_cap,
1174 .vidioc_s_fmt_vid_cap = solo_enc_set_fmt_cap,
1175 .vidioc_g_fmt_vid_cap = solo_enc_get_fmt_cap,
1176 /* Streaming I/O */
Hans Verkuil382c31a2013-03-15 12:04:14 -03001177 .vidioc_reqbufs = vb2_ioctl_reqbufs,
1178 .vidioc_querybuf = vb2_ioctl_querybuf,
1179 .vidioc_qbuf = vb2_ioctl_qbuf,
1180 .vidioc_dqbuf = vb2_ioctl_dqbuf,
1181 .vidioc_streamon = vb2_ioctl_streamon,
1182 .vidioc_streamoff = vb2_ioctl_streamoff,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001183 /* Frame size and interval */
1184 .vidioc_enum_framesizes = solo_enum_framesizes,
1185 .vidioc_enum_frameintervals = solo_enum_frameintervals,
1186 /* Video capture parameters */
1187 .vidioc_s_parm = solo_s_parm,
1188 .vidioc_g_parm = solo_g_parm,
Hans Verkuil94160492013-03-12 18:47:03 -03001189 /* Logging and events */
1190 .vidioc_log_status = v4l2_ctrl_log_status,
Hans Verkuil316d9e82014-01-27 11:16:05 -03001191 .vidioc_subscribe_event = solo_subscribe_event,
Hans Verkuil94160492013-03-12 18:47:03 -03001192 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001193};
1194
Hans Verkuildcae5da2013-03-25 05:35:17 -03001195static const struct video_device solo_enc_template = {
Krzysztof Hałasadecebab2011-02-11 13:38:20 +01001196 .name = SOLO6X10_NAME,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001197 .fops = &solo_enc_fops,
1198 .ioctl_ops = &solo_enc_ioctl_ops,
1199 .minor = -1,
1200 .release = video_device_release,
Hans Verkuil4c211ed2013-03-15 12:53:17 -03001201 .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL,
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001202};
1203
Hans Verkuilc813bd32013-03-25 05:38:14 -03001204static const struct v4l2_ctrl_ops solo_ctrl_ops = {
1205 .s_ctrl = solo_s_ctrl,
1206};
1207
Hans Verkuilc813bd32013-03-25 05:38:14 -03001208static const struct v4l2_ctrl_config solo_osd_text_ctrl = {
1209 .ops = &solo_ctrl_ops,
1210 .id = V4L2_CID_OSD_TEXT,
1211 .name = "OSD Text",
1212 .type = V4L2_CTRL_TYPE_STRING,
1213 .max = OSD_TEXT_MAX,
1214 .step = 1,
1215};
1216
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001217/* Motion Detection Threshold matrix */
1218static const struct v4l2_ctrl_config solo_md_thresholds = {
1219 .ops = &solo_ctrl_ops,
1220 .id = V4L2_CID_DETECT_MD_THRESHOLD_GRID,
1221 .dims = { SOLO_MOTION_SZ, SOLO_MOTION_SZ },
1222 .def = SOLO_DEF_MOT_THRESH,
1223 .max = 65535,
1224 .step = 1,
1225};
1226
Hans Verkuildcae5da2013-03-25 05:35:17 -03001227static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
1228 u8 ch, unsigned nr)
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001229{
1230 struct solo_enc_dev *solo_enc;
Hans Verkuilc813bd32013-03-25 05:38:14 -03001231 struct v4l2_ctrl_handler *hdl;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001232 int ret;
1233
1234 solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL);
1235 if (!solo_enc)
1236 return ERR_PTR(-ENOMEM);
1237
Hans Verkuilc813bd32013-03-25 05:38:14 -03001238 hdl = &solo_enc->hdl;
1239 v4l2_ctrl_handler_init(hdl, 10);
1240 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1241 V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
1242 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1243 V4L2_CID_CONTRAST, 0, 255, 1, 128);
1244 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1245 V4L2_CID_SATURATION, 0, 255, 1, 128);
1246 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1247 V4L2_CID_HUE, 0, 255, 1, 128);
1248 if (tw28_has_sharpness(solo_dev, ch))
1249 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1250 V4L2_CID_SHARPNESS, 0, 15, 1, 0);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001251 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1252 V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 255, 1, solo_dev->fps);
Andrey Utkin56981112014-07-08 12:23:32 -03001253 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1254 V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 31, 1, SOLO_DEFAULT_QP);
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001255 v4l2_ctrl_new_std_menu(hdl, &solo_ctrl_ops,
1256 V4L2_CID_DETECT_MD_MODE,
1257 V4L2_DETECT_MD_MODE_THRESHOLD_GRID, 0,
1258 V4L2_DETECT_MD_MODE_DISABLED);
1259 v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
1260 V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD, 0, 0xff, 1,
1261 SOLO_DEF_MOT_THRESH >> 8);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001262 v4l2_ctrl_new_custom(hdl, &solo_osd_text_ctrl, NULL);
Hans Verkuil4063a3c2014-06-10 07:37:30 -03001263 solo_enc->md_thresholds =
1264 v4l2_ctrl_new_custom(hdl, &solo_md_thresholds, NULL);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001265 if (hdl->error) {
1266 ret = hdl->error;
Hans Verkuila7eb9312013-03-18 08:41:13 -03001267 goto hdl_free;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001268 }
1269
1270 solo_enc->solo_dev = solo_dev;
1271 solo_enc->ch = ch;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001272 mutex_init(&solo_enc->lock);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001273 spin_lock_init(&solo_enc->av_lock);
1274 INIT_LIST_HEAD(&solo_enc->vidq_active);
Ismael Luceno16af6902013-04-18 10:56:35 -03001275 solo_enc->fmt = (solo_dev->type == SOLO_DEV_6010) ?
1276 V4L2_PIX_FMT_MPEG4 : V4L2_PIX_FMT_H264;
Hans Verkuila7eb9312013-03-18 08:41:13 -03001277 solo_enc->type = SOLO_ENC_TYPE_STD;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001278
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001279 solo_enc->qp = SOLO_DEFAULT_QP;
Ben Collinsf62de9b2010-11-04 22:51:17 -04001280 solo_enc->gop = solo_dev->fps;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001281 solo_enc->interval = 1;
1282 solo_enc->mode = SOLO_ENC_MODE_CIF;
Hans Verkuilf5df0b72013-03-18 08:43:14 -03001283 solo_enc->motion_global = true;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001284 solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001285 solo_enc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1286 solo_enc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
1287 solo_enc->vidq.ops = &solo_enc_video_qops;
1288 solo_enc->vidq.mem_ops = &vb2_dma_sg_memops;
1289 solo_enc->vidq.drv_priv = solo_enc;
Mel Gormand0164ad2015-11-06 16:28:21 -08001290 solo_enc->vidq.gfp_flags = __GFP_DMA32 | __GFP_KSWAPD_RECLAIM;
Sakari Ailusade48682014-02-25 19:12:19 -03001291 solo_enc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001292 solo_enc->vidq.buf_struct_size = sizeof(struct solo_vb2_buf);
1293 solo_enc->vidq.lock = &solo_enc->lock;
Hans Verkuil2bc46b32016-02-15 12:37:15 -02001294 solo_enc->vidq.dev = &solo_dev->pdev->dev;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001295 ret = vb2_queue_init(&solo_enc->vidq);
1296 if (ret)
1297 goto hdl_free;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001298 solo_update_mode(solo_enc);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001299
Hans Verkuila7eb9312013-03-18 08:41:13 -03001300 spin_lock_init(&solo_enc->motion_lock);
1301
Hans Verkuildcae5da2013-03-25 05:35:17 -03001302 /* Initialize this per encoder */
1303 solo_enc->jpeg_len = sizeof(jpeg_header);
1304 memcpy(solo_enc->jpeg_header, jpeg_header, solo_enc->jpeg_len);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001305
Hans Verkuila7eb9312013-03-18 08:41:13 -03001306 solo_enc->desc_nelts = 32;
1307 solo_enc->desc_items = pci_alloc_consistent(solo_dev->pdev,
1308 sizeof(struct solo_p2m_desc) *
Aybuke Ozdemirfa917832014-03-13 02:20:20 +02001309 solo_enc->desc_nelts,
1310 &solo_enc->desc_dma);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001311 ret = -ENOMEM;
1312 if (solo_enc->desc_items == NULL)
1313 goto hdl_free;
1314
Hans Verkuila7eb9312013-03-18 08:41:13 -03001315 solo_enc->vfd = video_device_alloc();
1316 if (!solo_enc->vfd)
1317 goto pci_free;
1318
1319 *solo_enc->vfd = solo_enc_template;
1320 solo_enc->vfd->v4l2_dev = &solo_dev->v4l2_dev;
1321 solo_enc->vfd->ctrl_handler = hdl;
Hans Verkuil382c31a2013-03-15 12:04:14 -03001322 solo_enc->vfd->queue = &solo_enc->vidq;
1323 solo_enc->vfd->lock = &solo_enc->lock;
Hans Verkuila7eb9312013-03-18 08:41:13 -03001324 video_set_drvdata(solo_enc->vfd, solo_enc);
1325 ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr);
1326 if (ret < 0)
1327 goto vdev_release;
1328
1329 snprintf(solo_enc->vfd->name, sizeof(solo_enc->vfd->name),
1330 "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num,
1331 solo_enc->vfd->num);
1332
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001333 return solo_enc;
Hans Verkuila7eb9312013-03-18 08:41:13 -03001334
1335vdev_release:
1336 video_device_release(solo_enc->vfd);
1337pci_free:
1338 pci_free_consistent(solo_enc->solo_dev->pdev,
1339 sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts,
1340 solo_enc->desc_items, solo_enc->desc_dma);
1341hdl_free:
1342 v4l2_ctrl_handler_free(hdl);
1343 kfree(solo_enc);
1344 return ERR_PTR(ret);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001345}
1346
1347static void solo_enc_free(struct solo_enc_dev *solo_enc)
1348{
1349 if (solo_enc == NULL)
1350 return;
1351
Andrey Utkin0cb2df32014-10-29 13:03:52 -03001352 pci_free_consistent(solo_enc->solo_dev->pdev,
1353 sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts,
1354 solo_enc->desc_items, solo_enc->desc_dma);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001355 video_unregister_device(solo_enc->vfd);
Hans Verkuilc813bd32013-03-25 05:38:14 -03001356 v4l2_ctrl_handler_free(&solo_enc->hdl);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001357 kfree(solo_enc);
1358}
1359
Hans Verkuildcae5da2013-03-25 05:35:17 -03001360int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001361{
1362 int i;
1363
Hans Verkuildcae5da2013-03-25 05:35:17 -03001364 init_waitqueue_head(&solo_dev->ring_thread_wait);
1365
Krzysztof Hałasa4a61ad32013-09-12 08:28:07 -03001366 solo_dev->vh_size = sizeof(vop_header);
Hans Verkuildcae5da2013-03-25 05:35:17 -03001367 solo_dev->vh_buf = pci_alloc_consistent(solo_dev->pdev,
1368 solo_dev->vh_size,
1369 &solo_dev->vh_dma);
1370 if (solo_dev->vh_buf == NULL)
1371 return -ENOMEM;
1372
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001373 for (i = 0; i < solo_dev->nr_chans; i++) {
Hans Verkuildcae5da2013-03-25 05:35:17 -03001374 solo_dev->v4l2_enc[i] = solo_enc_alloc(solo_dev, i, nr);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001375 if (IS_ERR(solo_dev->v4l2_enc[i]))
1376 break;
1377 }
1378
1379 if (i != solo_dev->nr_chans) {
1380 int ret = PTR_ERR(solo_dev->v4l2_enc[i]);
Hans Verkuil1c6f3db2014-07-17 20:40:22 -03001381
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001382 while (i--)
1383 solo_enc_free(solo_dev->v4l2_enc[i]);
Hans Verkuildcae5da2013-03-25 05:35:17 -03001384 pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
1385 solo_dev->vh_buf, solo_dev->vh_dma);
Hans Verkuila7eb9312013-03-18 08:41:13 -03001386 solo_dev->vh_buf = NULL;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001387 return ret;
1388 }
1389
Hans Verkuildcae5da2013-03-25 05:35:17 -03001390 if (solo_dev->type == SOLO_DEV_6010)
1391 solo_dev->enc_bw_remain = solo_dev->fps * 4 * 4;
1392 else
1393 solo_dev->enc_bw_remain = solo_dev->fps * 4 * 5;
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001394
1395 dev_info(&solo_dev->pdev->dev, "Encoders as /dev/video%d-%d\n",
1396 solo_dev->v4l2_enc[0]->vfd->num,
1397 solo_dev->v4l2_enc[solo_dev->nr_chans - 1]->vfd->num);
1398
Andrey Utkin670390c2014-10-29 13:03:53 -03001399 return solo_ring_start(solo_dev);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001400}
1401
Krzysztof Hałasadecebab2011-02-11 13:38:20 +01001402void solo_enc_v4l2_exit(struct solo_dev *solo_dev)
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001403{
1404 int i;
1405
Andrey Utkin670390c2014-10-29 13:03:53 -03001406 solo_ring_stop(solo_dev);
1407
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001408 for (i = 0; i < solo_dev->nr_chans; i++)
1409 solo_enc_free(solo_dev->v4l2_enc[i]);
Hans Verkuildcae5da2013-03-25 05:35:17 -03001410
Hans Verkuila7eb9312013-03-18 08:41:13 -03001411 if (solo_dev->vh_buf)
1412 pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
Hans Verkuildcae5da2013-03-25 05:35:17 -03001413 solo_dev->vh_buf, solo_dev->vh_dma);
Ben Collinsfaa4fd22010-06-17 13:27:26 -04001414}