1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
|
/*
* TW5864 driver - common header file
*
* Copyright (C) 2016 Bluecherry, LLC <maintainers@bluecherrydvr.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/pci.h>
#include <linux/videodev2.h>
#include <linux/notifier.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/videobuf2-dma-sg.h>
#include "tw5864-reg.h"
#define PCI_DEVICE_ID_TECHWELL_5864 0x5864
#define TW5864_NORMS V4L2_STD_ALL
/* ----------------------------------------------------------- */
/* card configuration */
#define TW5864_INPUTS 4
/* The TW5864 uses 192 (16x12) detection cells in full screen for motion
* detection. Each detection cell is composed of 44 pixels and 20 lines for
* NTSC and 24 lines for PAL.
*/
#define MD_CELLS_HOR 16
#define MD_CELLS_VERT 12
#define MD_CELLS (MD_CELLS_HOR * MD_CELLS_VERT)
#define H264_VLC_BUF_SIZE 0x80000
#define H264_MV_BUF_SIZE 0x2000 /* device writes 5396 bytes */
#define QP_VALUE 28
#define MAX_GOP_SIZE 255
#define GOP_SIZE MAX_GOP_SIZE
enum resolution {
D1 = 1,
HD1 = 2, /* half d1 - 360x(240|288) */
CIF = 3,
QCIF = 4,
};
/* ----------------------------------------------------------- */
/* device / file handle status */
struct tw5864_dev; /* forward delclaration */
/* buffer for one video/vbi/ts frame */
struct tw5864_buf {
struct vb2_v4l2_buffer vb;
struct list_head list;
unsigned int size;
};
struct tw5864_dma_buf {
void *addr;
dma_addr_t dma_addr;
};
enum tw5864_vid_std {
STD_NTSC = 0, /* NTSC (M) */
STD_PAL = 1, /* PAL (B, D, G, H, I) */
STD_SECAM = 2, /* SECAM */
STD_NTSC443 = 3, /* NTSC4.43 */
STD_PAL_M = 4, /* PAL (M) */
STD_PAL_CN = 5, /* PAL (CN) */
STD_PAL_60 = 6, /* PAL 60 */
STD_INVALID = 7,
STD_AUTO = 7,
};
struct tw5864_input {
int nr; /* input number */
struct tw5864_dev *root;
struct mutex lock; /* used for vidq and vdev */
spinlock_t slock; /* used for sync between ISR, tasklet & V4L2 API */
struct video_device vdev;
struct v4l2_ctrl_handler hdl;
struct vb2_queue vidq;
struct list_head active;
enum resolution resolution;
unsigned int width, height;
unsigned int frame_seqno;
unsigned int frame_gop_seqno;
unsigned int h264_idr_pic_id;
int enabled;
enum tw5864_vid_std std;
v4l2_std_id v4l2_std;
int tail_nb_bits;
u8 tail;
u8 *buf_cur_ptr;
int buf_cur_space_left;
u32 reg_interlacing;
u32 reg_vlc;
u32 reg_dsp_codec;
u32 reg_dsp;
u32 reg_emu;
u32 reg_dsp_qp;
u32 reg_dsp_ref_mvp_lambda;
u32 reg_dsp_i4x4_weight;
u32 buf_id;
struct tw5864_buf *vb;
struct v4l2_ctrl *md_threshold_grid_ctrl;
u16 md_threshold_grid_values[12 * 16];
int qp;
int gop;
/*
* In (1/MAX_FPS) units.
* For max FPS (default), set to 1.
* For 1 FPS, set to e.g. 32.
*/
int frame_interval;
unsigned long new_frame_deadline;
};
struct tw5864_h264_frame {
struct tw5864_dma_buf vlc;
struct tw5864_dma_buf mv;
int vlc_len;
u32 checksum;
struct tw5864_input *input;
u64 timestamp;
unsigned int seqno;
unsigned int gop_seqno;
};
/* global device status */
struct tw5864_dev {
spinlock_t slock; /* used for sync between ISR, tasklet & V4L2 API */
struct v4l2_device v4l2_dev;
struct tw5864_input inputs[TW5864_INPUTS];
#define H264_BUF_CNT 4
struct tw5864_h264_frame h264_buf[H264_BUF_CNT];
int h264_buf_r_index;
int h264_buf_w_index;
struct tasklet_struct tasklet;
int encoder_busy;
/* Input number to check next for ready raw picture (in RR fashion) */
int next_input;
/* pci i/o */
char name[64];
struct pci_dev *pci;
void __iomem *mmio;
u32 irqmask;
};
#define tw_readl(reg) readl(dev->mmio + reg)
#define tw_mask_readl(reg, mask) \
(tw_readl(reg) & (mask))
#define tw_mask_shift_readl(reg, mask, shift) \
(tw_mask_readl((reg), ((mask) << (shift))) >> (shift))
#define tw_writel(reg, value) writel((value), dev->mmio + reg)
#define tw_mask_writel(reg, mask, value) \
tw_writel(reg, (tw_readl(reg) & ~(mask)) | ((value) & (mask)))
#define tw_mask_shift_writel(reg, mask, shift, value) \
tw_mask_writel((reg), ((mask) << (shift)), ((value) << (shift)))
#define tw_setl(reg, bit) tw_writel((reg), tw_readl(reg) | (bit))
#define tw_clearl(reg, bit) tw_writel((reg), tw_readl(reg) & ~(bit))
u8 tw5864_indir_readb(struct tw5864_dev *dev, u16 addr);
#define tw_indir_readb(addr) tw5864_indir_readb(dev, addr)
void tw5864_indir_writeb(struct tw5864_dev *dev, u16 addr, u8 data);
#define tw_indir_writeb(addr, data) tw5864_indir_writeb(dev, addr, data)
void tw5864_irqmask_apply(struct tw5864_dev *dev);
int tw5864_video_init(struct tw5864_dev *dev, int *video_nr);
void tw5864_video_fini(struct tw5864_dev *dev);
void tw5864_prepare_frame_headers(struct tw5864_input *input);
void tw5864_h264_put_stream_header(u8 **buf, size_t *space_left, int qp,
int width, int height);
void tw5864_h264_put_slice_header(u8 **buf, size_t *space_left,
unsigned int idr_pic_id,
unsigned int frame_gop_seqno,
int *tail_nb_bits, u8 *tail);
void tw5864_request_encoded_frame(struct tw5864_input *input);
|