1/* second CTRC functionality
2
3   Authors:
4   Mark Watson 6/2000,
5   Rudolf Cornelissen 12/2002 - 11/2005
6*/
7
8#define MODULE_BIT 0x00020000
9
10#include "mga_std.h"
11
12/*set a mode line - inputs are in pixels/scanlines*/
13status_t g400_crtc2_set_timing(display_mode target)
14{
15	uint32 temp;
16
17	LOG(4,("CRTC2: setting timing\n"));
18
19	if ((!(target.flags & TV_BITS)) || (si->ps.card_type <= G400MAX))
20	{
21		/* G450/G550 monitor mode, and all modes on older cards */
22
23		/* check horizontal timing parameters are to nearest 8 pixels */
24		if ((target.timing.h_display & 0x07) | (target.timing.h_sync_start & 0x07) |
25			(target.timing.h_sync_end & 0x07) | (target.timing.h_total & 0x07))
26		{
27			LOG(8,("CRTC2: Horizontal timings are not multiples of 8 pixels\n"));
28			return B_ERROR;
29		}
30
31		/* make sure NTSC clock killer circuitry is disabled */
32		CR2W(DATACTL, (CR2R(DATACTL) & ~0x00000010));
33
34		/* make sure CRTC2 is set to progressive scan for monitor mode */
35		CR2W(CTL, (CR2R(CTL) & ~0x02001000));
36
37		/* program the second CRTC */
38		CR2W(HPARAM, ((((target.timing.h_display - 8) & 0x0fff) << 16) |
39										((target.timing.h_total - 8) & 0x0fff)));
40		CR2W(HSYNC, ((((target.timing.h_sync_end - 8) & 0x0fff) << 16) |
41										((target.timing.h_sync_start - 8) & 0x0fff)));
42		CR2W(VPARAM, ((((target.timing.v_display - 1) & 0x0fff) << 16) |
43										((target.timing.v_total - 1) & 0x0fff)));
44		CR2W(VSYNC, ((((target.timing.v_sync_end - 1) & 0x0fff) << 16) |
45										((target.timing.v_sync_start - 1) & 0x0fff)));
46		//Mark: (wrong AFAIK, warning: SETMODE MAVEN-CRTC delay is now tuned to new setup!!)
47		//CR2W(PRELOAD, (((target.timing.v_sync_start & 0x0fff) << 16) |
48		//								(target.timing.h_sync_start & 0x0fff)));
49		CR2W(PRELOAD, ((((target.timing.v_sync_start - 1) & 0x0fff) << 16) |
50										((target.timing.h_sync_start - 8) & 0x0fff)));
51
52		temp = (0xfff << 16);
53		if (!(target.timing.flags & B_POSITIVE_HSYNC)) temp |= (0x01 << 8);
54		if (!(target.timing.flags & B_POSITIVE_VSYNC)) temp |= (0x01 << 9);
55		CR2W(MISC, temp);
56
57		/* On <= G400MAX dualhead cards we need to send a copy to the MAVEN;
58		 * unless TVout is active */
59		if ((si->ps.secondary_head) && (!(target.flags & TV_BITS)))
60													gx00_maven_set_timing(target);
61	}
62	else
63	{
64		/* G450/G550 TVout mode */
65		display_mode tv_mode = target;
66		uint8 frame;
67		unsigned int vcount, prev_vcount;
68
69		LOG(4,("CRTC2: setting up G450/G550 TVout mode\n"));
70
71		/* check horizontal timing parameters are to nearest 8 pixels */
72		if ((tv_mode.timing.h_display & 0x07) | (tv_mode.timing.h_sync_start & 0x07) |
73			(tv_mode.timing.h_sync_end & 0x07))
74		{
75			LOG(8,("CRTC2: Horizontal timings are not multiples of 8 pixels\n"));
76			return B_ERROR;
77		}
78
79		/* disable NTSC clock killer circuitry */
80		CR2W(DATACTL, (CR2R(DATACTL) & ~0x00000010));
81
82		if (tv_mode.timing.h_total & 0x07)
83		{
84			/* we rely on this for both PAL and NTSC modes if h_total is 'illegal' */
85			LOG(4,("CRTC2: enabling clock killer circuitry\n"));
86			CR2W(DATACTL, (CR2R(DATACTL) | 0x00000010));
87		}
88
89		/* make sure h_total is valid for TVout mode */
90		tv_mode.timing.h_total &= ~0x07;
91
92		/* modify tv_mode for interlaced use */
93		tv_mode.timing.v_display >>= 1;
94		tv_mode.timing.v_sync_start >>= 1;
95		tv_mode.timing.v_sync_end >>= 1;
96		tv_mode.timing.v_total >>= 1;
97
98		/*program the second CRTC*/
99		CR2W(HPARAM, ((((tv_mode.timing.h_display - 8) & 0x0fff) << 16) |
100										((tv_mode.timing.h_total - 8) & 0x0fff)));
101		CR2W(HSYNC, ((((tv_mode.timing.h_sync_end - 8) & 0x0fff) << 16) |
102										((tv_mode.timing.h_sync_start - 8) & 0x0fff)));
103		CR2W(VPARAM, ((((tv_mode.timing.v_display - 1) & 0x0fff) << 16) |
104										((tv_mode.timing.v_total - 1) & 0x0fff)));
105		CR2W(VSYNC, ((((tv_mode.timing.v_sync_end - 1) & 0x0fff) << 16) |
106										((tv_mode.timing.v_sync_start - 1) & 0x0fff)));
107		//Mark: (wrong AFAIK, warning: SETMODE MAVEN-CRTC delay is now tuned to new setup!!)
108		//CR2W(PRELOAD, (((tv_mode.timing.v_sync_start & 0x0fff) << 16) |
109		//								(tv_mode.timing.h_sync_start & 0x0fff)));
110		CR2W(PRELOAD, ((((tv_mode.timing.v_sync_start - 1) & 0x0fff) << 16) |
111										((tv_mode.timing.h_sync_start - 8) & 0x0fff)));
112
113		/* set CRTC2 to interlaced mode:
114		 * First enable progressive scan mode while making sure
115		 * CRTC2 is setup for TVout mode use... */
116		CR2W(CTL, ((CR2R(CTL) & ~0x02000000) | 0x00001000));
117		/* now synchronize to the start of a frame... */
118		prev_vcount = 0;
119		for (frame = 0; frame < 2; frame++)
120		{
121			for (;;)
122			{
123				vcount = (CR2R(VCOUNT) & 0x00000fff);
124				if (vcount >= prev_vcount)
125					prev_vcount = vcount;
126				else
127					break;
128			}
129		}
130		/* and start interlaced mode now! */
131		CR2W(CTL, (CR2R(CTL) | 0x02000000));
132
133		temp = (0xfff << 16);
134		if (!(tv_mode.timing.flags & B_POSITIVE_HSYNC)) temp |= (0x01 << 8);
135		if (!(tv_mode.timing.flags & B_POSITIVE_VSYNC)) temp |= (0x01 << 9);
136		CR2W(MISC, temp);
137	}
138
139	return B_OK;
140}
141
142status_t g400_crtc2_depth(int mode)
143{
144	/* validate bit depth and set mode */
145	/* also clears TVout mode (b12) */
146	switch(mode)
147	{
148	case BPP16:case BPP32DIR:
149		CR2W(CTL,(CR2R(CTL)&0xFF10077F)|(mode<<21));
150		break;
151	case BPP8:case BPP15:case BPP24:case BPP32:default:
152		LOG(8,("CRTC2:Invalid bit depth\n"));
153		return B_ERROR;
154		break;
155	}
156
157	return B_OK;
158}
159
160status_t g400_crtc2_dpms(bool display, bool h, bool v)
161{
162	char msg[100];
163
164	strlcpy(msg, "CRTC2: setting DPMS: ", sizeof(msg));
165
166	if (si->ps.card_type <= G400MAX)
167	{
168		if (display && h && v)
169		{
170			/* enable CRTC2 and don't touch the rest */
171			CR2W(CTL, ((CR2R(CTL) & 0xFFF0177E) | 0x01));
172			strlcat(msg, "display on, hsync enabled, vsync enabled\n", sizeof(msg));
173		}
174		else
175		{
176			/* disable CRTC2 and don't touch the rest */
177			CR2W(CTL, (CR2R(CTL) & 0xFFF0177E));
178			strlcat(msg, "display off, hsync disabled, vsync disabled\n", sizeof(msg));
179		}
180
181		LOG(4, (msg));
182
183		/* On <= G400MAX dualhead cards we always need to send a 'copy' to the MAVEN */
184		if (si->ps.secondary_head) gx00_maven_dpms(display, h, v);
185	}
186	else /* G450/G550 */
187	{
188		/* set HD15 and DVI-A sync pol. to be fixed 'straight through' from the CRTCs,
189		 * and preset enabled sync signals on both connectors.
190		 * (polarities and primary DPMS are done via other registers.) */
191		uint8 temp = 0x00;
192
193		if (display)
194		{
195			/* enable CRTC2 and don't touch the rest */
196			CR2W(CTL, ((CR2R(CTL) & 0xFFF0177E) | 0x01));
197			strlcat(msg, "display on, ", sizeof(msg));
198		}
199		else
200		{
201			/* disable CRTC2 and don't touch the rest */
202			CR2W(CTL, (CR2R(CTL) & 0xFFF0177E));
203			strlcat(msg, "display off, ", sizeof(msg));
204		}
205
206		if (si->crossed_conns)
207		{
208			if (h)
209			{
210				/* enable DVI-A hsync */
211				temp &= ~0x01;
212				strlcat(msg, "hsync enabled, ", sizeof(msg));
213			}
214			else
215			{
216				/* disable DVI-A hsync */
217				temp |= 0x01;
218				strlcat(msg, "hsync disabled, ", sizeof(msg));
219			}
220			if (v)
221			{
222				/* enable DVI-A vsync */
223				temp &= ~0x02;
224				strlcat(msg, "vsync enabled\n", sizeof(msg));
225			}
226			else
227			{
228				/* disable DVI-A vsync */
229				temp |= 0x02;
230				strlcat(msg, "vsync disabled\n", sizeof(msg));
231			}
232		}
233		else
234		{
235			if (h)
236			{
237				/* enable HD15 hsync */
238				temp &= ~0x10;
239				strlcat(msg, "hsync enabled, ", sizeof(msg));
240			}
241			else
242			{
243				/* disable HD15 hsync */
244				temp |= 0x10;
245				strlcat(msg, "hsync disabled, ", sizeof(msg));
246			}
247			if (v)
248			{
249				/* enable HD15 vsync */
250				temp &= ~0x20;
251				strlcat(msg, "vsync enabled\n", sizeof(msg));
252			}
253			else
254			{
255				/* disable HD15 vsync */
256				temp |= 0x20;
257				strlcat(msg, "vsync disabled\n", sizeof(msg));
258			}
259		}
260
261		LOG(4, (msg));
262
263		/* program new syncs */
264		DXIW(SYNCCTRL, temp);
265	}
266
267	return B_OK;
268}
269
270status_t g400_crtc2_set_display_pitch()
271{
272	uint32 offset;
273
274	LOG(4,("CRTC2: setting card pitch (offset between lines)\n"));
275
276	/* figure out offset value hardware needs */
277	offset = si->fbc.bytes_per_row;
278	if (si->interlaced_tv_mode)
279	{
280		LOG(4,("CRTC2: setting interlaced mode\n"));
281		/* double the CRTC2 linelength so fields are displayed instead of frames */
282		offset *= 2;
283	}
284	else
285		LOG(4,("CRTC2: setting progressive scan mode\n"));
286
287	LOG(2,("CRTC2: offset set to %d bytes\n", offset));
288
289	/* program the head */
290	CR2W(OFFSET,offset);
291	return B_OK;
292}
293
294status_t g400_crtc2_set_display_start(uint32 startadd,uint8 bpp)
295{
296	LOG(4,("CRTC2: setting card RAM to be displayed for %d bits per pixel\n", bpp));
297
298	LOG(2,("CRTC2: startadd: $%x\n",startadd));
299	LOG(2,("CRTC2: frameRAM: $%x\n",si->framebuffer));
300	LOG(2,("CRTC2: framebuffer: $%x\n",si->fbc.frame_buffer));
301
302	if (si->interlaced_tv_mode)
303	{
304		LOG(4,("CRTC2: setting up fields for interlaced mode\n"));
305		/* program the head for interlaced use */
306		//fixme: seperate both heads: we need a secondary si->fbc!
307		/* setup field 0 startadress in buffer to read picture's odd lines */
308		CR2W(STARTADD0,	(startadd + si->fbc.bytes_per_row));
309		/* setup field 1 startadress in buffer to read picture's even lines */
310		CR2W(STARTADD1, startadd);
311	}
312	else
313	{
314		LOG(4,("CRTC2: setting up frames for progressive scan mode\n"));
315		/* program the head for non-interlaced use */
316		CR2W(STARTADD0, startadd);
317	}
318
319	return B_OK;
320}
321