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
18CCapture::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
35CCapture::~CCapture()
36{
37	PRINT(("CCapture::~CCapture()\n"));
38}
39
40status_t CCapture::InitCheck() const
41{
42	return fRadeon.InitCheck();
43}
44
45void 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
62void 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
70void 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
79void 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
87void 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
275void 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
289void 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
308int 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
333int CCapture::Register(radeon_register index, int mask)
334{
335	return fRadeon.Register(index, mask);
336}
337
338void CCapture::SetRegister(radeon_register index, int value)
339{
340	fRadeon.SetRegister(index, value);
341}
342
343void CCapture::SetRegister(radeon_register index, int mask, int value)
344{
345	fRadeon.SetRegister(index, mask, value);
346}
347