1 /******************************************************************************
2 /
3 / File: Capture.cpp
4 /
5 / Description: ATI Radeon Capture Unit interface.
6 /
7 / Copyright 2001, Carlos Hasan
8 /
9 / TK: something about synchronization: I removed all the FIFO wait
10 / functions as they aren't thread-safe and AFAIK not needed as
11 / only 2D/3D register accesses are buffered
12 /
13 *******************************************************************************/
14
15 #include <Debug.h>
16 #include "Capture.h"
17
CCapture(CRadeon & radeon)18 CCapture::CCapture(CRadeon & radeon)
19 : fRadeon(radeon),
20 fMode(C_RADEON_CAPTURE_FIELD_SINGLE),
21 fFormat(C_RADEON_CAPTURE_CCIR656),
22 fOffset0(0),
23 fOffset1(0),
24 fVBIOffset0(0),
25 fVBIOffset1(0),
26 fSize(0),
27 fVBISize(0),
28 fPitch(0),
29 fClip(),
30 fVBIClip()
31 {
32 PRINT(("CCapture::CCapture()\n"));
33 }
34
~CCapture()35 CCapture::~CCapture()
36 {
37 PRINT(("CCapture::~CCapture()\n"));
38 }
39
InitCheck() const40 status_t CCapture::InitCheck() const
41 {
42 return fRadeon.InitCheck();
43 }
44
SetBuffer(capture_stream_format format,capture_buffer_mode mode,int offset0,int offset1,int size,int pitch)45 void CCapture::SetBuffer(capture_stream_format format, capture_buffer_mode mode,
46 int offset0, int offset1, int size, int pitch)
47 {
48 PRINT(("CCapture::SetBuffer(%s, %s, 0x%08x, 0x%08x, 0x%08x, %d)\n",
49 "BROOKTREE\0CCIR656\0\0\0ZVIDEO\0\0\0\0VIP"+10*format,
50 "FIELD-SINGLE\0FIELD-DOUBLE\0BOB-SINGLE\0\0\0"
51 "BOB-DOUBLE\0\0\0WEAVE-SINGLE\0WEAVE-DOUBLE"+13*mode,
52 offset0, offset1, size, pitch));
53
54 fMode = mode;
55 fFormat = format;
56 fOffset0 = offset0 + fRadeon.VirtualMemoryBase();
57 fOffset1 = offset1 + fRadeon.VirtualMemoryBase();
58 fSize = size;
59 fPitch = pitch;
60 }
61
SetClip(int left,int top,int right,int bottom)62 void CCapture::SetClip(int left, int top, int right, int bottom)
63 {
64 PRINT(("CCapture::SetClip(%d, %d, %d, %d)\n",
65 left, top, right, bottom));
66
67 fClip.SetTo(left, top, right, bottom);
68 }
69
SetVBIBuffer(int offset0,int offset1,int size)70 void CCapture::SetVBIBuffer(int offset0, int offset1, int size)
71 {
72 PRINT(("CCapture::SetVBIBuffer(0x%08x, 0x%08x, %d)\n", offset0, offset1, size));
73
74 fVBIOffset0 = offset0 + fRadeon.VirtualMemoryBase();
75 fVBIOffset1 = offset1 + fRadeon.VirtualMemoryBase();
76 fVBISize = size;
77 }
78
SetVBIClip(int left,int top,int right,int bottom)79 void CCapture::SetVBIClip(int left, int top, int right, int bottom)
80 {
81 PRINT(("CCapture::SetVBIClip(%d, %d, %d, %d)\n",
82 left, top, right, bottom));
83
84 fVBIClip.SetTo(left, top, right, bottom);
85 }
86
Start(bool vbi)87 void CCapture::Start(bool vbi)
88 {
89 PRINT(("CCapture::Start(%d)\n", vbi));
90
91 // initially the capture unit is disabled
92 //fRadeon.WaitForFifo(2);
93 SetRegister(C_RADEON_CAP0_TRIG_CNTL, C_RADEON_CAP0_TRIGGER_W_NO_ACTION);
94
95 // select buffer offset and pitch
96 //fRadeon.WaitForFifo(5);
97
98 switch (fMode) {
99 case C_RADEON_CAPTURE_FIELD_SINGLE:
100 /* capture single field, single buffer */
101 SetRegister(C_RADEON_CAP0_BUF0_OFFSET, fOffset0);
102 SetRegister(C_RADEON_CAP0_BUF_PITCH, fPitch << 1);
103 break;
104
105 case C_RADEON_CAPTURE_FIELD_DOUBLE:
106 /* capture single field, double buffer */
107 SetRegister(C_RADEON_CAP0_BUF0_OFFSET, fOffset0);
108 SetRegister(C_RADEON_CAP0_BUF1_OFFSET, fOffset1);
109 SetRegister(C_RADEON_CAP0_BUF_PITCH, fPitch << 1);
110 break;
111
112 case C_RADEON_CAPTURE_BOB_SINGLE:
113 /* capture interlaced frame, single buffer */
114 SetRegister(C_RADEON_CAP0_BUF0_OFFSET, fOffset0);
115 SetRegister(C_RADEON_CAP0_BUF0_EVEN_OFFSET, fOffset0 + fSize);
116 SetRegister(C_RADEON_CAP0_BUF_PITCH, fPitch << 1);
117 break;
118
119 case C_RADEON_CAPTURE_BOB_DOUBLE:
120 /* capture interlaced frame, double buffer */
121 SetRegister(C_RADEON_CAP0_BUF0_OFFSET, fOffset0);
122 SetRegister(C_RADEON_CAP0_BUF0_EVEN_OFFSET, fOffset0 + fSize);
123 SetRegister(C_RADEON_CAP0_BUF1_OFFSET, fOffset1);
124 SetRegister(C_RADEON_CAP0_BUF1_EVEN_OFFSET, fOffset1 + fSize);
125 SetRegister(C_RADEON_CAP0_BUF_PITCH, fPitch << 1);
126 break;
127
128 case C_RADEON_CAPTURE_WEAVE_SINGLE:
129 /* capture deinterlaced frame, single buffer */
130 SetRegister(C_RADEON_CAP0_BUF0_OFFSET, fOffset0);
131 SetRegister(C_RADEON_CAP0_BUF0_EVEN_OFFSET, fOffset0 + (fPitch << 1));
132 SetRegister(C_RADEON_CAP0_BUF_PITCH, fPitch << 2);
133 break;
134
135 case C_RADEON_CAPTURE_WEAVE_DOUBLE:
136 /* capture deinterlaced frame, double buffer */
137 SetRegister(C_RADEON_CAP0_BUF0_OFFSET, fOffset0);
138 SetRegister(C_RADEON_CAP0_BUF0_EVEN_OFFSET, fOffset0 + (fPitch << 1));
139 SetRegister(C_RADEON_CAP0_BUF1_OFFSET, fOffset1);
140 SetRegister(C_RADEON_CAP0_BUF1_EVEN_OFFSET, fOffset1 + (fPitch << 1));
141 SetRegister(C_RADEON_CAP0_BUF_PITCH, fPitch << 2);
142 break;
143 }
144
145 // select VBI buffer offset
146 //fRadeon.WaitForFifo(4);
147
148 // FIXME: change according to the buffering mode?
149 SetRegister(C_RADEON_CAP0_VBI0_OFFSET, fVBIOffset0);
150 SetRegister(C_RADEON_CAP0_VBI1_OFFSET, fVBIOffset0 + fVBISize);
151
152 SetRegister(C_RADEON_CAP0_VBI2_OFFSET, fVBIOffset1);
153 SetRegister(C_RADEON_CAP0_VBI3_OFFSET, fVBIOffset1 + fVBISize);
154
155 // select capture clipping window
156 //fRadeon.WaitForFifo(2);
157
158 SetRegister(C_RADEON_CAP0_H_WINDOW,
159 ((fClip.Left() << 1) & C_RADEON_CAP0_H_START) |
160 ((fClip.Width() << 17) & C_RADEON_CAP0_H_WIDTH));
161
162 SetRegister(C_RADEON_CAP0_V_WINDOW,
163 ((fClip.Top() << 0) & C_RADEON_CAP0_V_START) |
164 ((fClip.Bottom() << 16) & C_RADEON_CAP0_V_END));
165
166 // select VBI clipping window
167 //fRadeon.WaitForFifo(2);
168
169 SetRegister(C_RADEON_CAP0_VBI_H_WINDOW,
170 ((fVBIClip.Left() << 0) & C_RADEON_CAP0_VBI_H_START) |
171 ((fVBIClip.Width() << 16) & C_RADEON_CAP0_VBI_H_WIDTH));
172
173 SetRegister(C_RADEON_CAP0_VBI_V_WINDOW,
174 ((fVBIClip.Top() << 0) & C_RADEON_CAP0_VBI_V_START) |
175 ((fVBIClip.Bottom() << 16) & C_RADEON_CAP0_VBI_V_END));
176
177 // select buffer type, input mode, video format and buffering mode
178 //fRadeon.WaitForFifo(10);
179
180 switch (fMode) {
181 case C_RADEON_CAPTURE_FIELD_SINGLE:
182 case C_RADEON_CAPTURE_FIELD_DOUBLE:
183 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_BUF_TYPE, C_RADEON_CAP0_BUF_TYPE_FIELD);
184 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_ONESHOT_MODE, C_RADEON_CAP0_ONESHOT_MODE_FIELD);
185 break;
186
187 case C_RADEON_CAPTURE_BOB_SINGLE:
188 case C_RADEON_CAPTURE_BOB_DOUBLE:
189 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_BUF_TYPE, C_RADEON_CAP0_BUF_TYPE_ALTERNATING);
190 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_ONESHOT_MODE, C_RADEON_CAP0_ONESHOT_MODE_FIELD);
191 break;
192
193 case C_RADEON_CAPTURE_WEAVE_SINGLE:
194 case C_RADEON_CAPTURE_WEAVE_DOUBLE:
195 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_BUF_TYPE, C_RADEON_CAP0_BUF_TYPE_FRAME);
196 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_ONESHOT_MODE, C_RADEON_CAP0_ONESHOT_MODE_FRAME);
197 break;
198 }
199
200 switch (fMode) {
201 case C_RADEON_CAPTURE_FIELD_SINGLE:
202 case C_RADEON_CAPTURE_BOB_SINGLE:
203 case C_RADEON_CAPTURE_WEAVE_SINGLE:
204 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_BUF_MODE, C_RADEON_CAP0_BUF_MODE_SINGLE);
205 break;
206
207 case C_RADEON_CAPTURE_FIELD_DOUBLE:
208 case C_RADEON_CAPTURE_BOB_DOUBLE:
209 case C_RADEON_CAPTURE_WEAVE_DOUBLE:
210 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_BUF_MODE, C_RADEON_CAP0_BUF_MODE_DOUBLE);
211 break;
212 }
213
214 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_INPUT_MODE, C_RADEON_CAP0_INPUT_MODE_CONTINUOUS);
215 SetRegister(C_RADEON_CAP0_CONFIG,
216 C_RADEON_CAP0_VIDEO_IN_FORMAT | C_RADEON_CAP0_VIDEO_SIGNED_UV, C_RADEON_CAP0_VIDEO_IN_VYUY422);
217
218
219 // select stream format and port mode
220 //fRadeon.WaitForFifo(4);
221
222 switch (fFormat) {
223 case C_RADEON_CAPTURE_BROOKTREE:
224 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_STREAM_FORMAT, C_RADEON_CAP0_STREAM_BROOKTREE);
225 SetRegister(C_RADEON_CAP0_PORT_MODE_CNTL, C_RADEON_CAP0_PORT_WIDTH_8_BITS | C_RADEON_CAP0_PORT_LOWER_BYTE_USED);
226 break;
227 case C_RADEON_CAPTURE_CCIR656:
228 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_STREAM_FORMAT, C_RADEON_CAP0_STREAM_CCIR656);
229 SetRegister(C_RADEON_CAP0_PORT_MODE_CNTL, C_RADEON_CAP0_PORT_WIDTH_8_BITS | C_RADEON_CAP0_PORT_LOWER_BYTE_USED);
230 break;
231 case C_RADEON_CAPTURE_ZOOMVIDEO:
232 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_STREAM_FORMAT, C_RADEON_CAP0_STREAM_ZV);
233 SetRegister(C_RADEON_CAP0_PORT_MODE_CNTL, C_RADEON_CAP0_PORT_WIDTH_16_BITS | C_RADEON_CAP0_PORT_LOWER_BYTE_USED);
234 break;
235 case C_RADEON_CAPTURE_VIP:
236 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_STREAM_FORMAT, C_RADEON_CAP0_STREAM_VIP);
237 SetRegister(C_RADEON_CAP0_PORT_MODE_CNTL, C_RADEON_CAP0_PORT_WIDTH_16_BITS | C_RADEON_CAP0_PORT_LOWER_BYTE_USED);
238 break;
239 }
240
241 // set capture mirror mode, field sense, downscaler/decimator, enable 3:4 pull down
242 //fRadeon.WaitForFifo(16);
243 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_MIRROR_EN, 0);
244 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_ONESHOT_MIRROR_EN, 0);
245 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_START_FIELD, C_RADEON_CAP0_START_ODD_FIELD);
246 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_HORZ_DOWN, C_RADEON_CAP0_HORZ_DOWN_1X);
247 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_VERT_DOWN, C_RADEON_CAP0_VERT_DOWN_1X);
248 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_VBI_HORZ_DOWN, C_RADEON_CAP0_VBI_HORZ_DOWN_1X);
249 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_HDWNS_DEC, C_RADEON_CAP0_DECIMATOR);
250 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_SOFT_PULL_DOWN_EN, C_RADEON_CAP0_SOFT_PULL_DOWN_EN);
251
252 // prepare to enable capture
253 //fRadeon.WaitForFifo(14);
254
255 // disable test and debug modes
256 SetRegister(C_RADEON_TEST_DEBUG_CNTL, 0);
257 SetRegister(C_RADEON_CAP0_VIDEO_SYNC_TEST, 0);
258 SetRegister(C_RADEON_CAP0_DEBUG, C_RADEON_CAP0_V_SYNC);
259
260 // connect capture engine to AMC connector
261 SetRegister(C_RADEON_VIDEOMUX_CNTL, 1, 1);
262
263 // select capture engine clock source to PCLK
264 SetRegister(C_RADEON_FCP_CNTL, C_RADEON_FCP0_SRC_PCLK);
265
266 // enable capture unit
267 SetRegister(C_RADEON_CAP0_TRIG_CNTL,
268 C_RADEON_CAP0_TRIGGER_W_CAPTURE | C_RADEON_CAP0_EN);
269
270 // enable VBI capture
271 SetRegister(C_RADEON_CAP0_CONFIG, C_RADEON_CAP0_VBI_EN,
272 (vbi ? C_RADEON_CAP0_VBI_EN : 0));
273 }
274
Stop()275 void CCapture::Stop()
276 {
277 PRINT(("CCapture::Stop()\n"));
278
279 // disable capture unit
280 //fRadeon.WaitForFifo(4);
281
282 // disable capture unit
283 SetRegister(C_RADEON_CAP0_TRIG_CNTL, C_RADEON_CAP0_TRIGGER_W_NO_ACTION);
284
285 // disable the capture engine clock (set to ground)
286 fRadeon.SetRegister(C_RADEON_FCP_CNTL, C_RADEON_FCP0_SRC_GND);
287 }
288
SetInterrupts(bool enable)289 void CCapture::SetInterrupts(bool enable)
290 {
291 PRINT(("CCapture::SetInterrupts(%d)\n", enable));
292
293 fRadeon.SetRegister(C_RADEON_CAP_INT_CNTL,
294 C_RADEON_CAP0_BUF0_INT_EN | C_RADEON_CAP0_BUF0_EVEN_INT_EN |
295 C_RADEON_CAP0_BUF1_INT_EN | C_RADEON_CAP0_BUF1_EVEN_INT_EN |
296 C_RADEON_CAP0_VBI0_INT_EN | C_RADEON_CAP0_VBI1_INT_EN,
297 (enable ? C_RADEON_CAP0_BUF0_INT_EN | C_RADEON_CAP0_BUF0_EVEN_INT_EN |
298 C_RADEON_CAP0_BUF1_INT_EN | C_RADEON_CAP0_BUF1_EVEN_INT_EN |
299 C_RADEON_CAP0_VBI0_INT_EN | C_RADEON_CAP0_VBI1_INT_EN : 0));
300
301 // clear any stick interrupt
302 fRadeon.SetRegister(C_RADEON_CAP_INT_STATUS,
303 C_RADEON_CAP0_BUF0_INT_AK | C_RADEON_CAP0_BUF0_EVEN_INT_AK |
304 C_RADEON_CAP0_BUF1_INT_AK | C_RADEON_CAP0_BUF1_EVEN_INT_AK |
305 C_RADEON_CAP0_VBI0_INT_AK | C_RADEON_CAP0_VBI1_INT_AK);
306 }
307
WaitInterrupts(int * sequence,bigtime_t * when,bigtime_t timeout)308 int CCapture::WaitInterrupts(int * sequence, bigtime_t * when, bigtime_t timeout)
309 {
310 int mask;
311
312 if (fRadeon.WaitInterrupt(&mask, sequence, when, timeout) == B_OK) {
313 /*
314 int mask = fRadeon.Register(C_RADEON_CAP_INT_STATUS);
315
316 fRadeon.SetRegister(C_RADEON_CAP_INT_STATUS,
317 C_RADEON_CAP0_BUF0_INT_AK | C_RADEON_CAP0_BUF0_EVEN_INT_AK |
318 C_RADEON_CAP0_BUF1_INT_AK | C_RADEON_CAP0_BUF1_EVEN_INT_AK |
319 C_RADEON_CAP0_VBI0_INT_AK | C_RADEON_CAP0_VBI1_INT_AK);
320 */
321
322 return
323 ((mask & C_RADEON_CAP0_BUF0_INT) != 0 ? C_RADEON_CAPTURE_BUF0_INT : 0) |
324 ((mask & C_RADEON_CAP0_BUF1_INT) != 0 ? C_RADEON_CAPTURE_BUF1_INT : 0) |
325 ((mask & C_RADEON_CAP0_BUF0_EVEN_INT) != 0 ? C_RADEON_CAPTURE_BUF0_EVEN_INT : 0) |
326 ((mask & C_RADEON_CAP0_BUF1_EVEN_INT) != 0 ? C_RADEON_CAPTURE_BUF1_EVEN_INT : 0) |
327 ((mask & C_RADEON_CAP0_VBI0_INT) != 0 ? C_RADEON_CAPTURE_VBI0_INT : 0) |
328 ((mask & C_RADEON_CAP0_VBI1_INT) != 0 ? C_RADEON_CAPTURE_VBI1_INT : 0);
329 }
330 return 0;
331 }
332
Register(radeon_register index,int mask)333 int CCapture::Register(radeon_register index, int mask)
334 {
335 return fRadeon.Register(index, mask);
336 }
337
SetRegister(radeon_register index,int value)338 void CCapture::SetRegister(radeon_register index, int value)
339 {
340 fRadeon.SetRegister(index, value);
341 }
342
SetRegister(radeon_register index,int mask,int value)343 void CCapture::SetRegister(radeon_register index, int mask, int value)
344 {
345 fRadeon.SetRegister(index, mask, value);
346 }
347