1 /* CTRC functionality */
2 /* Author:
3 Rudolf Cornelissen 4/2003-1/2006
4 */
5
6 #define MODULE_BIT 0x00040000
7
8 #include "nm_std.h"
9
10 /* Adjust passed parameters to a valid mode line */
nm_crtc_validate_timing(uint16 * hd_e,uint16 * hs_s,uint16 * hs_e,uint16 * ht,uint16 * vd_e,uint16 * vs_s,uint16 * vs_e,uint16 * vt)11 status_t nm_crtc_validate_timing(
12 uint16 *hd_e,uint16 *hs_s,uint16 *hs_e,uint16 *ht,
13 uint16 *vd_e,uint16 *vs_s,uint16 *vs_e,uint16 *vt
14 )
15 {
16 /* horizontal */
17 /* make all parameters multiples of 8 */
18 *hd_e &= 0xfff8;
19 *hs_s &= 0xfff8;
20 *hs_e &= 0xfff8;
21 *ht &= 0xfff8;
22
23 /* confine to required number of bits, taking logic into account */
24 if (*hd_e > ((0xff - 2) << 3)) *hd_e = ((0xff - 2) << 3);
25 if (*hs_s > ((0xff - 1) << 3)) *hs_s = ((0xff - 1) << 3);
26 if (*hs_e > ( 0xff << 3)) *hs_e = ( 0xff << 3);
27 if (*ht > ((0xff + 5) << 3)) *ht = ((0xff + 5) << 3);
28
29 /* NOTE: keep horizontal timing at multiples of 8! */
30 /* confine to a reasonable width */
31 if (*hd_e < 640) *hd_e = 640;
32 if (*hd_e > si->ps.max_crtc_width) *hd_e = si->ps.max_crtc_width;
33
34 /* if hor. total does not leave room for a sensible sync pulse,*/
35 /* increase it! */
36 if (*ht < (*hd_e + 80)) *ht = (*hd_e + 80);
37
38 /* if hor. total does not adhere to max. blanking pulse width,*/
39 /* decrease it! */
40 if (*ht > (*hd_e + 0x1f8)) *ht = (*hd_e + 0x1f8);
41
42 /* make sure sync pulse is not during display */
43 if (*hs_e > (*ht - 8)) *hs_e = (*ht - 8);
44 if (*hs_s < (*hd_e + 8)) *hs_s = (*hd_e + 8);
45
46 /* correct sync pulse if it is too long:
47 * there are only 5 bits available to save this in the card registers! */
48 if (*hs_e > (*hs_s + 0xf8)) *hs_e = (*hs_s + 0xf8);
49
50 /*vertical*/
51 /* confine to required number of bits, taking logic into account */
52 if (si->ps.card_type < NM2200)
53 {
54 if (*vd_e > (0x3ff - 2)) *vd_e = (0x3ff - 2);
55 if (*vs_s > (0x3ff - 1)) *vs_s = (0x3ff - 1);
56 if (*vs_e > 0x3ff ) *vs_e = 0x3ff ;
57 if (*vt > (0x3ff + 2)) *vt = (0x3ff + 2);
58 }
59 else
60 {
61 if (*vd_e > (0x7ff - 2)) *vd_e = (0x7ff - 2);
62 if (*vs_s > (0x7ff - 1)) *vs_s = (0x7ff - 1);
63 if (*vs_e > 0x7ff ) *vs_e = 0x7ff ;
64 if (*vt > (0x7ff + 2)) *vt = (0x7ff + 2);
65 }
66
67 /* confine to a reasonable height */
68 if (*vd_e < 480) *vd_e = 480;
69 if (*vd_e > si->ps.max_crtc_height) *vd_e = si->ps.max_crtc_height;
70
71 /*if vertical total does not leave room for a sync pulse, increase it!*/
72 if (*vt < (*vd_e + 3)) *vt = (*vd_e + 3);
73
74 /* if vert. total does not adhere to max. blanking pulse width,*/
75 /* decrease it! */
76 if (*vt > (*vd_e + 0xff)) *vt = (*vd_e + 0xff);
77
78 /* make sure sync pulse is not during display */
79 if (*vs_e > (*vt - 1)) *vs_e = (*vt - 1);
80 if (*vs_s < (*vd_e + 1)) *vs_s = (*vd_e + 1);
81
82 /* correct sync pulse if it is too long:
83 * there are only 4 bits available to save this in the card registers! */
84 if (*vs_e > (*vs_s + 0x0f)) *vs_e = (*vs_s + 0x0f);
85
86 return B_OK;
87 }
88
89 /* set a mode line */
nm_crtc_set_timing(display_mode target,bool crt_only)90 status_t nm_crtc_set_timing(display_mode target, bool crt_only)
91 {
92 uint8 temp;
93
94 uint32 htotal; /*total horizontal total VCLKs*/
95 uint32 hdisp_e; /*end of horizontal display (begins at 0)*/
96 uint32 hsync_s; /*begin of horizontal sync pulse*/
97 uint32 hsync_e; /*end of horizontal sync pulse*/
98 uint32 hblnk_s; /*begin horizontal blanking*/
99 uint32 hblnk_e; /*end horizontal blanking*/
100
101 uint32 vtotal; /*total vertical total scanlines*/
102 uint32 vdisp_e; /*end of vertical display*/
103 uint32 vsync_s; /*begin of vertical sync pulse*/
104 uint32 vsync_e; /*end of vertical sync pulse*/
105 uint32 vblnk_s; /*begin vertical blanking*/
106 uint32 vblnk_e; /*end vertical blanking*/
107
108 uint32 linecomp; /*split screen and vdisp_e interrupt*/
109
110 LOG(4,("CRTC: setting timing\n"));
111
112 /* modify visible sceensize if needed */
113 /* (note that MOVE_CURSOR checks for a panning/scrolling mode itself,
114 * the display_mode as placed in si->dm may _not_ be modified!) */
115 if (!crt_only)
116 {
117 if (target.timing.h_display > si->ps.panel_width)
118 {
119 target.timing.h_display = si->ps.panel_width;
120 LOG(4,
121 ("CRTC: req. width > panel width: setting panning mode\n"));
122 }
123 if (target.timing.v_display > si->ps.panel_height)
124 {
125 target.timing.v_display = si->ps.panel_height;
126 LOG(4,
127 ("CRTC: req. height > panel height: setting scrolling "
128 "mode\n"));
129 }
130
131 /* modify sync polarities
132 * (needed to maintain correct panel centering):
133 * both polarities must be negative (confirmed NM2160) */
134 target.timing.flags &= ~(B_POSITIVE_HSYNC | B_POSITIVE_VSYNC);
135 }
136
137 /* Modify parameters as required by standard VGA */
138 htotal = ((target.timing.h_total >> 3) - 5);
139 hdisp_e = ((target.timing.h_display >> 3) - 1);
140 hblnk_s = hdisp_e;
141 hblnk_e = (htotal + 0); /* this register differs from standard VGA! */
142 /* (says + 4) */
143 hsync_s = (target.timing.h_sync_start >> 3);
144 hsync_e = (target.timing.h_sync_end >> 3);
145
146 vtotal = target.timing.v_total - 2;
147 vdisp_e = target.timing.v_display - 1;
148 vblnk_s = vdisp_e;
149 vblnk_e = (vtotal + 1);
150 vsync_s = target.timing.v_sync_start;//-1;
151 vsync_e = target.timing.v_sync_end;//-1;
152
153 /* prevent memory adress counter from being reset */
154 /* (linecomp may not occur) */
155 linecomp = target.timing.v_display;
156
157 if (crt_only)
158 {
159 LOG(4,("CRTC: CRT only mode, setting full timing...\n"));
160
161 /* log the mode that will be set */
162 LOG(2,("CRTC:\n\tHTOT:%x\n\tHDISPEND:%x\n\tHBLNKS:%x\n\tHBLNKE:%x\n\tHSYNCS:%x\n\tHSYNCE:%x\n\t",htotal,hdisp_e,hblnk_s,hblnk_e,hsync_s,hsync_e));
163 LOG(2,("VTOT:%x\n\tVDISPEND:%x\n\tVBLNKS:%x\n\tVBLNKE:%x\n\tVSYNCS:%x\n\tVSYNCE:%x\n",vtotal,vdisp_e,vblnk_s,vblnk_e,vsync_s,vsync_e));
164
165 /* actually program the card! */
166 /* unlock CRTC registers at index 0-7 */
167 temp = (ISACRTCR(VSYNCE) & 0x7f);
168 /* we need to wait a bit or the card will mess-up it's */
169 /* register values.. */
170 snooze(10);
171 ISACRTCW(VSYNCE, temp);
172 /* horizontal standard VGA regs */
173 ISACRTCW(HTOTAL, (htotal & 0xff));
174 ISACRTCW(HDISPE, (hdisp_e & 0xff));
175 ISACRTCW(HBLANKS, (hblnk_s & 0xff));
176 /* also unlock vertical retrace registers in advance */
177 ISACRTCW(HBLANKE, ((hblnk_e & 0x1f) | 0x80));
178 ISACRTCW(HSYNCS, (hsync_s & 0xff));
179 ISACRTCW(HSYNCE, ((hsync_e & 0x1f) | ((hblnk_e & 0x20) << 2)));
180
181 /* vertical standard VGA regs */
182 ISACRTCW(VTOTAL, (vtotal & 0xff));
183 ISACRTCW(OVERFLOW,
184 (
185 ((vtotal & 0x100) >> (8 - 0)) | ((vtotal & 0x200) >> (9 - 5)) |
186 ((vdisp_e & 0x100) >> (8 - 1)) | ((vdisp_e & 0x200) >> (9 - 6)) |
187 ((vsync_s & 0x100) >> (8 - 2)) | ((vsync_s & 0x200) >> (9 - 7)) |
188 ((vblnk_s & 0x100) >> (8 - 3)) | ((linecomp & 0x100) >> (8 - 4))
189 ));
190 ISACRTCW(PRROWSCN, 0x00); /* not used */
191 ISACRTCW(MAXSCLIN, (((vblnk_s & 0x200) >> (9 - 5))
192 | ((linecomp & 0x200) >> (9 - 6))));
193 ISACRTCW(VSYNCS, (vsync_s & 0xff));
194 temp = (ISACRTCR(VSYNCE) & 0xf0);
195 /* we need to wait a bit or the card will mess-up it's */
196 /* register values.. */
197 snooze(10);
198 ISACRTCW(VSYNCE, (temp | (vsync_e & 0x0f)));
199 ISACRTCW(VDISPE, (vdisp_e & 0xff));
200 ISACRTCW(VBLANKS, (vblnk_s & 0xff));
201 ISACRTCW(VBLANKE, (vblnk_e & 0xff));
202 //linux: (BIOSmode)
203 // regp->CRTC[23] = 0xC3;
204 ISACRTCW(LINECOMP, (linecomp & 0xff));
205
206 /* horizontal - no extended regs available or needed on */
207 /* NeoMagic chips */
208
209 /* vertical - extended regs */
210 //fixme: checkout if b2 or 3 should be switched! (linux contains error here)
211 //fixme: linecomp should also have an extra bit... testable by setting linecomp
212 //to 100 for example and then try out writing an '1' to b2, b3(!) and the rest
213 //for screenorig reset visible on upper half of the screen or not at all..
214 if (si->ps.card_type >= NM2200)
215 ISACRTCW(VEXT,
216 (
217 ((vtotal & 0x400) >> (10 - 0)) |
218 ((vdisp_e & 0x400) >> (10 - 1)) |
219 ((vblnk_s & 0x400) >> (10 - 2)) |
220 ((vsync_s & 0x400) >> (10 - 3))/*|
221 ((linecomp&0x400)>>3)*/
222 ));
223 }
224 else
225 {
226 LOG(4,
227 ("CRTC: internal flatpanel active, setting display region only\n"));
228
229 /* actually program the card! */
230 /* unlock CRTC registers at index 0-7 */
231 temp = (ISACRTCR(VSYNCE) & 0x7f);
232 /* we need to wait a bit or the card will mess-up it's */
233 /* register values.. */
234 snooze(10);
235 ISACRTCW(VSYNCE, temp);
236 /* horizontal standard VGA regs */
237 ISACRTCW(HDISPE, (hdisp_e & 0xff));
238
239 /* vertical standard VGA regs */
240 temp = (ISACRTCR(OVERFLOW) & ~0x52);
241 /* we need to wait a bit or the card will mess-up it's */
242 /* register values.. */
243 snooze(10);
244 ISACRTCW(OVERFLOW,
245 (
246 temp |
247 ((vdisp_e & 0x100) >> (8 - 1)) |
248 ((vdisp_e & 0x200) >> (9 - 6)) |
249 ((linecomp & 0x100) >> (8 - 4))
250 ));
251
252 ISACRTCW(PRROWSCN, 0x00); /* not used */
253
254 temp = (ISACRTCR(MAXSCLIN) & ~0x40);
255 /* we need to wait a bit or the card will mess-up it's */
256 /* register values.. */
257 snooze(10);
258 ISACRTCW(MAXSCLIN, (temp | ((linecomp & 0x200) >> (9 - 6))));
259
260 ISACRTCW(VDISPE, (vdisp_e & 0xff));
261 //linux:(BIOSmode)
262 // regp->CRTC[23] = 0xC3;
263 ISACRTCW(LINECOMP, (linecomp & 0xff));
264
265 /* horizontal - no extended regs available or needed on */
266 /* NeoMagic chips */
267
268 /* vertical - extended regs */
269 //fixme: linecomp should have an extra bit... testable by setting linecomp
270 //to 100 for example and then try out writing an '1' to b2, b3(!) and the rest
271 //for screenorig reset visible on upper half of the screen or not at all..
272 if (si->ps.card_type >= NM2200)
273 {
274 temp = (ISACRTCR(VEXT) & ~0x02);
275 /* we need to wait a bit or the card will mess-up it's */
276 /* register values.. */
277 snooze(10);
278 ISACRTCW(VEXT,
279 (
280 temp |
281 ((vdisp_e & 0x400) >> (10 - 1))/*|
282 ((linecomp&0x400)>>3)*/
283 ));
284 }
285 }
286
287 /* setup HSYNC & VSYNC polarity */
288 LOG(2,("CRTC: sync polarity: "));
289 temp = ISARB(MISCR);
290 if (target.timing.flags & B_POSITIVE_HSYNC)
291 {
292 LOG(2,("H:pos "));
293 temp &= ~0x40;
294 }
295 else
296 {
297 LOG(2,("H:neg "));
298 temp |= 0x40;
299 }
300 if (target.timing.flags & B_POSITIVE_VSYNC)
301 {
302 LOG(2,("V:pos "));
303 temp &= ~0x80;
304 }
305 else
306 {
307 LOG(2,("V:neg "));
308 temp |= 0x80;
309 }
310 /* we need to wait a bit or the card will mess-up it's register values.. */
311 snooze(10);
312 ISAWB(MISCW, temp);
313 LOG(2,(", MISC reg readback: $%02x\n", ISARB(MISCR)));
314
315 /* program 'fixed' mode if needed */
316 if (si->ps.card_type != NM2070)
317 {
318 uint8 width;
319
320 temp = ISAGRPHR(PANELCTRL1);
321 /* we need to wait a bit or the card will mess-up it's register values.. */
322 snooze(10);
323
324 switch (target.timing.h_display)
325 {
326 case 1280:
327 width = (3 << 5);
328 break;
329 case 1024:
330 width = (2 << 5);
331 break;
332 case 800:
333 width = (1 << 5);
334 break;
335 case 640:
336 default: //fixme: non-std modes should be in between above modes?!?
337 width = (0 << 5);
338 break;
339 }
340
341 switch (si->ps.card_type)
342 {
343 case NM2090:
344 case NM2093:
345 case NM2097:
346 case NM2160:
347 //fixme: checkout b6????
348 ISAGRPHW(PANELCTRL1, ((temp & ~0x20) | (width & 0x20)));
349 break;
350 default:
351 /* NM2200 and later */
352 ISAGRPHW(PANELCTRL1, ((temp & ~0x60) | (width & 0x60)));
353 break;
354 }
355 }
356
357 return B_OK;
358 }
359
nm_crtc_depth(int mode)360 status_t nm_crtc_depth(int mode)
361 {
362 uint8 vid_delay = 0;
363
364 LOG(4,("CRTC: setting colordepth to be displayed\n"));
365
366 /* set VCLK scaling */
367 switch(mode)
368 {
369 case BPP8:
370 vid_delay = 0x01;
371 break;
372 case BPP15:
373 vid_delay = 0x02;
374 break;
375 case BPP16:
376 vid_delay = 0x03;
377 break;
378 case BPP24:
379 vid_delay = 0x04;
380 break;
381 default:
382 LOG(4,("CRTC: colordepth not supported, aborting!\n"));
383 return B_ERROR;
384 break;
385 }
386
387 switch (si->ps.card_type)
388 {
389 case NM2070:
390 vid_delay |= (ISAGRPHR(COLDEPTH) & 0xf0);
391 break;
392 default:
393 vid_delay |= (ISAGRPHR(COLDEPTH) & 0x70);
394 break;
395 }
396 /* we need to wait a bit or the card will mess-up it's */
397 /* register values.. (NM2160) */
398 snooze(10);
399 ISAGRPHW(COLDEPTH, vid_delay);
400
401 snooze(10);
402 LOG(4,("CRTC: colordepth register readback $%02x\n", (ISAGRPHR(COLDEPTH))));
403
404 return B_OK;
405 }
406
nm_crtc_dpms(bool display,bool h,bool v)407 status_t nm_crtc_dpms(bool display, bool h, bool v)
408 {
409 char msg[100];
410 const char* displayStatus;
411 const char* horizontalSync;
412 const char* verticalSync;
413
414 uint8 temp, size_outputs;
415
416 sprintf(msg, "CRTC: setting DPMS: ");
417
418 /* start synchronous reset: required before turning screen off! */
419 ISASEQW(RESET, 0x01);
420
421 /* turn screen off */
422 temp = ISASEQR(CLKMODE);
423 /* we need to wait a bit or the card will mess-up it's */
424 /* register values.. (NM2160) */
425 snooze(10);
426
427 if (display)
428 {
429 ISASEQW(CLKMODE, (temp & ~0x20));
430
431 /* end synchronous reset if display should be enabled */
432 ISASEQW(RESET, 0x03);
433 displayStatus = "on";
434 }
435 else
436 {
437 ISASEQW(CLKMODE, (temp | 0x20));
438 displayStatus = "off";
439 }
440
441 temp = 0x00;
442 if (h)
443 {
444 horizontalSync = "enabled";
445 }
446 else
447 {
448 temp |= 0x10;
449 horizontalSync = "disabled";
450 }
451 if (v)
452 {
453 verticalSync = "enabled";
454 }
455 else
456 {
457 temp |= 0x20;
458 verticalSync = "disabled";
459 }
460
461 snprintf(msg, sizeof(msg),
462 "CRTC: setting DPMS: display %s, hsync %s, vsync %s\n",
463 displayStatus, horizontalSync, verticalSync);
464 LOG(4, (msg));
465
466 /* read panelsize and currently active outputs */
467 size_outputs = nm_general_output_read();
468 /* we need to wait a bit or the card will mess-up it's register */
469 /* values.. (NM2160) */
470 snooze(10);
471
472 if (si->ps.card_type < NM2200)
473 {
474 /* no full DPMS support */
475 if (temp)
476 {
477 /* Turn panel plus backlight and external monitor's */
478 /* sync signals off */
479 ISAGRPHW(PANELCTRL1, (size_outputs & 0xfc));
480 }
481 else
482 {
483 /* restore 'previous' output device(s) */
484 ISAGRPHW(PANELCTRL1, size_outputs);
485 }
486 }
487 else
488 {
489 if (temp)
490 {
491 /* Turn panel plus backlight off */
492 ISAGRPHW(PANELCTRL1, (size_outputs & 0xfd));
493 }
494 else
495 {
496 /* restore 'previous' panel situation */
497 ISAGRPHW(PANELCTRL1, size_outputs);
498 }
499
500 /* if external monitor is active, update it's DPMS state */
501 if (size_outputs & 0x01)
502 {
503 /* we have full DPMS support for external monitors */
504 //fixme: checkout if so...
505 temp |= ((ISAGRPHR(ENSETRESET) & 0x0f) | 0x80);
506 /* we need to wait a bit or the card will mess-up it's */
507 /* register values.. (NM2160) */
508 snooze(10);
509 ISAGRPHW(ENSETRESET, temp);
510
511 snooze(10);
512 LOG(4,("CRTC: DPMS readback $%02x, programmed $%02x\n",
513 ISAGRPHR(ENSETRESET), temp));
514 }
515 }
516
517 return B_OK;
518 }
519
nm_crtc_set_display_pitch()520 status_t nm_crtc_set_display_pitch()
521 {
522 uint32 offset;
523
524 LOG(4,("CRTC: setting card pitch (offset between lines)\n"));
525
526 /* figure out offset value hardware needs: same for all Neomagic cards */
527 offset = si->fbc.bytes_per_row / 8;
528
529 LOG(2,("CRTC: offset register set to: $%04x\n", offset));
530
531 /* program the card */
532 ISACRTCW(PITCHL, (offset & 0xff));
533 //fixme: test for max supported pitch if possible,
534 //not all bits below will be implemented.
535 //NM2160: confirmed b0 and b1 in register below to exist and work.
536 if (si->ps.card_type != NM2070)
537 ISAGRPHW(CRTC_PITCHE, ((offset & 0xff00) >> 8));
538
539 return B_OK;
540 }
541
nm_crtc_set_display_start(uint32 startadd,uint8 bpp)542 status_t nm_crtc_set_display_start(uint32 startadd,uint8 bpp)
543 {
544 uint8 val;
545 uint32 timeout = 0;
546
547 LOG(2,("CRTC: relative startadd: $%06x\n",startadd));
548 LOG(2,("CRTC: frameRAM: $%08x\n",si->framebuffer));
549 LOG(2,("CRTC: framebuffer: $%08x\n",si->fbc.frame_buffer));
550
551 /* make sure we _just_ left retrace, because otherwise distortions */
552 /* might occur during our reprogramming (no double buffering) */
553 /* (verified on NM2160) */
554
555 /* we might have no retraces during setmode! So:
556 * wait 25mS max. for retrace to occur (refresh > 40Hz) */
557 //fixme? move this function to the kernel driver... is much 'faster'.
558 while ((!(ISARB(INSTAT1) & 0x08)) && (timeout < (25000/4)))
559 {
560 snooze(4);
561 timeout++;
562 }
563 /* now wait until retrace ends (with timeout) */
564 timeout = 0;
565 while ((ISARB(INSTAT1) & 0x08) && (timeout < (25000/4)))
566 {
567 snooze(4);
568 timeout++;
569 }
570
571 /* set standard VGA registers */
572 /* (startadress in 32bit words (b2 - b17) */
573 ISACRTCW(FBSTADDH, ((startadd & 0x03fc00) >> 10));
574 ISACRTCW(FBSTADDL, ((startadd & 0x0003fc) >> 2));
575
576 /* set NM extended register */
577 //fixme: NM2380 _must_ have one more bit (has >4Mb RAM)!!
578 //this is testable via virtualscreen in 640x480x8 mode...
579 //(b4 is >256Kb adresswrap bit, so that's already occupied)
580 val = ISAGRPHR(FBSTADDE);
581 /* we need to wait a bit or the card will mess-up it's */
582 /* register values.. (NM2160) */
583 snooze(10);
584 if (si->ps.card_type < NM2200)
585 /* extended bits: (b18-20) */
586 ISAGRPHW(FBSTADDE,(((startadd >> 18) & 0x07) | (val & 0xf8)));
587 else
588 /* extended bits: (b18-21) */
589 ISAGRPHW(FBSTADDE,(((startadd >> 18) & 0x0f) | (val & 0xf0)));
590
591 /* set byte adress: (b0 - 1):
592 * Neomagic cards work with _pixel_ offset here. */
593 switch(bpp)
594 {
595 case 8:
596 ISAATBW(HORPIXPAN, (startadd & 0x00000003));
597 break;
598 case 15:
599 case 16:
600 ISAATBW(HORPIXPAN, ((startadd & 0x00000002) >> 1));
601 break;
602 case 24:
603 ISAATBW(HORPIXPAN, ((4 - (startadd & 0x00000003)) & 0x03));
604 break;
605 }
606
607 return B_OK;
608 }
609
610 /* setup centering mode for current internal or simultaneous */
611 /* flatpanel mode */
nm_crtc_center(display_mode target,bool crt_only)612 status_t nm_crtc_center(display_mode target, bool crt_only)
613 {
614 /* note:
615 * NM2070 apparantly doesn't support horizontal */
616 /* centering this way... */
617
618 uint8 vcent1, vcent2, vcent3, vcent4, vcent5;
619 uint8 hcent1, hcent2, hcent3, hcent4, hcent5;
620 uint8 ctrl2, ctrl3;
621
622 /* preset no centering */
623 uint16 hoffset = 0;
624 uint16 voffset = 0;
625 vcent1 = vcent2 = vcent3 = vcent4 = vcent5 = 0x00;
626 hcent1 = hcent2 = hcent3 = hcent4 = hcent5 = 0x00;
627 ctrl2 = ctrl3 = 0x00;
628
629 /* calculate offsets for centering if prudent */
630 if (!crt_only)
631 {
632 if (target.timing.h_display < si->ps.panel_width)
633 {
634 hoffset = (si->ps.panel_width - target.timing.h_display);
635 /* adjust for register contraints:
636 * horizontal center granularity is 16 pixels */
637 hoffset = ((hoffset >> 4) - 1);
638 /* turn on horizontal centering? */
639 ctrl3 = 0x10;
640 }
641
642 if (target.timing.v_display < si->ps.panel_height)
643 {
644 voffset = (si->ps.panel_height - target.timing.v_display);
645 /* adjust for register contraints:
646 * vertical center granularity is 2 pixels */
647 voffset = ((voffset >> 1) - 2);
648 /* turn on vertical centering? */
649 ctrl2 = 0x01;
650 }
651
652 switch(target.timing.h_display)
653 {
654 case 640:
655 hcent1 = hoffset;
656 vcent3 = voffset;
657 break;
658 case 800:
659 hcent2 = hoffset;
660 switch(target.timing.v_display)
661 {
662 case 480:
663 //Linux fixme: check this out...
664 vcent3 = voffset;
665 break;
666 case 600:
667 vcent4 = voffset;
668 break;
669 }
670 break;
671 case 1024:
672 hcent5 = hoffset;
673 vcent5 = voffset;
674 break;
675 case 1280:
676 /* this mode equals the largest possible panel on the *
677 * newest chip: so no centering needed here. */
678 break;
679 default:
680 //fixme?: block non-standard modes? for now: not centered.
681 break;
682 }
683 }
684
685 /* now program the card's registers */
686 ISAGRPHW(PANELVCENT1, vcent1);
687 ISAGRPHW(PANELVCENT2, vcent2);
688 ISAGRPHW(PANELVCENT3, vcent3);
689 if (si->ps.card_type > NM2070)
690 {
691 ISAGRPHW(PANELVCENT4, vcent4);
692 ISAGRPHW(PANELHCENT1, hcent1);
693 ISAGRPHW(PANELHCENT2, hcent2);
694 ISAGRPHW(PANELHCENT3, hcent3);
695 }
696 if (si->ps.card_type >= NM2160)
697 {
698 ISAGRPHW(PANELHCENT4, hcent4);
699 }
700 if (si->ps.card_type >= NM2200)
701 {
702 ISAGRPHW(PANELVCENT5, vcent5);
703 ISAGRPHW(PANELHCENT5, hcent5);
704 }
705
706 /* program panel control register 2: don't touch bit 3-5 */
707 ctrl2 |= (ISAGRPHR(PANELCTRL2) & 0x38);
708 /* we need to wait a bit or the card will mess-up it's register */
709 /* values.. (NM2160) */
710 snooze(10);
711 ISAGRPHW(PANELCTRL2, ctrl2);
712
713 if (si->ps.card_type > NM2070)
714 {
715 /* program panel control register 3: don't touch bit 7-5 */
716 /* and bit 3-0 */
717 ctrl3 |= (ISAGRPHR(PANELCTRL3) & 0xef);
718 /* we need to wait a bit or the card will mess-up it's */
719 /* register values.. (NM2160) */
720 snooze(10);
721 ISAGRPHW(PANELCTRL3, ctrl3);
722 }
723
724 return B_OK;
725 }
726
727 /* program panel modeline if needed */
nm_crtc_prg_panel()728 status_t nm_crtc_prg_panel()
729 {
730 status_t stat = B_ERROR;
731
732 /* only NM2070 requires this apparantly */
733 /* (because it's BIOS doesn't do it OK) */
734 if (si->ps.card_type > NM2070) return B_OK;
735
736 switch(si->ps.panel_width)
737 {
738 case 640:
739 /* 640x480 panels are only used on NM2070 */
740 ISACRTCW(PANEL_0x40, 0x5f);
741 ISACRTCW(PANEL_0x41, 0x50);
742 ISACRTCW(PANEL_0x42, 0x02);
743 ISACRTCW(PANEL_0x43, 0x55);
744 ISACRTCW(PANEL_0x44, 0x81);
745 ISACRTCW(PANEL_0x45, 0x0b);
746 ISACRTCW(PANEL_0x46, 0x2e);
747 ISACRTCW(PANEL_0x47, 0xea);
748 ISACRTCW(PANEL_0x48, 0x0c);
749 ISACRTCW(PANEL_0x49, 0xe7);
750 ISACRTCW(PANEL_0x4a, 0x04);
751 ISACRTCW(PANEL_0x4b, 0x2d);
752 ISACRTCW(PANEL_0x4c, 0x28);
753 ISACRTCW(PANEL_0x4d, 0x90);
754 ISACRTCW(PANEL_0x4e, 0x2b);
755 ISACRTCW(PANEL_0x4f, 0xa0);
756 stat = B_OK;
757 break;
758 case 800:
759 switch(si->ps.panel_height)
760 {
761 case 600:
762 /* 800x600 panels are used on all cards... */
763 ISACRTCW(PANEL_0x40, 0x7f);
764 ISACRTCW(PANEL_0x41, 0x63);
765 ISACRTCW(PANEL_0x42, 0x02);
766 ISACRTCW(PANEL_0x43, 0x6c);
767 ISACRTCW(PANEL_0x44, 0x1c);
768 ISACRTCW(PANEL_0x45, 0x72);
769 ISACRTCW(PANEL_0x46, 0xe0);
770 ISACRTCW(PANEL_0x47, 0x58);
771 ISACRTCW(PANEL_0x48, 0x0c);
772 ISACRTCW(PANEL_0x49, 0x57);
773 ISACRTCW(PANEL_0x4a, 0x73);
774 ISACRTCW(PANEL_0x4b, 0x3d);
775 ISACRTCW(PANEL_0x4c, 0x31);
776 ISACRTCW(PANEL_0x4d, 0x01);
777 ISACRTCW(PANEL_0x4e, 0x36);
778 ISACRTCW(PANEL_0x4f, 0x1e);
779 if (si->ps.card_type > NM2070)
780 {
781 ISACRTCW(PANEL_0x50, 0x6b);
782 ISACRTCW(PANEL_0x51, 0x4f);
783 ISACRTCW(PANEL_0x52, 0x0e);
784 ISACRTCW(PANEL_0x53, 0x58);
785 ISACRTCW(PANEL_0x54, 0x88);
786 ISACRTCW(PANEL_0x55, 0x33);
787 ISACRTCW(PANEL_0x56, 0x27);
788 ISACRTCW(PANEL_0x57, 0x16);
789 ISACRTCW(PANEL_0x58, 0x2c);
790 ISACRTCW(PANEL_0x59, 0x94);
791 }
792 stat = B_OK;
793 break;
794 case 480:
795 /* ...while 800x480 widescreen panels are not used on NM2070. */
796 ISACRTCW(PANEL_0x40, 0x7f);
797 ISACRTCW(PANEL_0x41, 0x63);
798 ISACRTCW(PANEL_0x42, 0x02);
799 ISACRTCW(PANEL_0x43, 0x6b);
800 ISACRTCW(PANEL_0x44, 0x1b);
801 ISACRTCW(PANEL_0x45, 0x72);
802 ISACRTCW(PANEL_0x46, 0xe0);
803 ISACRTCW(PANEL_0x47, 0x1c);
804 ISACRTCW(PANEL_0x48, 0x00);
805 ISACRTCW(PANEL_0x49, 0x57);
806 ISACRTCW(PANEL_0x4a, 0x73);
807 ISACRTCW(PANEL_0x4b, 0x3e);
808 ISACRTCW(PANEL_0x4c, 0x31);
809 ISACRTCW(PANEL_0x4d, 0x01);
810 ISACRTCW(PANEL_0x4e, 0x36);
811 ISACRTCW(PANEL_0x4f, 0x1e);
812 ISACRTCW(PANEL_0x50, 0x6b);
813 ISACRTCW(PANEL_0x51, 0x4f);
814 ISACRTCW(PANEL_0x52, 0x0e);
815 ISACRTCW(PANEL_0x53, 0x57);
816 ISACRTCW(PANEL_0x54, 0x87);
817 ISACRTCW(PANEL_0x55, 0x33);
818 ISACRTCW(PANEL_0x56, 0x27);
819 ISACRTCW(PANEL_0x57, 0x16);
820 ISACRTCW(PANEL_0x58, 0x2c);
821 ISACRTCW(PANEL_0x59, 0x94);
822 stat = B_OK;
823 break;
824 }
825 break;
826 case 1024:
827 switch(si->ps.panel_height)
828 {
829 case 768:
830 /* 1024x768 panels are only used on later cards
831 * (NM2097 and later ?) */
832 ISACRTCW(PANEL_0x40, 0xa3);
833 ISACRTCW(PANEL_0x41, 0x7f);
834 ISACRTCW(PANEL_0x42, 0x06);
835 ISACRTCW(PANEL_0x43, 0x85);
836 ISACRTCW(PANEL_0x44, 0x96);
837 ISACRTCW(PANEL_0x45, 0x24);
838 ISACRTCW(PANEL_0x46, 0xe5);
839 ISACRTCW(PANEL_0x47, 0x02);
840 ISACRTCW(PANEL_0x48, 0x08);
841 ISACRTCW(PANEL_0x49, 0xff);
842 ISACRTCW(PANEL_0x4a, 0x25);
843 ISACRTCW(PANEL_0x4b, 0x4f);
844 ISACRTCW(PANEL_0x4c, 0x40);
845 ISACRTCW(PANEL_0x4d, 0x00);
846 ISACRTCW(PANEL_0x4e, 0x44);
847 ISACRTCW(PANEL_0x4f, 0x0c);
848 ISACRTCW(PANEL_0x50, 0x7a);
849 ISACRTCW(PANEL_0x51, 0x56);
850 ISACRTCW(PANEL_0x52, 0x00);
851 ISACRTCW(PANEL_0x53, 0x5d);
852 ISACRTCW(PANEL_0x54, 0x0e);
853 ISACRTCW(PANEL_0x55, 0x3b);
854 ISACRTCW(PANEL_0x56, 0x2b);
855 ISACRTCW(PANEL_0x57, 0x00);
856 ISACRTCW(PANEL_0x58, 0x2f);
857 ISACRTCW(PANEL_0x59, 0x18);
858 ISACRTCW(PANEL_0x60, 0x88);
859 ISACRTCW(PANEL_0x61, 0x63);
860 ISACRTCW(PANEL_0x62, 0x0b);
861 ISACRTCW(PANEL_0x63, 0x69);
862 ISACRTCW(PANEL_0x64, 0x1a);
863 stat = B_OK;
864 break;
865 case 480:
866 /* 1024x480 widescreen panels are only used on later cards
867 * (NM2097 and later ?) */
868 ISACRTCW(PANEL_0x40, 0xa3);
869 ISACRTCW(PANEL_0x41, 0x7f);
870 ISACRTCW(PANEL_0x42, 0x1b);
871 ISACRTCW(PANEL_0x43, 0x89);
872 ISACRTCW(PANEL_0x44, 0x16);
873 ISACRTCW(PANEL_0x45, 0x0b);
874 ISACRTCW(PANEL_0x46, 0x2c);
875 ISACRTCW(PANEL_0x47, 0xe8);
876 ISACRTCW(PANEL_0x48, 0x0c);
877 ISACRTCW(PANEL_0x49, 0xe7);
878 ISACRTCW(PANEL_0x4a, 0x09);
879 ISACRTCW(PANEL_0x4b, 0x4f);
880 ISACRTCW(PANEL_0x4c, 0x40);
881 ISACRTCW(PANEL_0x4d, 0x00);
882 ISACRTCW(PANEL_0x4e, 0x44);
883 ISACRTCW(PANEL_0x4f, 0x0c);
884 ISACRTCW(PANEL_0x50, 0x7a);
885 ISACRTCW(PANEL_0x51, 0x56);
886 ISACRTCW(PANEL_0x52, 0x00);
887 ISACRTCW(PANEL_0x53, 0x5d);
888 ISACRTCW(PANEL_0x54, 0x0e);
889 ISACRTCW(PANEL_0x55, 0x3b);
890 ISACRTCW(PANEL_0x56, 0x2a);
891 ISACRTCW(PANEL_0x57, 0x00);
892 ISACRTCW(PANEL_0x58, 0x2f);
893 ISACRTCW(PANEL_0x59, 0x18);
894 ISACRTCW(PANEL_0x60, 0x88);
895 ISACRTCW(PANEL_0x61, 0x63);
896 ISACRTCW(PANEL_0x62, 0x0b);
897 ISACRTCW(PANEL_0x63, 0x69);
898 ISACRTCW(PANEL_0x64, 0x1a);
899 stat = B_OK;
900 break;
901 }
902 break;
903 case 1280:
904 /* no info available */
905 break;
906 }
907
908 if (stat != B_OK)
909 LOG(2,("CRTC: unable to program panel: unknown modeline needed.\n"));
910
911 return stat;
912 }
913
nm_crtc_cursor_init()914 status_t nm_crtc_cursor_init()
915 {
916 int i;
917 vuint32 * fb;
918 uint32 curadd, curreg;
919
920 /* the cursor is at the end of cardRAM */
921 curadd = ((si->ps.memory_size * 1024) - si->ps.curmem_size);
922
923 /* set cursor bitmap adress on a 1kb boundary, and move the bits around
924 * so they get placed at the correct registerbits */
925 curreg = (((curadd >> 10) & 0x000f) << 8);
926 curreg |= (((curadd >> 10) & 0x0ff0) >> 4);
927 /* NM2380 must have an extra bit for > 4Mb: assuming it to be on b12... */
928 curreg |= ((curadd >> 10) & 0x1000);
929
930 if (si->ps.card_type < NM2200)
931 CR1W(CURADDRESS, curreg);
932 else
933 CR1W(22CURADDRESS, curreg);
934
935 /*set cursor colour*/
936 if (si->ps.card_type < NM2200)
937 {
938 /* background is black */
939 CR1W(CURBGCOLOR, 0x00000000);
940 /* foreground is white */
941 CR1W(CURFGCOLOR, 0x00ffffff);
942 }
943 else
944 {
945 /* background is black */
946 CR1W(22CURBGCOLOR, 0x00000000);
947 /* foreground is white */
948 CR1W(22CURFGCOLOR, 0x00ffffff);
949 }
950
951 /* we must set a valid colordepth to get full RAM access on Neomagic cards:
952 * in old pre 8-bit color VGA modes some planemask is in effect apparantly,
953 * allowing access only to every 7th and 8th RAM byte across the
954 * entire RAM. */
955 nm_crtc_depth(BPP8);
956
957 /* clear cursor: so we need full RAM access! */
958 fb = ((vuint32 *)(((uintptr_t)si->framebuffer) + curadd));
959 for (i = 0; i < (1024/4); i++)
960 {
961 fb[i] = 0;
962 }
963
964 /* activate hardware cursor */
965 nm_crtc_cursor_show();
966
967 return B_OK;
968 }
969
nm_crtc_cursor_show()970 status_t nm_crtc_cursor_show()
971 {
972 if (si->ps.card_type < NM2200)
973 {
974 CR1W(CURCTRL, 0x00000001);
975 }
976 else
977 {
978 CR1W(22CURCTRL, 0x00000001);
979 }
980 return B_OK;
981 }
982
nm_crtc_cursor_hide()983 status_t nm_crtc_cursor_hide()
984 {
985 //linux fixme: using this kills PCI(?) access sometimes,
986 //so use ISA access as below...
987 /*
988 if (si->ps.card_type < NM2200)
989 {
990 CR1W(CURCTRL, 0x00000000);
991 }
992 else
993 {
994 CR1W(22CURCTRL, 0x00000000);
995 }
996 */
997 /* disable cursor */
998 ISAGRPHW(CURCTRL,0x00);
999
1000 return B_OK;
1001 }
1002
1003 /*set up cursor shape*/
nm_crtc_cursor_define(uint8 * andMask,uint8 * xorMask)1004 status_t nm_crtc_cursor_define(uint8* andMask,uint8* xorMask)
1005 {
1006 uint8 y;
1007 vuint8 * cursor;
1008
1009 /* get a pointer to the cursor: it's at the end of cardRAM */
1010 cursor = (vuint8*) si->framebuffer;
1011 cursor += ((si->ps.memory_size * 1024) - si->ps.curmem_size);
1012
1013 /*draw the cursor*/
1014 for(y=0;y<16;y++)
1015 {
1016 cursor[y*16+8]=~*andMask++;
1017 cursor[y*16+0]=*xorMask++;
1018 cursor[y*16+9]=~*andMask++;
1019 cursor[y*16+1]=*xorMask++;
1020 }
1021
1022 //test.. only valid for <NM2200!!
1023 /* {
1024 float pclk;
1025 uint8 n,m,x = 1;
1026 n = ISAGRPHR(PLLC_NL);
1027 m = ISAGRPHR(PLLC_M);
1028 LOG(4,("CRTC: PLLSEL $%02x\n", ISARB(MISCR)));
1029 LOG(4,("CRTC: PLLN $%02x\n", n));
1030 LOG(4,("CRTC: PLLM $%02x\n", m));
1031
1032 if (n & 0x80) x = 2;
1033 n &= 0x7f;
1034 pclk = ((si->ps.f_ref * (n + 1)) / ((m + 1) * x));
1035 LOG(2,("CRTC: Pixelclock is %fMHz\n", pclk));
1036 nm_general_output_select();
1037 }
1038 */
1039 return B_OK;
1040 }
1041
1042 /*position the cursor*/
nm_crtc_cursor_position(uint16 x,uint16 y)1043 status_t nm_crtc_cursor_position(uint16 x ,uint16 y)
1044 {
1045 //NM2160 is ok without this, still verify the rest..:
1046 /* make sure we are not in retrace, because the register(s) might get copied
1047 * during our reprogramming them (double buffering feature) */
1048 /* fixme!?
1049 while (ACCR(STATUS) & 0x08)
1050 {
1051 snooze(4);
1052 }
1053 */
1054 if (si->ps.card_type < NM2200)
1055 {
1056 CR1W(CURX, (uint32)x);
1057 CR1W(CURY, (uint32)y);
1058 }
1059 else
1060 {
1061 CR1W(22CURX, (uint32)x);
1062 CR1W(22CURY, (uint32)y);
1063 }
1064
1065 return B_OK;
1066 }
1067