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