xref: /haiku/src/add-ons/media/media-add-ons/radeon/Capture.cpp (revision f2ced752a08ff5d2618826bcd3ae3976c9f3e92e)
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 
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 
35 CCapture::~CCapture()
36 {
37 	PRINT(("CCapture::~CCapture()\n"));
38 }
39 
40 status_t CCapture::InitCheck() const
41 {
42 	return fRadeon.InitCheck();
43 }
44 
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 
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 
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 
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 
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 
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 
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 
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 
333 int CCapture::Register(radeon_register index, int mask)
334 {
335 	return fRadeon.Register(index, mask);
336 }
337 
338 void CCapture::SetRegister(radeon_register index, int value)
339 {
340 	fRadeon.SetRegister(index, value);
341 }
342 
343 void CCapture::SetRegister(radeon_register index, int mask, int value)
344 {
345 	fRadeon.SetRegister(index, mask, value);
346 }
347