xref: /haiku/src/add-ons/accelerants/matrox/engine/mga_crtc2.c (revision 8d86b84d18535654da5b693537802d6ca115efe0)
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*/
g400_crtc2_set_timing(display_mode target)13 status_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 
g400_crtc2_depth(int mode)142 status_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 
g400_crtc2_dpms(bool display,bool h,bool v)160 status_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 
g400_crtc2_set_display_pitch()270 status_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 
g400_crtc2_set_display_start(uint32 startadd,uint8 bpp)294 status_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