added 2.6.29.6 aldebaran kernel
[nao-ulib.git] / kernel / 2.6.29.6-aldebaran-rt / lib / cimarron / cim / cim_vg.c
blob8dbd3622a7dd91ac7e6b2e19e01a98435ed89876
1 /*
2 * <LIC_AMD_STD>
3 * Copyright (C) 2005 Advanced Micro Devices, Inc. All Rights Reserved.
4 * </LIC_AMD_STD>
6 * <CTL_AMD_STD>
7 * </CTL_AMD_STD>
9 * <DOC_AMD_STD>
10 * Cimarron display controller routines. These routines program the display
11 * mode and configure the hardware cursor and video buffers.
12 * </DOC_AMD_STD>
16 /*---------------------*/
17 /* CIMARRON VG GLOBALS */
18 /*---------------------*/
20 CIMARRON_STATIC unsigned long vg3_x_hotspot = 0;
21 CIMARRON_STATIC unsigned long vg3_y_hotspot = 0;
22 CIMARRON_STATIC unsigned long vg3_cursor_offset = 0;
23 CIMARRON_STATIC unsigned long vg3_mode_width = 0;
24 CIMARRON_STATIC unsigned long vg3_mode_height = 0;
25 CIMARRON_STATIC unsigned long vg3_panel_width = 0;
26 CIMARRON_STATIC unsigned long vg3_panel_height = 0;
27 CIMARRON_STATIC unsigned long vg3_delta_x = 0;
28 CIMARRON_STATIC unsigned long vg3_delta_y = 0;
29 CIMARRON_STATIC unsigned long vg3_bpp = 0;
31 CIMARRON_STATIC unsigned long vg3_color_cursor = 0;
32 CIMARRON_STATIC unsigned long vg3_panel_enable = 0;
34 /*---------------------------------------------------------------------------
35 * vg_delay_milliseconds
37 * This routine delays for a number of milliseconds based on a crude
38 * delay loop.
39 *---------------------------------------------------------------------------*/
41 int vg_delay_milliseconds (unsigned long ms)
43 /* ASSUME 500 MHZ 20 CLOCKS PER READ */
45 unsigned long loop = ms * 25000;
46 while (loop-- > 0)
48 READ_REG32 (DC3_UNLOCK);
50 return CIM_STATUS_OK;
53 /*---------------------------------------------------------------------------
54 * vg_set_display_mode
56 * This routine sets a CRT display mode using predefined Cimarron timings. The
57 * source width and height are specified to allow scaling.
58 *---------------------------------------------------------------------------*/
60 int vg_set_display_mode (unsigned long src_width, unsigned long src_height,
61 unsigned long dst_width, unsigned long dst_height, int bpp, int hz,
62 unsigned long flags)
64 VG_QUERY_MODE crt_query;
65 VG_DISPLAY_MODE crt_mode;
66 int mode;
68 crt_query.active_width = dst_width;
69 crt_query.active_height = dst_height;
70 crt_query.bpp = bpp;
71 crt_query.hz = hz;
72 crt_query.query_flags = VG_QUERYFLAG_ACTIVEWIDTH |
73 VG_QUERYFLAG_ACTIVEHEIGHT |
74 VG_QUERYFLAG_BPP |
75 VG_QUERYFLAG_REFRESH;
77 mode = vg_get_display_mode_index (&crt_query);
78 if (mode >= 0)
80 crt_mode = CimarronDisplayModes[mode];
81 crt_mode.src_width = src_width;
82 crt_mode.src_height = src_height;
84 /* ADD USER-REQUESTED FLAGS */
86 crt_mode.flags |= (flags & VG_MODEFLAG_VALIDUSERFLAGS);
88 if (flags & VG_MODEFLAG_OVERRIDE_BAND)
90 crt_mode.flags &= ~VG_MODEFLAG_BANDWIDTHMASK;
91 crt_mode.flags |= (flags & VG_MODEFLAG_BANDWIDTHMASK);
93 if (flags & VG_MODEFLAG_INT_OVERRIDE)
95 crt_mode.flags &= ~VG_MODEFLAG_INT_MASK;
96 crt_mode.flags |= (flags & VG_MODEFLAG_INT_MASK);
99 return vg_set_custom_mode (&crt_mode, bpp);
101 return CIM_STATUS_ERROR;
104 /*---------------------------------------------------------------------------
105 * vg_set_panel_mode
107 * This routine sets a panel mode using predefined Cimarron fixed timings. The
108 * source width and height specify the width and height of the data in the frame
109 * buffer. The destination width and height specify the width and height of
110 * the active data to be displayed. The panel width and height specify the
111 * dimensions of the panel. This interface allows the user to scale or center
112 * graphics data or both. To perform scaling, the src width or height should
113 * be different than the destination width or height. To perform centering or
114 * panning, the destination width and height should be different than the panel
115 * resolution.
116 *---------------------------------------------------------------------------*/
118 int vg_set_panel_mode (unsigned long src_width, unsigned long src_height,
119 unsigned long dst_width, unsigned long dst_height,
120 unsigned long panel_width, unsigned long panel_height,
121 int bpp, unsigned long flags)
123 unsigned long sync_width;
124 unsigned long sync_offset;
125 VG_QUERY_MODE panel_query;
126 VG_DISPLAY_MODE panel_mode;
127 int mode;
129 /* SEARCH CIMARRON'S TABLE OF PREDEFINED PANEL MODES */
130 /* If the destination resolution is larger than the panel resolution, */
131 /* panning will be performed. However, the timings for a panned mode */
132 /* are identical to the timings without panning. To save space in the */
133 /* mode tables, there are no additional table entries for modes with */
134 /* panning. Instead, we read the timings for a mode without panning */
135 /* and override the structure entries that specify the width and */
136 /* height of the mode. We perform a similar procedure for centered */
137 /* modes, except that certain timing parameters are dynamically */
138 /* calculated. */
140 panel_query.active_width = panel_width;
141 panel_query.active_height = panel_height;
142 panel_query.panel_width = panel_width;
143 panel_query.panel_height = panel_height;
144 panel_query.bpp = bpp;
145 panel_query.query_flags = VG_QUERYFLAG_ACTIVEWIDTH |
146 VG_QUERYFLAG_ACTIVEHEIGHT |
147 VG_QUERYFLAG_PANELWIDTH |
148 VG_QUERYFLAG_PANELHEIGHT |
149 VG_QUERYFLAG_PANEL |
150 VG_QUERYFLAG_BPP;
152 mode = vg_get_display_mode_index (&panel_query);
154 /* COPY THE DATA FROM THE MODE TABLE TO A TEMPORARY STRUCTURE */
156 if (mode >= 0)
158 panel_mode = CimarronDisplayModes[mode];
159 panel_mode.mode_width = dst_width;
160 panel_mode.mode_height = dst_height;
161 panel_mode.src_width = src_width;
162 panel_mode.src_height = src_height;
164 /* ADD USER-REQUESTED FLAGS */
166 panel_mode.flags |= (flags & VG_MODEFLAG_VALIDUSERFLAGS);
168 if (flags & VG_MODEFLAG_OVERRIDE_BAND)
170 panel_mode.flags &= ~VG_MODEFLAG_BANDWIDTHMASK;
171 panel_mode.flags |= (flags & VG_MODEFLAG_BANDWIDTHMASK);
173 if (flags & VG_MODEFLAG_INT_OVERRIDE)
175 panel_mode.flags &= ~VG_MODEFLAG_INT_MASK;
176 panel_mode.flags |= (flags & VG_MODEFLAG_INT_MASK);
179 /* DYNAMICALLY CALCULATE CENTERED TIMINGS */
180 /* For centered timings the blank start and blank end are set to */
181 /* half the difference between the mode dimension and the panel */
182 /* dimension. The sync pulse preserves the width and offset from */
183 /* blanking whenever possible. */
185 if (dst_width < panel_width)
187 sync_width = panel_mode.hsyncend - panel_mode.hsyncstart;
188 sync_offset = panel_mode.hsyncstart - panel_mode.hblankstart;
190 panel_mode.hactive = dst_width;
191 panel_mode.hblankstart = panel_mode.hactive + ((panel_width - dst_width) >> 1);
192 panel_mode.hblankend = panel_mode.htotal - ((panel_width - dst_width) >> 1);
193 panel_mode.hsyncstart = panel_mode.hblankstart + sync_offset;
194 panel_mode.hsyncend = panel_mode.hsyncstart + sync_width;
196 panel_mode.flags |= VG_MODEFLAG_CENTERED;
198 if (dst_height < panel_height)
200 sync_width = panel_mode.vsyncend - panel_mode.vsyncstart;
201 sync_offset = panel_mode.vsyncstart - panel_mode.vblankstart;
203 panel_mode.vactive = dst_height;
204 panel_mode.vblankstart = panel_mode.vactive + ((panel_height - dst_height) >> 1);
205 panel_mode.vblankend = panel_mode.vtotal - ((panel_height - dst_height) >> 1);
206 panel_mode.vsyncstart = panel_mode.vblankstart + sync_offset;
207 panel_mode.vsyncend = panel_mode.vsyncstart + sync_width;
209 panel_mode.flags |= VG_MODEFLAG_CENTERED;
211 return vg_set_custom_mode (&panel_mode, bpp);
213 return CIM_STATUS_ERROR;
216 /*---------------------------------------------------------------------------
217 * vg_set_tv_mode
219 * This routine sets a TV display mode using predefined Cimarron timings. The
220 * source width and height are specified to allow scaling.
221 *---------------------------------------------------------------------------*/
223 int vg_set_tv_mode (unsigned long *src_width, unsigned long *src_height,
224 unsigned long encoder, unsigned long tvres, int bpp, unsigned long flags,
225 unsigned long h_overscan, unsigned long v_overscan)
227 unsigned long sync_width;
228 unsigned long sync_offset;
229 VG_QUERY_MODE tv_query;
230 VG_DISPLAY_MODE tv_mode;
231 int mode;
233 if (!src_width || !src_height)
234 return CIM_STATUS_INVALIDPARAMS;
236 tv_query.bpp = bpp;
237 tv_query.encoder = encoder;
238 tv_query.tvmode = tvres;
239 tv_query.query_flags = VG_QUERYFLAG_BPP |
240 VG_QUERYFLAG_TVOUT |
241 VG_QUERYFLAG_ENCODER |
242 VG_QUERYFLAG_TVMODE;
244 mode = vg_get_display_mode_index (&tv_query);
245 if (mode >= 0)
247 /* RETRIEVE THE UNSCALED RESOLUTION */
248 /* As we are indexing here simply by a mode and encoder, the actual */
249 /* timings may vary. A 0 value for source or height will thus query the */
250 /* unscaled resolution. */
252 if (!(*src_width) || !(*src_height))
254 *src_width = CimarronDisplayModes[mode].hactive - (h_overscan << 1);
255 *src_height = CimarronDisplayModes[mode].vactive;
257 if (CimarronDisplayModes[mode].flags & VG_MODEFLAG_INTERLACED)
259 if (((flags & VG_MODEFLAG_INT_OVERRIDE) &&
260 (flags & VG_MODEFLAG_INT_MASK) == VG_MODEFLAG_INT_LINEDOUBLE) ||
261 (!(flags & VG_MODEFLAG_INT_OVERRIDE) &&
262 (CimarronDisplayModes[mode].flags & VG_MODEFLAG_INT_MASK) == VG_MODEFLAG_INT_LINEDOUBLE))
264 if (CimarronDisplayModes[mode].vactive_even > CimarronDisplayModes[mode].vactive)
265 *src_height = CimarronDisplayModes[mode].vactive_even;
267 /* ONLY 1/2 THE OVERSCAN FOR LINE DOUBLED MODES */
269 *src_height -= v_overscan;
271 else
273 *src_height += CimarronDisplayModes[mode].vactive_even;
274 *src_height -= v_overscan << 1;
277 else
279 *src_height -= v_overscan << 1;
282 return CIM_STATUS_OK;
285 tv_mode = CimarronDisplayModes[mode];
286 tv_mode.src_width = *src_width;
287 tv_mode.src_height = *src_height;
289 /* ADD USER-REQUESTED FLAGS */
291 tv_mode.flags |= (flags & VG_MODEFLAG_VALIDUSERFLAGS);
293 if (flags & VG_MODEFLAG_OVERRIDE_BAND)
295 tv_mode.flags &= ~VG_MODEFLAG_BANDWIDTHMASK;
296 tv_mode.flags |= (flags & VG_MODEFLAG_BANDWIDTHMASK);
298 if (flags & VG_MODEFLAG_INT_OVERRIDE)
300 tv_mode.flags &= ~VG_MODEFLAG_INT_MASK;
301 tv_mode.flags |= (flags & VG_MODEFLAG_INT_MASK);
304 /* ADJUST FOR OVERSCAN */
306 if (h_overscan)
308 sync_width = tv_mode.hsyncend - tv_mode.hsyncstart;
309 sync_offset = tv_mode.hsyncstart - tv_mode.hblankstart;
311 tv_mode.hactive -= h_overscan << 1;
312 tv_mode.hblankstart = tv_mode.hactive + h_overscan;
313 tv_mode.hblankend = tv_mode.htotal - h_overscan;
314 tv_mode.hsyncstart = tv_mode.hblankstart + sync_offset;
315 tv_mode.hsyncend = tv_mode.hsyncstart + sync_width;
317 tv_mode.flags |= VG_MODEFLAG_CENTERED;
319 if (v_overscan)
321 sync_width = tv_mode.vsyncend - tv_mode.vsyncstart;
322 sync_offset = tv_mode.vsyncstart - tv_mode.vblankstart;
324 if (tv_mode.flags & VG_MODEFLAG_INTERLACED)
326 tv_mode.vactive -= v_overscan;
327 tv_mode.vblankstart = tv_mode.vactive + (v_overscan >> 1);
328 tv_mode.vblankend = tv_mode.vtotal - (v_overscan >> 1);
329 tv_mode.vsyncstart = tv_mode.vblankstart + sync_offset;
330 tv_mode.vsyncend = tv_mode.vsyncstart + sync_width;
332 sync_width = tv_mode.vsyncend_even - tv_mode.vsyncstart_even;
333 sync_offset = tv_mode.vsyncstart_even - tv_mode.vblankstart_even;
335 tv_mode.vactive_even -= v_overscan;
336 tv_mode.vblankstart_even = tv_mode.vactive_even + (v_overscan >> 1);
337 tv_mode.vblankend_even = tv_mode.vtotal_even - (v_overscan >> 1);
338 tv_mode.vsyncstart_even = tv_mode.vblankstart_even + sync_offset;
339 tv_mode.vsyncend_even = tv_mode.vsyncstart_even + sync_width;
341 else
343 tv_mode.vactive -= v_overscan << 1;
344 tv_mode.vblankstart = tv_mode.vactive + v_overscan;
345 tv_mode.vblankend = tv_mode.vtotal - v_overscan;
346 tv_mode.vsyncstart = tv_mode.vblankstart + sync_offset;
347 tv_mode.vsyncend = tv_mode.vsyncstart + sync_width;
350 tv_mode.flags |= VG_MODEFLAG_CENTERED;
353 /* TV MODES WILL NEVER ALLOW PANNING */
355 tv_mode.panel_width = tv_mode.hactive;
356 tv_mode.panel_height = tv_mode.vactive;
357 tv_mode.mode_width = tv_mode.hactive;
358 tv_mode.mode_height = tv_mode.vactive;
360 return vg_set_custom_mode (&tv_mode, bpp);
362 return CIM_STATUS_ERROR;
365 /*---------------------------------------------------------------------------
366 * vg_set_custom_mode
368 * This routine sets a display mode. The API is structured such that this routine
369 * can be called from four sources:
370 * - vg_set_display_mode
371 * - vg_set_panel_mode
372 * - vg_set_tv_mode
373 * - directly by the user for a custom mode.
374 *---------------------------------------------------------------------------*/
376 int vg_set_custom_mode (VG_DISPLAY_MODE *mode_params, int bpp)
378 unsigned long config, misc, temp;
379 unsigned long irq_ctl, genlk_ctl;
380 unsigned long unlock, flags;
381 unsigned long acfg, gcfg, dcfg;
382 unsigned long size, line_size, pitch;
383 unsigned long bpp_mask, dv_size;
384 unsigned long hscale, vscale, starting_width;
385 unsigned long starting_height, output_height;
386 Q_WORD msr_value;
388 /* DETERMINE DIMENSIONS FOR SCALING */
389 /* Scaling is performed before flicker filtering and interlacing */
391 output_height = mode_params->vactive;
393 if (mode_params->flags & VG_MODEFLAG_INTERLACED)
395 /* EVEN AND ODD FIELDS ARE SEPARATE */
396 /* The composite image height is the sum of the height of both fields */
398 if ((mode_params->flags & VG_MODEFLAG_INT_MASK) == VG_MODEFLAG_INT_FLICKER ||
399 (mode_params->flags & VG_MODEFLAG_INT_MASK) == VG_MODEFLAG_INT_ADDRESS)
401 output_height += mode_params->vactive_even;
404 /* LINE DOUBLING */
405 /* The composite image height is the greater of the two field heights. */
407 else if (mode_params->vactive_even > output_height)
408 output_height = mode_params->vactive_even;
411 /* CHECK FOR VALID SCALING FACTOR */
412 /* GeodeLX supports only 2:1 vertical downscale (before interlacing) and */
413 /* 2:1 horizontal downscale. The source width when scaling must be */
414 /* less than or equal to 1024 pixels. The destination can be any size, */
415 /* except when flicker filtering is enabled. */
417 irq_ctl = 0;
418 if (mode_params->flags & VG_MODEFLAG_PANELOUT)
420 if (mode_params->src_width != mode_params->mode_width)
422 starting_width = (mode_params->hactive * mode_params->src_width) / mode_params->mode_width;
423 hscale = (mode_params->src_width << 14) / (mode_params->mode_width - 1);
424 irq_ctl |= (DC3_IRQFILT_ALPHA_FILT_EN | DC3_IRQFILT_GFX_FILT_EN);
426 else
428 starting_width = mode_params->hactive;
429 hscale = 0x4000;
431 if (mode_params->src_height != mode_params->mode_height)
433 starting_height = (output_height * mode_params->src_height) / mode_params->mode_height;
434 vscale = (mode_params->src_height << 14) / (mode_params->mode_height - 1);
435 irq_ctl |= (DC3_IRQFILT_ALPHA_FILT_EN | DC3_IRQFILT_GFX_FILT_EN);
437 else
439 starting_height = output_height;
440 vscale = 0x4000;
443 else
445 starting_width = mode_params->src_width;
446 starting_height = mode_params->src_height;
447 if (mode_params->src_width != mode_params->hactive)
449 hscale = (mode_params->src_width << 14) / (mode_params->hactive - 1);
450 irq_ctl |= (DC3_IRQFILT_ALPHA_FILT_EN | DC3_IRQFILT_GFX_FILT_EN);
452 else
454 hscale = 0x4000;
456 if (mode_params->src_height != output_height)
458 vscale = (mode_params->src_height << 14) / (output_height - 1);
459 irq_ctl |= (DC3_IRQFILT_ALPHA_FILT_EN | DC3_IRQFILT_GFX_FILT_EN);
461 else
463 vscale = 0x4000;
467 starting_width = (starting_width + 7) & 0xFFFF8;
469 if (mode_params->hactive < (starting_width >> 1) ||
470 output_height < (starting_height >> 1) ||
471 (irq_ctl && (starting_width > 1024)))
473 return CIM_STATUS_INVALIDSCALE;
476 /* VERIFY INTERLACED SCALING */
477 /* The output width must be less than or equal to 1024 pixels when the */
478 /* flicker filter is enabled. Also, scaling should be disabled when */
479 /* the interlacing mode is set to interlaced addressing. */
481 if (mode_params->flags & VG_MODEFLAG_INTERLACED)
483 if ((((mode_params->flags & VG_MODEFLAG_INT_MASK) == VG_MODEFLAG_INT_FLICKER) &&
484 (mode_params->hactive > 1024)) ||
485 (((mode_params->flags & VG_MODEFLAG_INT_MASK) == VG_MODEFLAG_INT_ADDRESS) && irq_ctl))
487 return CIM_STATUS_INVALIDSCALE;
491 /* CHECK FOR VALID BPP */
493 switch (bpp)
495 case 8: bpp_mask = DC3_DCFG_DISP_MODE_8BPP; break;
496 case 24: bpp_mask = DC3_DCFG_DISP_MODE_24BPP; break;
497 case 32: bpp_mask = DC3_DCFG_DISP_MODE_32BPP; break;
498 case 12: bpp_mask = DC3_DCFG_DISP_MODE_16BPP | DC3_DCFG_12BPP; break;
499 case 15: bpp_mask = DC3_DCFG_DISP_MODE_16BPP | DC3_DCFG_15BPP; break;
500 case 16: bpp_mask = DC3_DCFG_DISP_MODE_16BPP | DC3_DCFG_16BPP; break;
501 default: return CIM_STATUS_INVALIDPARAMS;
504 vg3_bpp = bpp;
506 /* CLEAR PANNING OFFSETS */
508 vg3_delta_x = 0;
509 vg3_delta_y = 0;
511 /* SAVE PANEL PARAMETERS */
513 if (mode_params->flags & VG_MODEFLAG_PANELOUT)
515 vg3_panel_enable = 1;
516 vg3_panel_width = mode_params->panel_width;
517 vg3_panel_height = mode_params->panel_height;
518 vg3_mode_width = mode_params->mode_width;
519 vg3_mode_height = mode_params->mode_height;
521 /* INVERT THE SHIFT CLOCK IF REQUESTED */
522 /* Note that we avoid writing the power management register if */
523 /* we can help it. */
525 temp = READ_VID32 (DF_POWER_MANAGEMENT);
526 if ((mode_params->flags & VG_MODEFLAG_INVERT_SHFCLK) &&
527 !(temp & DF_PM_INVERT_SHFCLK))
529 WRITE_VID32 (DF_POWER_MANAGEMENT, (temp | DF_PM_INVERT_SHFCLK));
531 else if (!(mode_params->flags & VG_MODEFLAG_INVERT_SHFCLK) &&
532 (temp & DF_PM_INVERT_SHFCLK))
534 WRITE_VID32 (DF_POWER_MANAGEMENT, (temp & ~DF_PM_INVERT_SHFCLK));
537 /* SET PANEL TIMING VALUES */
539 if (!(mode_params->flags & VG_MODEFLAG_NOPANELTIMINGS))
541 unsigned long pmtim1, pmtim2, dith_ctl;
543 if (mode_params->flags & VG_MODEFLAG_XVGA_TFT)
545 pmtim1 = DF_DEFAULT_XVGA_PMTIM1;
546 pmtim2 = DF_DEFAULT_XVGA_PMTIM2;
547 dith_ctl = DF_DEFAULT_DITHCTL;
548 msr_value.low = DF_DEFAULT_XVGA_PAD_SEL_LOW;
549 msr_value.high = DF_DEFAULT_XVGA_PAD_SEL_HIGH;
551 else if (mode_params->flags & VG_MODEFLAG_CUSTOM_PANEL)
553 pmtim1 = mode_params->panel_tim1;
554 pmtim2 = mode_params->panel_tim2;
555 dith_ctl = mode_params->panel_dither_ctl;
556 msr_value.low = mode_params->panel_pad_sel_low;
557 msr_value.high = mode_params->panel_pad_sel_high;
559 else
561 pmtim1 = DF_DEFAULT_TFT_PMTIM1;
562 pmtim2 = DF_DEFAULT_TFT_PMTIM2;
563 dith_ctl = DF_DEFAULT_DITHCTL;
564 msr_value.low = DF_DEFAULT_TFT_PAD_SEL_LOW;
565 msr_value.high = DF_DEFAULT_TFT_PAD_SEL_HIGH;
568 WRITE_VID32 (DF_VIDEO_PANEL_TIM1, pmtim1);
569 WRITE_VID32 (DF_VIDEO_PANEL_TIM2, pmtim2);
570 WRITE_VID32 (DF_DITHER_CONTROL, dith_ctl);
571 msr_write64 (MSR_DEVICE_GEODELX_DF, DF_MSR_PAD_SEL, &msr_value);
574 /* SET APPROPRIATE PANEL OUTPUT MODE */
576 msr_read64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
578 msr_value.low &= ~DF_CONFIG_OUTPUT_MASK;
579 msr_value.low |= DF_OUTPUT_PANEL;
580 if (mode_params->flags & VG_MODEFLAG_CRT_AND_FP)
581 msr_value.low |= DF_SIMULTANEOUS_CRT_FP;
582 else
583 msr_value.low &= ~DF_SIMULTANEOUS_CRT_FP;
585 msr_write64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
588 else if (mode_params->flags & VG_MODEFLAG_TVOUT)
590 vg3_panel_enable = 0;
592 /* SET APPROPRIATE TV OUTPUT MODE */
594 msr_read64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
596 msr_value.low &= ~DF_CONFIG_OUTPUT_MASK;
597 msr_value.low |= DF_OUTPUT_PANEL;
598 if (mode_params->flags & VG_MODEFLAG_CRT_AND_FP)
599 msr_value.low |= DF_SIMULTANEOUS_CRT_FP;
600 else
601 msr_value.low &= ~DF_SIMULTANEOUS_CRT_FP;
603 msr_write64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
605 /* CONFIGURE PADS FOR VOP OUTPUT */
606 /* Note that the VOP clock is currently always inverted. */
608 msr_value.low = DF_DEFAULT_TV_PAD_SEL_LOW;
609 msr_value.high = DF_DEFAULT_TV_PAD_SEL_HIGH;
610 msr_write64 (MSR_DEVICE_GEODELX_DF, DF_MSR_PAD_SEL, &msr_value);
612 else
614 vg3_panel_enable = 0;
616 /* SET OUTPUT TO CRT ONLY */
618 msr_read64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
619 msr_value.low &= ~DF_CONFIG_OUTPUT_MASK;
620 msr_value.low |= DF_OUTPUT_CRT;
621 msr_write64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
624 /* SET UNLOCK VALUE */
626 unlock = READ_REG32 (DC3_UNLOCK);
627 WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
629 /*-------------------------------------------------------------------*/
630 /* MAKE THE SYSTEM "SAFE" */
631 /* Before setting a mode, we first ensure that the system is in a */
632 /* benign quiescent state. This involves disabling compression and */
633 /* all interrupt sources. It also involves terminating all accesses */
634 /* to memory, including video, FIFO load, VIP and the GP. */
635 /*-------------------------------------------------------------------*/
637 /* DISABLE VGA */
638 /* VGA *MUST* be turned off before TGEN is enabled. If not, a condition */
639 /* will result where VGA Enable is waiting for a VSync to be latched but */
640 /* a VSync will not be generated until VGA is disabled. */
642 temp = READ_REG32 (DC3_GENERAL_CFG) & ~DC3_GCFG_VGAE;
644 /* DISABLE VIDEO (INCLUDING ALPHA WINDOWS) */
646 WRITE_VID32 (DF_ALPHA_CONTROL_1, 0);
647 WRITE_VID32 (DF_ALPHA_CONTROL_1 + 32, 0);
648 WRITE_VID32 (DF_ALPHA_CONTROL_1 + 64, 0);
650 WRITE_REG32 (DC3_GENERAL_CFG, (temp & ~DC3_GCFG_VIDE));
651 temp = READ_VID32 (DF_VIDEO_CONFIG);
652 WRITE_VID32 (DF_VIDEO_CONFIG, (temp & ~DF_VCFG_VID_EN));
654 /* DISABLE VG INTERRUPTS */
656 WRITE_REG32 (DC3_IRQ, DC3_IRQ_MASK | DC3_VSYNC_IRQ_MASK |
657 DC3_IRQ_STATUS | DC3_VSYNC_IRQ_STATUS);
659 /* DISABLE GENLOCK */
661 genlk_ctl = READ_REG32 (DC3_GENLK_CTL);
662 WRITE_REG32 (DC3_GENLK_CTL, (genlk_ctl & ~DC3_GC_GENLOCK_ENABLE));
664 /* DISABLE VIP CAPTURE AND VIP INTERRUPTS */
666 WRITE_VIP32 (VIP_CONTROL1, 0);
667 WRITE_VIP32 (VIP_CONTROL2, 0);
668 WRITE_VIP32 (VIP_INTERRUPT, VIP_ALL_INTERRUPTS | (VIP_ALL_INTERRUPTS >> 16));
670 /* DISABLE COLOR KEYING */
671 /* The color key mechanism should be disabled whenever a mode switch occurs. */
673 temp = READ_REG32 (DC3_COLOR_KEY);
674 WRITE_REG32 (DC3_COLOR_KEY, (temp & ~DC3_CLR_KEY_ENABLE));
676 /* BLANK THE DISPLAY */
677 /* Note that we never blank the panel. Most flat panels have very long */
678 /* latency requirements when setting their power low. Some panels require */
679 /* upwards of 500ms before VDD goes high again. Needless to say, we are not */
680 /* planning to take over one half a second inside this routine. */
682 misc = READ_VID32 (DF_VID_MISC);
683 config = READ_VID32 (DF_DISPLAY_CONFIG);
685 WRITE_VID32 (DF_VID_MISC, (misc | DF_DAC_POWER_DOWN));
686 WRITE_VID32 (DF_DISPLAY_CONFIG, (config & ~(DF_DCFG_DIS_EN | DF_DCFG_HSYNC_EN |
687 DF_DCFG_VSYNC_EN | DF_DCFG_DAC_BL_EN)));
689 /* DISABLE COMPRESSION */
691 gcfg = READ_REG32 (DC3_GENERAL_CFG);
692 gcfg &= ~(DC3_GCFG_CMPE | DC3_GCFG_DECE);
693 WRITE_REG32 (DC3_GENERAL_CFG, gcfg);
695 /* DISABLE THE TIMING GENERATOR */
697 dcfg = READ_REG32 (DC3_DISPLAY_CFG);
698 dcfg &= ~DC3_DCFG_TGEN;
699 WRITE_REG32 (DC3_DISPLAY_CFG, dcfg);
701 /* WAIT FOR PENDING MEMORY REQUESTS */
703 vg_delay_milliseconds(1);
705 /* DISABLE DISPLAY FIFO LOAD */
707 gcfg &= ~DC3_GCFG_DFLE;
708 WRITE_REG32 (DC3_GENERAL_CFG, gcfg);
709 gcfg = 0;
710 dcfg = 0;
712 /* WAIT FOR THE GP TO BE IDLE (JUST IN CASE) */
714 while (((temp = READ_GP32 (GP3_BLT_STATUS)) & GP3_BS_BLT_BUSY) ||
715 !(temp & GP3_BS_CB_EMPTY))
720 /* SET THE DOT CLOCK FREQUENCY */
722 if (!(mode_params->flags & VG_MODEFLAG_EXCLUDEPLL))
724 if (mode_params->flags & VG_MODEFLAG_HALFCLOCK)
725 flags = VG_PLL_DIVIDE_BY_2;
726 else if (mode_params->flags & VG_MODEFLAG_QVGA)
727 flags = VG_PLL_DIVIDE_BY_4;
728 else
729 flags = 0;
731 /* ALLOW DOTREF TO BE USED AS THE PLL */
732 /* This is useful for some external TV encoders. */
734 if (mode_params->flags & VG_MODEFLAG_PLL_BYPASS)
735 flags |= VG_PLL_BYPASS;
737 /* ALLOW THE USER TO MANUALLY ENTER THE MSR VALUE */
739 if (mode_params->flags & VG_MODEFLAG_MANUAL_FREQUENCY)
740 flags |= VG_PLL_MANUAL;
741 if (mode_params->flags & VG_MODEFLAG_VIP_TO_DOT_CLOCK)
742 flags |= VG_PLL_VIP_CLOCK;
744 vg_set_clock_frequency (mode_params->frequency, flags);
747 /* CLEAR ALL BUFFER OFFSETS */
749 WRITE_REG32 (DC3_FB_ST_OFFSET, 0);
750 WRITE_REG32 (DC3_CB_ST_OFFSET, 0);
751 WRITE_REG32 (DC3_CURS_ST_OFFSET, 0);
753 genlk_ctl = READ_REG32 (DC3_GENLK_CTL) & ~(DC3_GC_ALPHA_FLICK_ENABLE |
754 DC3_GC_FLICKER_FILTER_ENABLE | DC3_GC_FLICKER_FILTER_MASK);
756 /* ENABLE INTERLACING */
758 if (mode_params->flags & VG_MODEFLAG_INTERLACED)
760 irq_ctl |= DC3_IRQFILT_INTL_EN;
762 if ((mode_params->flags & VG_MODEFLAG_INT_MASK) == VG_MODEFLAG_INT_ADDRESS)
763 irq_ctl |= DC3_IRQFILT_INTL_ADDR;
764 else if ((mode_params->flags & VG_MODEFLAG_INT_MASK) == VG_MODEFLAG_INT_FLICKER)
766 genlk_ctl |= DC3_GC_FLICKER_FILTER_1_8 | DC3_GC_FLICKER_FILTER_ENABLE |
767 DC3_GC_ALPHA_FLICK_ENABLE;
771 WRITE_REG32 (DC3_GFX_SCALE, (vscale << 16) | (hscale & 0xFFFF));
772 WRITE_REG32 (DC3_IRQ_FILT_CTL, irq_ctl);
773 WRITE_REG32 (DC3_GENLK_CTL, genlk_ctl);
775 /* SET LINE SIZE AND PITCH */
776 /* The line size and pitch are calculated from the src_width parameter */
777 /* passed in to this routine. All other parameters are ignored. */
778 /* The pitch is set either to a power of 2 to allow efficient */
779 /* compression or to a linear value to allow efficient memory management. */
781 switch (bpp)
783 case 8:
784 size = mode_params->src_width;
785 line_size = starting_width;
786 break;
788 case 12:
789 case 15:
790 case 16:
792 size = mode_params->src_width << 1;
793 line_size = starting_width << 1;
794 break;
796 case 24:
797 case 32:
798 default:
800 size = mode_params->src_width << 2;
801 line_size = starting_width << 2; break;
804 /* CALCULATE DV RAM SETTINGS AND POWER OF 2 PITCH */
806 pitch = 1024;
807 dv_size = DC3_DV_LINE_SIZE_1024;
809 if (size > 1024) { pitch = 2048; dv_size = DC3_DV_LINE_SIZE_2048; }
810 if (size > 2048) { pitch = 4096; dv_size = DC3_DV_LINE_SIZE_4096; }
811 if (size > 4096) { pitch = 8192; dv_size = DC3_DV_LINE_SIZE_8192; }
813 /* OVERRIDE SETTINGS FOR LINEAR PITCH */
815 if (mode_params->flags & VG_MODEFLAG_LINEARPITCH)
817 unsigned long max;
818 if (pitch != size)
820 /* CALCULATE MAXIMUM ADDRESS (1K ALIGNED) */
822 max = size * output_height;
823 max = (max + 0x3FF) & 0xFFFFFC00;
824 WRITE_REG32 (DC3_DV_TOP, max | DC3_DVTOP_ENABLE);
826 gcfg |= DC3_GCFG_FDTY;
827 pitch = size;
829 else
831 WRITE_REG32 (DC3_DV_TOP, 0);
835 /* WRITE PITCH AND DV RAM SETTINGS */
836 /* The DV RAM line length is programmed at a power of 2 boundary */
837 /* in case the user wants to toggle back to a power of 2 pitch */
838 /* later. It could happen... */
840 temp = READ_REG32 (DC3_DV_CTL);
841 WRITE_REG32 (DC3_GFX_PITCH, pitch >> 3);
842 WRITE_REG32 (DC3_DV_CTL, (temp & ~DC3_DV_LINE_SIZE_MASK) | dv_size);
844 /* SET THE LINE SIZE */
846 WRITE_REG32 (DC3_LINE_SIZE, (line_size + 7) >> 3);
848 /* ALWAYS ENABLE VIDEO AND GRAPHICS DATA */
849 /* These bits are relics from a previous design and */
850 /* should always be enabled. */
852 dcfg |= (DC3_DCFG_VDEN | DC3_DCFG_GDEN);
854 /* SET PIXEL FORMAT */
856 dcfg |= bpp_mask;
858 /* ENABLE TIMING GENERATOR, TIM. REG. UPDATES, PALETTE BYPASS */
859 /* AND VERT. INT. SELECT */
861 dcfg |= (unsigned long)(DC3_DCFG_TGEN | DC3_DCFG_TRUP | DC3_DCFG_PALB | DC3_DCFG_VISL);
863 /* SET FIFO PRIORITIES AND DISPLAY FIFO LOAD ENABLE */
864 /* Note that the bandwidth setting gets upgraded when scaling or flicker */
865 /* filtering are enabled, as they require more data throughput. */
867 msr_read64 (MSR_DEVICE_GEODELX_VG, DC3_SPARE_MSR, &msr_value);
868 msr_value.low &= ~(DC3_SPARE_DISABLE_CFIFO_HGO | DC3_SPARE_VFIFO_ARB_SELECT |
869 DC3_SPARE_LOAD_WM_LPEN_MASK | DC3_SPARE_WM_LPEN_OVRD |
870 DC3_SPARE_DISABLE_INIT_VID_PRI | DC3_SPARE_DISABLE_VFIFO_WM);
872 if ((mode_params->flags & VG_MODEFLAG_BANDWIDTHMASK) == VG_MODEFLAG_HIGH_BAND ||
873 ((mode_params->flags & VG_MODEFLAG_INTERLACED) &&
874 (mode_params->flags & VG_MODEFLAG_INT_MASK) == VG_MODEFLAG_INT_FLICKER) ||
875 (irq_ctl & DC3_IRQFILT_GFX_FILT_EN))
877 /* HIGH BANDWIDTH */
878 /* Set agressive watermarks and disallow forced low priority */
880 gcfg |= 0x0000BA01;
881 dcfg |= 0x000EA000;
882 acfg = 0x001A0201;
884 msr_value.low |= DC3_SPARE_DISABLE_CFIFO_HGO | DC3_SPARE_VFIFO_ARB_SELECT |
885 DC3_SPARE_WM_LPEN_OVRD;
887 else if ((mode_params->flags & VG_MODEFLAG_BANDWIDTHMASK) == VG_MODEFLAG_AVG_BAND)
889 /* AVERAGE BANDWIDTH */
890 /* Set average watermarks and allow small regions of forced low priority. */
892 gcfg |= 0x0000B601;
893 dcfg |= 0x00009000;
894 acfg = 0x00160001;
896 msr_value.low |= DC3_SPARE_DISABLE_CFIFO_HGO | DC3_SPARE_VFIFO_ARB_SELECT |
897 DC3_SPARE_WM_LPEN_OVRD;
899 /* SET THE NUMBER OF LOW PRIORITY LINES TO 1/2 THE TOTAL AVAILABLE */
901 temp = ((READ_REG32 (DC3_V_ACTIVE_TIMING) >> 16) & 0x7FF) + 1;
902 temp -= (READ_REG32 (DC3_V_SYNC_TIMING) & 0x7FF) + 1;
903 temp >>= 1;
904 if (temp > 127)
905 temp = 127;
907 acfg |= temp << 9;
909 else if ((mode_params->flags & VG_MODEFLAG_BANDWIDTHMASK) == VG_MODEFLAG_LOW_BAND)
911 /* LOW BANDWIDTH */
912 /* Set low watermarks and allow larger regions of forced low priority. */
914 gcfg |= 0x00009501;
915 dcfg |= 0x00008000;
916 acfg = 0x00150001;
918 msr_value.low |= DC3_SPARE_DISABLE_CFIFO_HGO | DC3_SPARE_VFIFO_ARB_SELECT |
919 DC3_SPARE_WM_LPEN_OVRD;
921 /* SET THE NUMBER OF LOW PRIORITY LINES TO 3/4 THE TOTAL AVAILABLE */
923 temp = ((READ_REG32 (DC3_V_ACTIVE_TIMING) >> 16) & 0x7FF) + 1;
924 temp -= (READ_REG32 (DC3_V_SYNC_TIMING) & 0x7FF) + 1;
925 temp = (temp * 3) >> 2;
926 if (temp > 127)
927 temp = 127;
929 acfg |= temp << 9;
931 else
933 /* LEGACY CHARACTERISTICS */
934 /* Arbitration from a single set of watermarks. */
936 gcfg |= 0x0000B601;
937 msr_value.low |= DC3_SPARE_DISABLE_VFIFO_WM | DC3_SPARE_DISABLE_INIT_VID_PRI;
938 acfg = 0;
941 msr_write64 (MSR_DEVICE_GEODELX_VG, DC3_SPARE_MSR, &msr_value);
943 /* ENABLE FLAT PANEL CENTERING */
944 /* For panel modes having a resolution smaller than the */
945 /* panel resolution, turn on data centering. */
947 if (mode_params->flags & VG_MODEFLAG_CENTERED)
948 dcfg |= DC3_DCFG_DCEN;
950 /* COMBINE AND SET TIMING VALUES */
952 temp = (mode_params->hactive - 1) | ((mode_params->htotal - 1) << 16);
953 WRITE_REG32(DC3_H_ACTIVE_TIMING, temp);
954 temp = (mode_params->hblankstart - 1) | ((mode_params->hblankend - 1) << 16);
955 WRITE_REG32(DC3_H_BLANK_TIMING, temp);
956 temp = (mode_params->hsyncstart - 1) | ((mode_params->hsyncend - 1) << 16);
957 WRITE_REG32(DC3_H_SYNC_TIMING, temp);
958 temp = (mode_params->vactive - 1) | ((mode_params->vtotal - 1) << 16);
959 WRITE_REG32(DC3_V_ACTIVE_TIMING, temp);
960 temp = (mode_params->vblankstart - 1) | ((mode_params->vblankend - 1) << 16);
961 WRITE_REG32(DC3_V_BLANK_TIMING, temp);
962 temp = (mode_params->vsyncstart - 1) | ((mode_params->vsyncend - 1) << 16);
963 WRITE_REG32(DC3_V_SYNC_TIMING, temp);
964 temp = (mode_params->vactive_even - 1) | ((mode_params->vtotal_even - 1) << 16);
965 WRITE_REG32(DC3_V_ACTIVE_EVEN, temp);
966 temp = (mode_params->vblankstart_even - 1) | ((mode_params->vblankend_even - 1) << 16);
967 WRITE_REG32(DC3_V_BLANK_EVEN, temp);
968 temp = (mode_params->vsyncstart_even - 1) | ((mode_params->vsyncend_even - 1) << 16);
969 WRITE_REG32(DC3_V_SYNC_EVEN, temp);
971 /* SET THE VIDEO REQUEST REGISTER */
973 WRITE_VID32 (DF_VIDEO_REQUEST, 0);
975 /* SET SOURCE DIMENSIONS */
977 WRITE_REG32 (DC3_FB_ACTIVE, ((starting_width - 1) << 16) |
978 (starting_height - 1));
980 /* SET SYNC POLARITIES */
982 temp = READ_VID32 (DF_DISPLAY_CONFIG);
984 temp &= ~(DF_DCFG_CRT_SYNC_SKW_MASK | DF_DCFG_PWR_SEQ_DLY_MASK |
985 DF_DCFG_CRT_HSYNC_POL | DF_DCFG_CRT_VSYNC_POL);
987 temp |= (DF_DCFG_CRT_SYNC_SKW_INIT |
988 DF_DCFG_PWR_SEQ_DLY_INIT |
989 DF_DCFG_GV_PAL_BYP);
991 if (mode_params->flags & VG_MODEFLAG_NEG_HSYNC)
992 temp |= DF_DCFG_CRT_HSYNC_POL;
993 if (mode_params->flags & VG_MODEFLAG_NEG_VSYNC)
994 temp |= DF_DCFG_CRT_VSYNC_POL;
996 WRITE_VID32 (DF_DISPLAY_CONFIG, temp);
998 WRITE_REG32 (DC3_DISPLAY_CFG, dcfg);
999 WRITE_REG32 (DC3_ARB_CFG, acfg);
1000 WRITE_REG32 (DC3_GENERAL_CFG, gcfg);
1002 /* RESTORE VALUE OF DC3_UNLOCK */
1004 WRITE_REG32(DC3_UNLOCK, unlock);
1006 return CIM_STATUS_OK;
1009 /*---------------------------------------------------------------------------
1010 * vg_set_bpp
1012 * This routine changes the display BPP on the fly. It is intended only to
1013 * switch between pixel depths of the same pixel size 24<->32 or 15<->16, NOT
1014 * between pixel depths of differing sizes 16<->32
1015 *---------------------------------------------------------------------------*/
1017 int vg_set_display_bpp (int bpp)
1019 unsigned long unlock, dcfg, bpp_mask;
1021 switch (bpp)
1023 case 8: bpp_mask = DC3_DCFG_DISP_MODE_8BPP; break;
1024 case 24: bpp_mask = DC3_DCFG_DISP_MODE_24BPP; break;
1025 case 32: bpp_mask = DC3_DCFG_DISP_MODE_32BPP; break;
1026 case 12: bpp_mask = DC3_DCFG_DISP_MODE_16BPP | DC3_DCFG_12BPP; break;
1027 case 15: bpp_mask = DC3_DCFG_DISP_MODE_16BPP | DC3_DCFG_15BPP; break;
1028 case 16: bpp_mask = DC3_DCFG_DISP_MODE_16BPP | DC3_DCFG_16BPP; break;
1029 default: return CIM_STATUS_INVALIDPARAMS;
1032 unlock = READ_REG32 (DC3_UNLOCK);
1033 dcfg = READ_REG32 (DC3_DISPLAY_CFG) & ~(DC3_DCFG_DISP_MODE_MASK | DC3_DCFG_16BPP_MODE_MASK);
1034 dcfg |= bpp_mask;
1036 WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
1037 WRITE_REG32 (DC3_DISPLAY_CFG, dcfg);
1038 WRITE_REG32 (DC3_UNLOCK, unlock);
1040 return CIM_STATUS_OK;
1043 /*---------------------------------------------------------------------------
1044 * vg_get_display_mode_index
1046 * This routine searches the Cimarron mode table for a mode that matches the
1047 * input parameters. If a match is found, the return value is the index into
1048 * the mode table. If no match is found, the return value is -1.
1049 *---------------------------------------------------------------------------*/
1051 int vg_get_display_mode_index (VG_QUERY_MODE *query)
1053 unsigned int mode;
1054 unsigned long hz_flag = 0xFFFFFFFF;
1055 unsigned long bpp_flag = 0xFFFFFFFF;
1056 unsigned long enc_flag = 0xFFFFFFFF;
1057 unsigned long tv_flag = 0;
1058 unsigned long interlaced = 0;
1059 unsigned long halfclock = 0;
1060 long minimum = 0x7FFFFFFF;
1061 long diff;
1062 int match = -1;
1064 if (!query || !query->query_flags)
1065 return -1;
1067 if (query->query_flags & VG_QUERYFLAG_REFRESH)
1069 /* SET FLAGS TO MATCH REFRESH RATE */
1071 if (query->hz == 56) hz_flag = VG_SUPPORTFLAG_56HZ;
1072 else if (query->hz == 60) hz_flag = VG_SUPPORTFLAG_60HZ;
1073 else if (query->hz == 70) hz_flag = VG_SUPPORTFLAG_70HZ;
1074 else if (query->hz == 72) hz_flag = VG_SUPPORTFLAG_72HZ;
1075 else if (query->hz == 75) hz_flag = VG_SUPPORTFLAG_75HZ;
1076 else if (query->hz == 85) hz_flag = VG_SUPPORTFLAG_85HZ;
1077 else if (query->hz == 90) hz_flag = VG_SUPPORTFLAG_90HZ;
1078 else if (query->hz == 100) hz_flag = VG_SUPPORTFLAG_100HZ;
1079 else hz_flag = 0;
1082 if (query->query_flags & VG_QUERYFLAG_BPP)
1084 /* SET BPP FLAGS TO LIMIT MODE SELECTION */
1086 if (query->bpp == 8) bpp_flag = VG_SUPPORTFLAG_8BPP;
1087 else if (query->bpp == 12) bpp_flag = VG_SUPPORTFLAG_12BPP;
1088 else if (query->bpp == 15) bpp_flag = VG_SUPPORTFLAG_15BPP;
1089 else if (query->bpp == 16) bpp_flag = VG_SUPPORTFLAG_16BPP;
1090 else if (query->bpp == 24) bpp_flag = VG_SUPPORTFLAG_24BPP;
1091 else if (query->bpp == 32) bpp_flag = VG_SUPPORTFLAG_32BPP;
1092 else bpp_flag = 0;
1095 if (query->query_flags & VG_QUERYFLAG_ENCODER)
1097 /* SET ENCODER FLAGS TO LIMIT MODE SELECTION */
1099 if (query->encoder == VG_ENCODER_ADV7171) enc_flag = VG_SUPPORTFLAG_ADV7171;
1100 else if (query->encoder == VG_ENCODER_SAA7127) enc_flag = VG_SUPPORTFLAG_SAA7127;
1101 else if (query->encoder == VG_ENCODER_FS454) enc_flag = VG_SUPPORTFLAG_FS454;
1102 else if (query->encoder == VG_ENCODER_ADV7300) enc_flag = VG_SUPPORTFLAG_ADV7300;
1103 else enc_flag = 0;
1106 if (query->query_flags & VG_QUERYFLAG_TVMODE)
1108 /* SET ENCODER FLAGS TO LIMIT MODE SELECTION */
1110 if (query->tvmode == VG_TVMODE_NTSC) tv_flag = VG_SUPPORTFLAG_NTSC;
1111 else if (query->tvmode == VG_TVMODE_PAL) tv_flag = VG_SUPPORTFLAG_PAL;
1112 else if (query->tvmode == VG_TVMODE_480P) tv_flag = VG_SUPPORTFLAG_480P;
1113 else if (query->tvmode == VG_TVMODE_720P) tv_flag = VG_SUPPORTFLAG_720P;
1114 else if (query->tvmode == VG_TVMODE_1080I) tv_flag = VG_SUPPORTFLAG_1080I;
1115 else if (query->tvmode == VG_TVMODE_6X4_NTSC) tv_flag = VG_SUPPORTFLAG_6X4_NTSC;
1116 else if (query->tvmode == VG_TVMODE_8X6_NTSC) tv_flag = VG_SUPPORTFLAG_8X6_NTSC;
1117 else if (query->tvmode == VG_TVMODE_10X7_NTSC) tv_flag = VG_SUPPORTFLAG_10X7_NTSC;
1118 else if (query->tvmode == VG_TVMODE_6X4_PAL) tv_flag = VG_SUPPORTFLAG_6X4_PAL;
1119 else if (query->tvmode == VG_TVMODE_8X6_PAL) tv_flag = VG_SUPPORTFLAG_8X6_PAL;
1120 else if (query->tvmode == VG_TVMODE_10X7_PAL) tv_flag = VG_SUPPORTFLAG_10X7_PAL;
1121 else tv_flag = 0xFFFFFFFF;
1124 /* SET APPROPRIATE TV AND VOP FLAGS */
1126 if (query->query_flags & VG_QUERYFLAG_INTERLACED)
1127 interlaced = query->interlaced ? VG_MODEFLAG_INTERLACED : 0;
1128 if (query->query_flags & VG_QUERYFLAG_HALFCLOCK)
1129 halfclock = query->halfclock ? VG_MODEFLAG_HALFCLOCK : 0;
1131 /* CHECK FOR INVALID REQUEST */
1133 if (!hz_flag || !bpp_flag || !enc_flag || tv_flag == 0xFFFFFFFF)
1134 return -1;
1136 /* LOOP THROUGH THE AVAILABLE MODES TO FIND A MATCH */
1138 for (mode = 0; mode < NUM_CIMARRON_DISPLAY_MODES; mode++)
1140 if ( (!(query->query_flags & VG_QUERYFLAG_PANEL) ||
1141 (CimarronDisplayModes[mode].internal_flags & VG_SUPPORTFLAG_PANEL)) &&
1142 (!(query->query_flags & VG_QUERYFLAG_TVOUT) ||
1143 (CimarronDisplayModes[mode].internal_flags & VG_SUPPORTFLAG_TVOUT)) &&
1144 (!(query->query_flags & VG_QUERYFLAG_INTERLACED) ||
1145 (CimarronDisplayModes[mode].flags & VG_MODEFLAG_INTERLACED) == interlaced) &&
1146 (!(query->query_flags & VG_QUERYFLAG_HALFCLOCK) ||
1147 (CimarronDisplayModes[mode].flags & VG_MODEFLAG_HALFCLOCK) == halfclock) &&
1148 (!(query->query_flags & VG_QUERYFLAG_PANELWIDTH) ||
1149 (CimarronDisplayModes[mode].panel_width == query->panel_width)) &&
1150 (!(query->query_flags & VG_QUERYFLAG_PANELHEIGHT) ||
1151 (CimarronDisplayModes[mode].panel_height == query->panel_height)) &&
1152 (!(query->query_flags & VG_QUERYFLAG_ACTIVEWIDTH) ||
1153 (CimarronDisplayModes[mode].hactive == query->active_width)) &&
1154 (!(query->query_flags & VG_QUERYFLAG_ACTIVEHEIGHT) ||
1155 (CimarronDisplayModes[mode].vactive == query->active_height)) &&
1156 (!(query->query_flags & VG_QUERYFLAG_TOTALWIDTH) ||
1157 (CimarronDisplayModes[mode].htotal == query->total_width)) &&
1158 (!(query->query_flags & VG_QUERYFLAG_TOTALHEIGHT) ||
1159 (CimarronDisplayModes[mode].vtotal == query->total_height)) &&
1160 (!(query->query_flags & VG_QUERYFLAG_BPP) ||
1161 (CimarronDisplayModes[mode].internal_flags & bpp_flag)) &&
1162 (!(query->query_flags & VG_QUERYFLAG_REFRESH) ||
1163 (CimarronDisplayModes[mode].internal_flags & hz_flag)) &&
1164 (!(query->query_flags & VG_QUERYFLAG_ENCODER) ||
1165 (CimarronDisplayModes[mode].internal_flags & enc_flag)) &&
1166 (!(query->query_flags & VG_QUERYFLAG_TVMODE) ||
1167 ((CimarronDisplayModes[mode].internal_flags & VG_SUPPORTFLAG_TVMODEMASK) == tv_flag)) &&
1168 (!(query->query_flags & VG_QUERYFLAG_PIXELCLOCK) ||
1169 (CimarronDisplayModes[mode].frequency == query->frequency)))
1171 /* ALLOW SEARCHING BASED ON AN APPROXIMATE PIXEL CLOCK */
1173 if (query->query_flags & VG_QUERYFLAG_PIXELCLOCK_APPROX)
1175 diff = query->frequency - CimarronDisplayModes[mode].frequency;
1176 if (diff < 0)
1177 diff = -diff;
1179 if (diff < minimum)
1181 minimum = diff;
1182 match = mode;
1185 else
1187 match = mode;
1188 break;
1193 /* RETURN DISPLAY MODE INDEX */
1195 return match;
1198 /*---------------------------------------------------------------------------
1199 * vg_get_display_mode_information
1201 * This routine retrieves all information for a display mode contained
1202 * within Cimarron's mode tables.
1203 *---------------------------------------------------------------------------*/
1205 int vg_get_display_mode_information (unsigned int index, VG_DISPLAY_MODE *vg_mode)
1207 if (index > NUM_CIMARRON_DISPLAY_MODES)
1208 return CIM_STATUS_INVALIDPARAMS;
1210 *vg_mode = CimarronDisplayModes[index];
1211 return CIM_STATUS_OK;
1214 /*---------------------------------------------------------------------------
1215 * vg_get_display_mode_count
1217 * This routine retrieves the count of all predefined Cimarron modes.
1218 *---------------------------------------------------------------------------*/
1220 int vg_get_display_mode_count (void)
1222 return NUM_CIMARRON_DISPLAY_MODES;
1225 /*---------------------------------------------------------------------------
1226 * vg_get_current_display_mode
1228 * This routine retrieves the settings for the current display. This includes
1229 * any panel settings.
1230 *---------------------------------------------------------------------------*/
1232 int vg_get_current_display_mode (VG_DISPLAY_MODE *current_display, int *bpp)
1234 Q_WORD msr_value;
1235 unsigned long active, blank, sync;
1236 unsigned long i, m, n, p;
1237 unsigned long genlk, irq, temp;
1238 unsigned long flags = 0;
1239 unsigned long iflags = 0;
1241 /* READ THE CURRENT HORIZONTAL DISPLAY TIMINGS */
1243 active = READ_REG32 (DC3_H_ACTIVE_TIMING);
1244 blank = READ_REG32 (DC3_H_BLANK_TIMING);
1245 sync = READ_REG32 (DC3_H_SYNC_TIMING);
1247 current_display->hactive = (active & 0xFFF) + 1;
1248 current_display->hblankstart = (blank & 0xFFF) + 1;
1249 current_display->hsyncstart = (sync & 0xFFF) + 1;
1251 current_display->htotal = ((active >> 16) & 0xFFF) + 1;
1252 current_display->hblankend = ((blank >> 16) & 0xFFF) + 1;
1253 current_display->hsyncend = ((sync >> 16) & 0xFFF) + 1;
1255 /* READ THE CURRENT VERTICAL DISPLAY TIMINGS */
1257 active = READ_REG32 (DC3_V_ACTIVE_TIMING);
1258 blank = READ_REG32 (DC3_V_BLANK_TIMING);
1259 sync = READ_REG32 (DC3_V_SYNC_TIMING);
1261 current_display->vactive = (active & 0x7FF) + 1;
1262 current_display->vblankstart = (blank & 0x7FF) + 1;
1263 current_display->vsyncstart = (sync & 0x7FF) + 1;
1265 current_display->vtotal = ((active >> 16) & 0x7FF) + 1;
1266 current_display->vblankend = ((blank >> 16) & 0x7FF) + 1;
1267 current_display->vsyncend = ((sync >> 16) & 0x7FF) + 1;
1269 /* READ THE CURRENT EVEN FIELD VERTICAL DISPLAY TIMINGS */
1271 active = READ_REG32 (DC3_V_ACTIVE_EVEN);
1272 blank = READ_REG32 (DC3_V_BLANK_EVEN);
1273 sync = READ_REG32 (DC3_V_SYNC_EVEN);
1275 current_display->vactive_even = (active & 0x7FF) + 1;
1276 current_display->vblankstart_even = (blank & 0x7FF) + 1;
1277 current_display->vsyncstart_even = (sync & 0x7FF) + 1;
1279 current_display->vtotal_even = ((active >> 16) & 0x7FF) + 1;
1280 current_display->vblankend_even = ((blank >> 16) & 0x7FF) + 1;
1281 current_display->vsyncend_even = ((sync >> 16) & 0x7FF) + 1;
1283 /* READ THE CURRENT SOURCE DIMENSIONS */
1284 /* The DC3_FB_ACTIVE register is only used when scaling is enabled. */
1285 /* As the goal of this routine is to return a structure that can be */
1286 /* passed to vg_set_custom_mode to exactly recreate the current mode, */
1287 /* we must check the status of the scaler/filter. */
1289 genlk = READ_REG32 (DC3_GENLK_CTL);
1290 irq = READ_REG32 (DC3_IRQ_FILT_CTL);
1291 temp = READ_REG32 (DC3_FB_ACTIVE);
1293 current_display->src_height = (temp & 0xFFFF) + 1;
1294 current_display->src_width = ((temp >> 16) & 0xFFF8) + 8;
1296 /* READ THE CURRENT PANEL CONFIGURATION */
1297 /* We can only infer some of the panel settings based on hardware */
1298 /* (like when panning). We will instead assume that the current */
1299 /* mode was set using Cimarron and use the panel variables inside */
1300 /* Cimarron when returning the current mode information. */
1302 if (vg3_panel_enable)
1304 Q_WORD msr_value;
1306 flags |= VG_MODEFLAG_PANELOUT;
1308 current_display->panel_width = vg3_panel_width;
1309 current_display->panel_height = vg3_panel_height;
1310 current_display->mode_width = vg3_mode_width;
1311 current_display->mode_height = vg3_mode_height;
1313 if (READ_REG32 (DC3_DISPLAY_CFG) & DC3_DCFG_DCEN)
1314 flags |= VG_MODEFLAG_CENTERED;
1316 msr_read64 (MSR_DEVICE_GEODELX_DF, DF_MSR_PAD_SEL, &msr_value);
1317 current_display->panel_tim1 = READ_VID32 (DF_VIDEO_PANEL_TIM1);
1318 current_display->panel_tim2 = READ_VID32 (DF_VIDEO_PANEL_TIM2);
1319 current_display->panel_dither_ctl = READ_VID32 (DF_DITHER_CONTROL);
1320 current_display->panel_pad_sel_low = msr_value.low;
1321 current_display->panel_pad_sel_high = msr_value.high;
1324 /* SET MISCELLANEOUS MODE FLAGS */
1326 /* INTERLACED */
1328 if (irq & DC3_IRQFILT_INTL_EN)
1330 flags |= VG_MODEFLAG_INTERLACED;
1331 if (irq & DC3_IRQFILT_INTL_ADDR)
1332 flags |= VG_MODEFLAG_INT_ADDRESS;
1333 else if (genlk & DC3_GC_FLICKER_FILTER_ENABLE)
1334 flags |= VG_MODEFLAG_INT_FLICKER;
1335 else
1336 flags |= VG_MODEFLAG_INT_LINEDOUBLE;
1339 /* POLARITIES */
1341 temp = READ_VID32 (DF_DISPLAY_CONFIG);
1342 if (temp & DF_DCFG_CRT_HSYNC_POL)
1343 flags |= VG_MODEFLAG_NEG_HSYNC;
1344 if (temp & DF_DCFG_CRT_VSYNC_POL)
1345 flags |= VG_MODEFLAG_NEG_VSYNC;
1347 /* BPP */
1349 temp = READ_REG32 (DC3_DISPLAY_CFG) & DC3_DCFG_DISP_MODE_MASK;
1350 if (temp == DC3_DCFG_DISP_MODE_8BPP)
1352 iflags |= VG_SUPPORTFLAG_8BPP;
1353 *bpp = 8;
1355 else if (temp == DC3_DCFG_DISP_MODE_24BPP)
1357 iflags |= VG_SUPPORTFLAG_24BPP;
1358 *bpp = 24;
1360 else if (temp == DC3_DCFG_DISP_MODE_32BPP)
1362 iflags |= VG_SUPPORTFLAG_32BPP;
1363 *bpp = 32;
1365 else if (temp == DC3_DCFG_DISP_MODE_16BPP)
1367 temp = READ_REG32 (DC3_DISPLAY_CFG) & DC3_DCFG_16BPP_MODE_MASK;
1368 if (temp == DC3_DCFG_16BPP)
1370 iflags |= VG_SUPPORTFLAG_16BPP;
1371 *bpp = 16;
1373 else if (temp == DC3_DCFG_15BPP)
1375 iflags |= VG_SUPPORTFLAG_15BPP;
1376 *bpp = 15;
1378 else if (temp == DC3_DCFG_12BPP)
1380 iflags |= VG_SUPPORTFLAG_12BPP;
1381 *bpp = 12;
1385 /* TV RELATED FLAGS */
1387 msr_read64 (MSR_DEVICE_GEODELX_DF, DF_MSR_PAD_SEL, &msr_value);
1388 if (msr_value.high & DF_INVERT_VOP_CLOCK)
1389 flags |= VG_MODEFLAG_TVOUT;
1391 /* LINEAR PITCH */
1393 temp = (READ_REG32 (DC3_GFX_PITCH) & 0x0000FFFF) << 3;
1394 if (temp != 1024 && temp != 2048 && temp != 4096 && temp != 8192)
1395 flags |= VG_MODEFLAG_LINEARPITCH;
1397 /* SIMULTANEOUS CRT/FP */
1399 msr_read64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
1400 if (msr_value.low & DF_SIMULTANEOUS_CRT_FP)
1401 flags |= VG_MODEFLAG_CRT_AND_FP;
1403 /* SET PLL-RELATED FLAGS */
1405 msr_read64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DOTPLL, &msr_value);
1406 if (msr_value.high & GLCP_DOTPLL_DIV4)
1407 flags |= VG_MODEFLAG_QVGA;
1408 if (msr_value.low & GLCP_DOTPLL_HALFPIX)
1409 flags |= VG_MODEFLAG_HALFCLOCK;
1411 /* SAVE THE FLAGS IN THE MODE STRUCTURE */
1413 current_display->internal_flags = iflags;
1414 current_display->flags = flags;
1416 /* READ PIXEL CLOCK FREQUENCY */
1417 /* We first search for an exact match. If none is found, we try */
1418 /* a fixed point calculation and return CIM_STATUS_INEXACTMATCH. */
1420 for (i = 0; i < NUM_CIMARRON_PLL_FREQUENCIES; i++)
1422 if (CimarronPLLFrequencies[i].pll_value == msr_value.high)
1423 break;
1426 if (i == NUM_CIMARRON_PLL_FREQUENCIES)
1428 /* ATTEMPT 16.16 CALCULATION */
1429 /* We assume the input frequency is 48 MHz, which is represented */
1430 /* in 16.16 fixed point as 0x300000. The PLL calculation is: */
1431 /* n + 1 */
1432 /* Fout = 48.000 * -------------- */
1433 /* m + 1 * p + 1 */
1435 p = msr_value.high & 0xF;
1436 n = (msr_value.high >> 4) & 0xFF;
1437 m = (msr_value.high >> 12) & 0x7;
1438 current_display->frequency = (0x300000 * (n + 1)) / ((p + 1) * (m + 1));
1440 return CIM_STATUS_INEXACTMATCH;
1443 current_display->frequency = CimarronPLLFrequencies[i].frequency;
1445 /* NOW SEARCH FOR AN IDENTICAL MODE */
1446 /* This is just to inform the user that an exact match was found. */
1447 /* With an exact match, the user can use the refresh rate flag that */
1448 /* is returned in the VG_DISPLAY_MODE structure. */
1450 for (i = 0; i < NUM_CIMARRON_DISPLAY_MODES; i++)
1452 if ((CimarronDisplayModes[i].flags & current_display->flags) &&
1453 CimarronDisplayModes[i].frequency == current_display->frequency &&
1454 CimarronDisplayModes[i].hactive == current_display->hactive &&
1455 CimarronDisplayModes[i].hblankstart == current_display->hblankstart &&
1456 CimarronDisplayModes[i].hsyncstart == current_display->hsyncstart &&
1457 CimarronDisplayModes[i].hsyncend == current_display->hsyncend &&
1458 CimarronDisplayModes[i].hblankend == current_display->hblankend &&
1459 CimarronDisplayModes[i].htotal == current_display->htotal &&
1460 CimarronDisplayModes[i].vactive == current_display->vactive &&
1461 CimarronDisplayModes[i].vblankstart == current_display->vblankstart &&
1462 CimarronDisplayModes[i].vsyncstart == current_display->vsyncstart &&
1463 CimarronDisplayModes[i].vsyncend == current_display->vsyncend &&
1464 CimarronDisplayModes[i].vblankend == current_display->vblankend &&
1465 CimarronDisplayModes[i].vtotal == current_display->vtotal)
1467 break;
1471 if (i == NUM_CIMARRON_DISPLAY_MODES)
1472 return CIM_STATUS_INEXACTMATCH;
1474 current_display->internal_flags |= (CimarronDisplayModes[i].internal_flags & VG_SUPPORTFLAG_HZMASK);
1475 return CIM_STATUS_OK;
1478 /*---------------------------------------------------------------------------
1479 * vg_set_scaler_filter_coefficients
1481 * This routine sets the vertical and horizontal filter coefficients for
1482 * graphics scaling. If either of the input arrays is specified as NULL, a
1483 * set of default coeffecients will be used.
1484 *---------------------------------------------------------------------------*/
1486 int vg_set_scaler_filter_coefficients (long h_taps[][5], long v_taps[][3])
1488 unsigned long irqfilt, i;
1489 unsigned long temp0, temp1;
1490 unsigned long lock;
1492 /* ENABLE ACCESS TO THE HORIZONTAL COEFFICIENTS */
1494 irqfilt = READ_REG32 (DC3_IRQ_FILT_CTL);
1495 irqfilt |= DC3_IRQFILT_H_FILT_SEL;
1497 /* UNLOCK THE COEFFICIENT REGISTERS */
1499 lock = READ_REG32 (DC3_UNLOCK);
1500 WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
1502 /* WRITE COEFFICIENTS */
1503 /* Coefficient indexes do not auto-increment, so we must */
1504 /* write the address for every phase */
1506 for (i = 0; i < 256; i++)
1508 WRITE_REG32 (DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
1510 if (!h_taps)
1512 temp0 = CimarronHorizontalGraphicsFilter[i][0];
1513 temp1 = CimarronHorizontalGraphicsFilter[i][1];
1515 else
1517 temp0 = ((unsigned long)h_taps[i][0] & 0x3FF) |
1518 (((unsigned long)h_taps[i][1] & 0x3FF) << 10) |
1519 (((unsigned long)h_taps[i][2] & 0x3FF) << 20);
1521 temp1 = ((unsigned long)h_taps[i][3] & 0x3FF) |
1522 (((unsigned long)h_taps[i][4] & 0x3FF) << 10);
1524 WRITE_REG32 (DC3_FILT_COEFF1, temp0);
1525 WRITE_REG32 (DC3_FILT_COEFF2, temp1);
1528 /* ENABLE ACCESS TO THE VERTICAL COEFFICIENTS */
1530 irqfilt &= ~DC3_IRQFILT_H_FILT_SEL;
1532 /* WRITE COEFFICIENTS */
1534 for (i = 0; i < 256; i++)
1536 WRITE_REG32 (DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
1538 if (!v_taps)
1540 temp0 = CimarronVerticalGraphicsFilter[i];
1542 else
1544 temp0 = ((unsigned long)v_taps[i][0] & 0x3FF) |
1545 (((unsigned long)v_taps[i][1] & 0x3FF) << 10) |
1546 (((unsigned long)v_taps[i][2] & 0x3FF) << 20);
1549 WRITE_REG32 (DC3_FILT_COEFF1, temp0);
1552 WRITE_REG32 (DC3_UNLOCK, lock);
1554 return CIM_STATUS_OK;
1557 /*---------------------------------------------------------------------------
1558 * vg_configure_flicker_filter
1560 * This routine updates the VG flicker filter settings when in an interlaced
1561 * mode. Note that flicker filtering is enabled inside a mode set. This routine
1562 * is provided to change from the default flicker filter setting of
1563 * 1/4, 1/2, 1/4.
1564 *---------------------------------------------------------------------------*/
1566 int vg_configure_flicker_filter (unsigned long flicker_strength, int flicker_alpha)
1568 unsigned long unlock;
1569 unsigned long genlk_ctl;
1571 /* CHECK FOR VALID FLICKER SETTING */
1573 if (flicker_strength != VG_FLICKER_FILTER_NONE &&
1574 flicker_strength != VG_FLICKER_FILTER_1_16 &&
1575 flicker_strength != VG_FLICKER_FILTER_1_8 &&
1576 flicker_strength != VG_FLICKER_FILTER_1_4 &&
1577 flicker_strength != VG_FLICKER_FILTER_5_16)
1579 return CIM_STATUS_INVALIDPARAMS;
1582 unlock = READ_REG32 (DC3_UNLOCK);
1583 genlk_ctl = READ_REG32 (DC3_GENLK_CTL) & ~(DC3_GC_FLICKER_FILTER_MASK | DC3_GC_ALPHA_FLICK_ENABLE);
1584 genlk_ctl |= flicker_strength;
1585 if (flicker_alpha)
1586 genlk_ctl |= DC3_GC_ALPHA_FLICK_ENABLE;
1588 WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
1589 WRITE_REG32 (DC3_GENLK_CTL, genlk_ctl);
1590 WRITE_REG32 (DC3_UNLOCK, unlock);
1592 return CIM_STATUS_OK;
1595 /*---------------------------------------------------------------------------
1596 * vg_set_clock_frequency
1598 * This routine sets the frequency of the dot clock. The input to this routine
1599 * is a 16.16 fraction. If an exact match is not found, this routine will program
1600 * the closest available frequency and return CIM_STATUS_INEXACTMATCH.
1601 *---------------------------------------------------------------------------*/
1603 int vg_set_clock_frequency (unsigned long frequency, unsigned long pll_flags)
1605 Q_WORD msr_value;
1606 unsigned long timeout;
1607 unsigned long index = 0;
1608 unsigned long unlock, i;
1609 unsigned long pll_high, pll_low;
1610 long diff, min = 0;
1612 /* FIND THE REGISTER VALUES FOR THE DESIRED FREQUENCY */
1613 /* Search the table for the closest frequency (16.16 format). */
1614 /* This search is skipped if the user is manually specifying */
1615 /* the MSR value. */
1617 pll_low = 0;
1618 if (!(pll_flags & VG_PLL_MANUAL))
1620 min = (long)CimarronPLLFrequencies[0].frequency - (long)frequency;
1621 if (min < 0L)
1622 min = -min;
1624 for (i = 1; i < NUM_CIMARRON_PLL_FREQUENCIES; i++)
1626 diff = (long)CimarronPLLFrequencies[i].frequency - (long)frequency;
1627 if (diff < 0L)
1628 diff = -diff;
1630 if (diff < min)
1632 min = diff;
1633 index = i;
1637 pll_high = CimarronPLLFrequencies[index].pll_value & 0x00007FFF;
1639 else
1641 pll_high = frequency;
1644 if (pll_flags & VG_PLL_DIVIDE_BY_2)
1645 pll_low |= GLCP_DOTPLL_HALFPIX;
1646 if (pll_flags & VG_PLL_DIVIDE_BY_4)
1647 pll_high |= GLCP_DOTPLL_DIV4;
1648 if (pll_flags & VG_PLL_BYPASS)
1649 pll_low |= GLCP_DOTPLL_BYPASS;
1650 if (pll_flags & VG_PLL_VIP_CLOCK)
1651 pll_high |= GLCP_DOTPLL_VIPCLK;
1653 /* VERIFY THAT WE ARE NOT WRITING WHAT IS ALREADY IN THE REGISTERS */
1654 /* The Dot PLL reset bit is tied to VDD for flat panels. This can */
1655 /* cause a brief drop in flat panel power, which can cause serious */
1656 /* glitches on some panels. */
1658 msr_read64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DOTPLL, &msr_value);
1660 if ((msr_value.low & GLCP_DOTPLL_LOCK) &&
1661 ((msr_value.low & (GLCP_DOTPLL_HALFPIX | GLCP_DOTPLL_BYPASS)) == pll_low) &&
1662 (msr_value.high == pll_high))
1664 return CIM_STATUS_OK;
1667 /* PROGRAM THE SETTINGS WITH THE RESET BIT SET */
1668 /* Clear the bypass bit to ensure that the programmed */
1669 /* M, N and P values are being used. */
1671 msr_value.high = pll_high;
1672 msr_value.low &= ~(GLCP_DOTPLL_BYPASS | GLCP_DOTPLL_HALFPIX);
1673 msr_value.low |= (pll_low | 0x00000001);
1674 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DOTPLL, &msr_value);
1676 /* WAIT FOR THE LOCK BIT */
1677 /* The PLL spec states that the PLL may take up to 100 us to */
1678 /* properly lock. Furthermore, the lock signal is not 100% */
1679 /* reliable. To address this, we add a hefty delay followed */
1680 /* by a polling loop that times out after a 1000 reads. */
1682 unlock = READ_REG32 (DC3_UNLOCK);
1683 for (timeout = 0; timeout < 1280; timeout++)
1684 WRITE_REG32 (DC3_UNLOCK, unlock);
1686 for (timeout = 0; timeout < 1000; timeout++)
1688 msr_read64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DOTPLL, &msr_value);
1689 if (msr_value.low & GLCP_DOTPLL_LOCK)
1690 break;
1693 /* CLEAR THE RESET BIT */
1695 msr_value.low &= 0xFFFFFFFE;
1696 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DOTPLL, &msr_value);
1698 /* DID THE PLL SUCCESSFULLY LOCK? */
1700 if (!(msr_value.low & GLCP_DOTPLL_LOCK))
1701 return CIM_STATUS_NOLOCK;
1703 /* RETURN THE APPROPRIATE CODE */
1705 if (min == 0)
1706 return CIM_STATUS_OK;
1707 else
1708 return CIM_STATUS_INEXACTMATCH;
1711 /*---------------------------------------------------------------------------
1712 * vg_set_border_color
1714 * This routine sets the color used as the border in centered panel modes.
1715 *---------------------------------------------------------------------------*/
1717 int vg_set_border_color (unsigned long border_color)
1719 unsigned long lock = READ_REG32 (DC3_UNLOCK);
1721 WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
1722 WRITE_REG32 (DC3_PAL_ADDRESS, 0x104);
1723 WRITE_REG32 (DC3_PAL_DATA, border_color);
1724 WRITE_REG32 (DC3_UNLOCK, lock);
1726 return CIM_STATUS_OK;
1729 /*---------------------------------------------------------------------------
1730 * vg_set_cursor_enable
1732 * This routine enables or disables the hardware cursor. This routine should
1733 * only be called after the hardware cursor has been completely configured.
1734 *---------------------------------------------------------------------------*/
1736 int vg_set_cursor_enable(int enable)
1738 unsigned long unlock, gcfg;
1740 /* SET OR CLEAR CURSOR ENABLE BIT */
1742 unlock = READ_REG32(DC3_UNLOCK);
1743 gcfg = READ_REG32(DC3_GENERAL_CFG);
1744 if (enable) gcfg |= DC3_GCFG_CURE;
1745 else gcfg &= ~(DC3_GCFG_CURE);
1747 /* WRITE NEW REGISTER VALUE */
1749 WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
1750 WRITE_REG32 (DC3_GENERAL_CFG, gcfg);
1751 WRITE_REG32 (DC3_UNLOCK, unlock);
1753 return CIM_STATUS_OK;
1756 /*---------------------------------------------------------------------------
1757 * vg_set_mono_cursor_colors
1759 * This routine sets the colors of the hardware monochrome cursor.
1760 *---------------------------------------------------------------------------*/
1762 int vg_set_mono_cursor_colors (unsigned long bkcolor, unsigned long fgcolor)
1764 unsigned long lock = READ_REG32 (DC3_UNLOCK);
1766 /* SET CURSOR COLORS */
1768 WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
1769 WRITE_REG32 (DC3_PAL_ADDRESS, 0x100);
1770 WRITE_REG32 (DC3_PAL_DATA, bkcolor);
1771 WRITE_REG32 (DC3_PAL_DATA, fgcolor);
1772 WRITE_REG32 (DC3_UNLOCK, lock);
1774 return CIM_STATUS_OK;
1777 /*---------------------------------------------------------------------------
1778 * vg_set_cursor_position
1780 * This routine sets the position of the hardware cursor. The cursor hotspots
1781 * and memory offset must have been specified in an earlier call to
1782 * a vg_set_cursor_shape_XX routine. The coordinates passed to this routine
1783 * generally specify the focal point of the cursor, NOT the upper left coordinate of
1784 * the cursor pattern. However, for operating systems that do not include a hotspot
1785 * the input parameters may be negative.
1786 *---------------------------------------------------------------------------*/
1788 int vg_set_cursor_position (long xpos, long ypos, VG_PANNING_COORDINATES *panning)
1790 unsigned long unlock, memoffset;
1791 unsigned long gcfg;
1792 long x, xoffset;
1793 long y, yoffset;
1795 memoffset = vg3_cursor_offset;
1796 x = xpos - (long) vg3_x_hotspot;
1797 y = ypos - (long) vg3_y_hotspot;
1799 /* HANDLE NEGATIVE COORDINATES */
1800 /* This routine supports operating systems that use negative */
1801 /* coordinates, instead of positive coordinates with an appropriate */
1802 /* hotspot. */
1804 if (xpos < 0) xpos = 0;
1805 if (ypos < 0) ypos = 0;
1807 if (x < -63) return CIM_STATUS_INVALIDPARAMS;
1808 if (y < -63) return CIM_STATUS_INVALIDPARAMS;
1810 if (vg3_panel_enable)
1812 if ((vg3_mode_width > vg3_panel_width) || (vg3_mode_height > vg3_panel_height))
1814 vg_pan_desktop (xpos, ypos, panning);
1815 x = x - (unsigned short)vg3_delta_x;
1816 y = y - (unsigned short)vg3_delta_y;
1818 else
1820 panning->start_x = 0;
1821 panning->start_y = 0;
1822 panning->start_updated = 0;
1826 /* ADJUST OFFSETS */
1827 /* Cursor movement and panning work as follows: The cursor position */
1828 /* refers to where the hotspot of the cursor is located. However, for */
1829 /* non-zero hotspots, the cursor buffer actually begins before the */
1830 /* specified position. */
1832 if (x < 0) { xoffset = -x; x = 0; }
1833 else { xoffset = 0; }
1834 if (y < 0) { yoffset = -y; y = 0; }
1835 else { yoffset = 0; }
1837 if (vg3_color_cursor) memoffset += (unsigned long) yoffset * 192;
1838 else memoffset += (unsigned long) yoffset << 4;
1840 /* SET COLOR CURSOR BIT */
1842 gcfg = READ_REG32(DC3_GENERAL_CFG);
1843 if (vg3_color_cursor)
1844 gcfg |= DC3_GCFG_CLR_CUR;
1845 else
1846 gcfg &= ~DC3_GCFG_CLR_CUR;
1848 /* SET CURSOR POSITION */
1850 unlock = READ_REG32(DC3_UNLOCK);
1851 WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
1852 WRITE_REG32 (DC3_CURS_ST_OFFSET, memoffset);
1853 WRITE_REG32 (DC3_GENERAL_CFG, gcfg);
1854 WRITE_REG32 (DC3_CURSOR_X, (unsigned long) x |
1855 (((unsigned long) xoffset) << 11));
1856 WRITE_REG32 (DC3_CURSOR_Y, (unsigned long) y |
1857 (((unsigned long) yoffset) << 11));
1858 WRITE_REG32 (DC3_UNLOCK, unlock);
1860 return CIM_STATUS_OK;
1863 /*---------------------------------------------------------------------------
1864 * vg_set_mono_cursor_shape32
1866 * This routine loads 32x32 cursor data into the cursor buffer in graphics memory.
1867 * The outside of the GeodeLX cursor buffer is padded with transparency.
1868 *---------------------------------------------------------------------------*/
1870 int vg_set_mono_cursor_shape32 (unsigned long memoffset, unsigned long *andmask,
1871 unsigned long *xormask, unsigned long x_hotspot, unsigned long y_hotspot)
1873 int i;
1875 /* SAVE THE CURSOR OFFSET AND HOTSPOTS */
1876 /* These are reused later when updating the cursor position, panning */
1877 /* and clipping the cursor pointer. */
1879 vg3_x_hotspot = x_hotspot;
1880 vg3_y_hotspot = y_hotspot;
1881 vg3_cursor_offset = memoffset;
1882 vg3_color_cursor = 0;
1884 for (i = 0; i < 32; i++)
1886 /* EVEN QWORDS CONTAIN THE AND MASK */
1888 WRITE_FB32 (memoffset, 0xFFFFFFFF);
1889 WRITE_FB32 (memoffset + 4, andmask[i]);
1891 /* ODD QWORDS CONTAIN THE XOR MASK */
1893 WRITE_FB32 (memoffset + 8, 0x00000000);
1894 WRITE_FB32 (memoffset + 12, xormask[i]);
1896 memoffset += 16;
1899 /* FILL THE LOWER HALF OF THE BUFFER WITH TRANSPARENT PIXELS */
1901 for (i = 0; i < 32; i++)
1903 WRITE_FB32 (memoffset, 0xFFFFFFFF);
1904 WRITE_FB32 (memoffset + 4, 0xFFFFFFFF);
1905 WRITE_FB32 (memoffset + 8, 0x00000000);
1906 WRITE_FB32 (memoffset + 12, 0x00000000);
1908 memoffset += 16;
1911 return CIM_STATUS_OK;
1914 /*---------------------------------------------------------------------------
1915 * vg_set_mono_cursor_shape64
1917 * This routine loads 64x64 cursor data into the cursor buffer in graphics memory.
1918 *---------------------------------------------------------------------------*/
1920 int vg_set_mono_cursor_shape64 (unsigned long memoffset, unsigned long *andmask,
1921 unsigned long *xormask, unsigned long x_hotspot, unsigned long y_hotspot)
1923 int i;
1925 /* SAVE THE CURSOR OFFSET AND HOTSPOTS */
1926 /* These are reused later when updating the cursor position, panning */
1927 /* and clipping the cursor pointer. */
1929 vg3_x_hotspot = x_hotspot;
1930 vg3_y_hotspot = y_hotspot;
1931 vg3_cursor_offset = memoffset;
1932 vg3_color_cursor = 0;
1934 for (i = 0; i < 128; i += 2)
1936 /* EVEN QWORDS CONTAIN THE AND MASK */
1937 /* We invert the dwords to prevent the calling */
1938 /* application from having to think in terms of Qwords. */
1939 /* The hardware data order is actually 63:0, or 31:0 of */
1940 /* the second dword followed by 31:0 of the first dword. */
1942 WRITE_FB32 (memoffset, andmask[i + 1]);
1943 WRITE_FB32 (memoffset + 4, andmask[i]);
1945 /* ODD QWORDS CONTAIN THE XOR MASK */
1947 WRITE_FB32 (memoffset + 8, xormask[i + 1]);
1948 WRITE_FB32 (memoffset + 12, xormask[i]);
1950 memoffset += 16;
1953 return CIM_STATUS_OK;
1956 /*---------------------------------------------------------------------------
1957 * vg_set_color_cursor_shape
1959 * This routine loads 8:8:8:8 cursor data into the color cursor buffer.
1960 *---------------------------------------------------------------------------*/
1962 int vg_set_color_cursor_shape (unsigned long memoffset, unsigned char *data,
1963 unsigned long width, unsigned long height, long pitch,
1964 unsigned long x_hotspot, unsigned long y_hotspot)
1966 unsigned long y;
1968 /* SAVE THE CURSOR OFFSET AND HOTSPOTS */
1969 /* These are reused later when updating the cursor position, panning */
1970 /* and clipping the cursor pointer. */
1972 vg3_x_hotspot = x_hotspot;
1973 vg3_y_hotspot = y_hotspot;
1974 vg3_cursor_offset = memoffset;
1975 vg3_color_cursor = 1;
1977 /* WRITE THE CURSOR DATA */
1978 /* The outside edges of the color cursor are filled with transparency */
1979 /* The cursor buffer dimensions are 48x64. */
1981 for (y = 0; y < height; y++)
1983 /* WRITE THE ACTIVE AND TRANSPARENT DATA */
1984 /* We implement this as a macro in our dedication to squeaking */
1985 /* every ounce of performance out of our code... */
1987 WRITE_FB_STRING32 (memoffset, data, width);
1988 WRITE_FB_CONSTANT ((memoffset + (width << 2)), 0, (48 - width));
1990 /* INCREMENT PAST THE LINE */
1992 memoffset += 192;
1993 data += pitch;
1996 /* WRITE THE EXTRA TRANSPARENT LINES */
1997 /* Write the lines in one big bulk setting. */
1999 WRITE_FB_CONSTANT (memoffset, 0, ((64 - height) * 48));
2001 return CIM_STATUS_OK;
2004 /*---------------------------------------------------------------------------
2005 * vg_pan_desktop
2007 * This routine sets the correct display offset based on the current cursor
2008 * position.
2009 *---------------------------------------------------------------------------*/
2011 int vg_pan_desktop (unsigned long x, unsigned long y, VG_PANNING_COORDINATES *panning)
2013 unsigned long modeShiftPerPixel;
2014 unsigned long modeBytesPerScanline;
2015 unsigned long startAddress;
2017 /* TEST FOR NO-WORK */
2019 if (x >= vg3_delta_x && x < (vg3_panel_width + vg3_delta_x) &&
2020 y >= vg3_delta_y && y < (vg3_panel_height + vg3_delta_y))
2022 panning->start_x = vg3_delta_x;
2023 panning->start_y = vg3_delta_y;
2024 panning->start_updated = 0;
2025 return CIM_STATUS_OK;
2028 if (vg3_bpp == 24) modeShiftPerPixel = 2;
2029 else modeShiftPerPixel = (vg3_bpp + 7) >> 4;
2031 modeBytesPerScanline = (READ_REG32 (DC3_GFX_PITCH) & 0x0000FFFF) << 3;
2033 /* ADJUST PANNING VARIABLES WHEN CURSOR EXCEEDS BOUNDARY */
2034 /* Test the boundary conditions for each coordinate and update */
2035 /* all variables and the starting offset accordingly. */
2037 if (x < vg3_delta_x)
2038 vg3_delta_x = x;
2040 else if (x >= (vg3_delta_x + vg3_panel_width))
2041 vg3_delta_x = x - vg3_panel_width + 1;
2043 if (y < vg3_delta_y)
2044 vg3_delta_y = y;
2046 else if (y >= (vg3_delta_y + vg3_panel_height))
2047 vg3_delta_y = y - vg3_panel_height + 1;
2049 /* CALCULATE THE START OFFSET */
2051 startAddress = (vg3_delta_x << modeShiftPerPixel) + (vg3_delta_y * modeBytesPerScanline);
2053 vg_set_display_offset (startAddress);
2055 panning->start_updated = 1;
2056 panning->start_x = vg3_delta_x;
2057 panning->start_y = vg3_delta_y;
2058 return CIM_STATUS_OK;
2061 /*---------------------------------------------------------------------------
2062 * vg_set_display_offset
2064 * This routine sets the start address of the frame buffer. It is
2065 * typically used to pan across a virtual desktop (frame buffer larger than
2066 * the displayed screen) or to flip the display between multiple buffers.
2067 *---------------------------------------------------------------------------*/
2069 int vg_set_display_offset (unsigned long address)
2071 unsigned long lock, gcfg;
2073 lock = READ_REG32 (DC3_UNLOCK);
2074 WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
2076 /* DISABLE COMPRESSION */
2077 /* When setting a non-zero display offset, we must disable display */
2078 /* compression. We could maintain a variable and re-enable */
2079 /* compression when the offset returns to zero. However, that */
2080 /* creates additional complexity for applications that perform */
2081 /* graphics animation. Re-enabling compression each time would */
2082 /* be tedious and slow for such applications, implying that they */
2083 /* would have to disable compression before starting the animation. */
2084 /* We will instead disable compression and force the user to */
2085 /* re-enable compression when they are ready. */
2087 if (address != 0)
2089 if (READ_REG32 (DC3_GENERAL_CFG) & DC3_GCFG_CMPE)
2091 gcfg = READ_REG32 (DC3_GENERAL_CFG);
2092 WRITE_REG32 (DC3_GENERAL_CFG, (gcfg & ~(DC3_GCFG_CMPE | DC3_GCFG_DECE)));
2096 WRITE_REG32 (DC3_FB_ST_OFFSET, address);
2097 WRITE_REG32 (DC3_UNLOCK, lock);
2099 return CIM_STATUS_OK;
2102 /*---------------------------------------------------------------------------
2103 * vg_set_display_pitch
2105 * This routine sets the stride between successive lines of data in the frame
2106 * buffer.
2107 *---------------------------------------------------------------------------*/
2109 int vg_set_display_pitch (unsigned long pitch)
2111 unsigned long dvtop, value;
2112 unsigned long lock = READ_REG32(DC3_UNLOCK);
2114 value = READ_REG32(DC3_GFX_PITCH) & 0xFFFF0000;
2115 value |= (pitch >> 3);
2117 /* PROGRAM THE DISPLAY PITCH */
2119 WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
2120 WRITE_REG32 (DC3_GFX_PITCH, value);
2122 /* SET THE COMPRESSION BEHAVIOR BASED ON THE PITCH */
2123 /* Strides that are not a power of two will not work with line */
2124 /* by line compression. For these cases, we enable full-screen */
2125 /* compression. In this mode, any write to the frame buffer */
2126 /* region marks the entire frame as dirty. */
2128 value = READ_REG32 (DC3_GENERAL_CFG);
2130 if (pitch == 1024 || pitch == 2048 || pitch == 4096 || pitch == 8192)
2132 value &= ~DC3_GCFG_FDTY;
2133 dvtop = 0;
2135 else
2137 value |= DC3_GCFG_FDTY;
2139 dvtop = (READ_REG32 (DC3_FB_ACTIVE) & 0xFFF) + 1;
2140 dvtop = ((dvtop * pitch) + 0x3FF) & 0xFFFFFC00;
2141 dvtop |= DC3_DVTOP_ENABLE;
2144 WRITE_REG32 (DC3_GENERAL_CFG, value);
2145 WRITE_REG32 (DC3_DV_TOP, dvtop);
2146 WRITE_REG32 (DC3_UNLOCK, lock);
2148 return CIM_STATUS_OK;
2151 /*---------------------------------------------------------------------------
2152 * vg_set_display_palette_entry
2154 * This routine sets a single 8BPP palette entry in the display controller.
2155 *---------------------------------------------------------------------------*/
2157 int vg_set_display_palette_entry (unsigned long index, unsigned long palette)
2159 unsigned long dcfg, unlock;
2161 if (index > 0xFF)
2162 return CIM_STATUS_INVALIDPARAMS;
2164 unlock = READ_REG32 (DC3_UNLOCK);
2165 dcfg = READ_REG32 (DC3_DISPLAY_CFG);
2167 WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
2168 WRITE_REG32 (DC3_DISPLAY_CFG, dcfg & ~DC3_DCFG_PALB);
2169 WRITE_REG32 (DC3_UNLOCK, unlock);
2171 WRITE_REG32 (DC3_PAL_ADDRESS, index);
2172 WRITE_REG32 (DC3_PAL_DATA, palette);
2174 return CIM_STATUS_OK;
2177 /*---------------------------------------------------------------------------
2178 * vg_set_display_palette
2180 * This routine sets the entire palette in the display controller.
2181 * A pointer is provided to a 256 entry table of 32-bit X:R:G:B values.
2182 *---------------------------------------------------------------------------*/
2184 int vg_set_display_palette (unsigned long *palette)
2186 unsigned long unlock, dcfg, i;
2187 WRITE_REG32 (DC3_PAL_ADDRESS, 0);
2189 if (palette)
2191 unlock = READ_REG32 (DC3_UNLOCK);
2192 dcfg = READ_REG32 (DC3_DISPLAY_CFG);
2194 WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
2195 WRITE_REG32 (DC3_DISPLAY_CFG, dcfg & ~DC3_DCFG_PALB);
2196 WRITE_REG32 (DC3_UNLOCK, unlock);
2198 for (i = 0; i < 256; i++)
2199 WRITE_REG32 (DC3_PAL_DATA, palette[i]);
2201 return CIM_STATUS_OK;
2203 return CIM_STATUS_INVALIDPARAMS;
2206 /*---------------------------------------------------------------------------
2207 * vg_set_compression_enable
2209 * This routine enables or disables display compression.
2210 *---------------------------------------------------------------------------*/
2212 int vg_set_compression_enable (int enable)
2214 Q_WORD msr_value;
2215 unsigned long unlock, gcfg;
2216 unsigned long temp;
2218 unlock = READ_REG32 (DC3_UNLOCK);
2219 gcfg = READ_REG32 (DC3_GENERAL_CFG);
2220 WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
2222 if (enable)
2224 /* DO NOT ENABLE IF THE DISPLAY OFFSET IS NOT ZERO */
2226 if (READ_REG32 (DC3_FB_ST_OFFSET) & 0x0FFFFFFF)
2227 return CIM_STATUS_ERROR;
2229 /* ENABLE BIT 1 IN THE VG SPARE MSR */
2230 /* The bus can hang when the VG attempts to merge compression writes. */
2231 /* No performance is lost due to the GeodeLink QUACK features in */
2232 /* GeodeLX. We also enable the command word check for a valid */
2233 /* compression header. */
2235 msr_read64 (MSR_DEVICE_GEODELX_VG, DC3_SPARE_MSR, &msr_value);
2236 msr_value.low |= DC3_SPARE_FIRST_REQ_MASK;
2237 msr_value.low &= ~DC3_SPARE_DISABLE_CWD_CHECK;
2238 msr_write64 (MSR_DEVICE_GEODELX_VG, DC3_SPARE_MSR, &msr_value);
2240 /* CLEAR DIRTY/VALID BITS IN MEMORY CONTROLLER */
2241 /* We don't want the controller to think that old lines are still */
2242 /* valid. Writing a 1 to bit 0 of the DV Control register will force */
2243 /* the hardware to clear all the valid bits. */
2245 temp = READ_REG32 (DC3_DV_CTL);
2246 WRITE_REG32 (DC3_DV_CTL, temp | 0x00000001);
2248 /* ENABLE COMPRESSION BITS */
2250 gcfg |= DC3_GCFG_CMPE | DC3_GCFG_DECE;
2252 else
2254 gcfg &= ~(DC3_GCFG_CMPE | DC3_GCFG_DECE);
2257 WRITE_REG32 (DC3_GENERAL_CFG, gcfg);
2258 WRITE_REG32 (DC3_UNLOCK, unlock);
2260 return CIM_STATUS_OK;
2263 /*---------------------------------------------------------------------------
2264 * vg_configure_compression
2266 * This routine configures all aspects of display compression, including pitch,
2267 * size and the offset of the compression buffer.
2268 *---------------------------------------------------------------------------*/
2270 int vg_configure_compression (VG_COMPRESSION_DATA *comp_data)
2272 unsigned long delta, size;
2273 unsigned long comp_size, unlock;
2275 /* CHECK FOR VALID PARAMETERS */
2276 /* The maximum size for the compression buffer is 544 bytes (with */
2277 /* the header) Also, the pitch cannot be less than the line size */
2278 /* and the compression buffer offset must be 16-byte aligned. */
2280 if (comp_data->size > 544 || comp_data->pitch < comp_data->size ||
2281 comp_data->compression_offset & 0x0F)
2283 return CIM_STATUS_INVALIDPARAMS;
2286 /* SUBTRACT 32 FROM SIZE */
2287 /* The display controller will actually write 4 extra QWords. So, */
2288 /* if we assume that "size" refers to the allocated size, we must */
2289 /* subtract 32 bytes. */
2291 comp_size = comp_data->size - 32;
2293 /* CALCULATE REGISTER VALUES */
2295 unlock = READ_REG32 (DC3_UNLOCK);
2296 size = READ_REG32 (DC3_LINE_SIZE) & ~DC3_LINE_SIZE_CBLS_MASK;
2297 delta = READ_REG32 (DC3_GFX_PITCH) & ~DC3_GFX_PITCH_CBP_MASK;
2299 size |= ((comp_size >> 3) + 1) << DC3_LINE_SIZE_CB_SHIFT;
2300 delta |= ((comp_data->pitch >> 3) << 16);
2302 /* WRITE COMPRESSION PARAMETERS */
2304 WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
2305 WRITE_REG32 (DC3_CB_ST_OFFSET, comp_data->compression_offset);
2306 WRITE_REG32 (DC3_LINE_SIZE, size);
2307 WRITE_REG32 (DC3_GFX_PITCH, delta);
2308 WRITE_REG32 (DC3_UNLOCK, unlock);
2310 return CIM_STATUS_OK;
2313 /*---------------------------------------------------------------------------
2314 * vg_test_timing_active
2316 * This routine checks the status of the display timing generator.
2317 *---------------------------------------------------------------------------*/
2319 int vg_test_timing_active (void)
2321 if (READ_REG32 (DC3_DISPLAY_CFG) & DC3_DCFG_TGEN)
2322 return 1;
2324 return 0;
2327 /*---------------------------------------------------------------------------
2328 * vg_test_vertical_active
2330 * This routine checks if the display is currently in the middle of a frame
2331 * (not in the VBlank interval)
2332 *---------------------------------------------------------------------------*/
2334 int vg_test_vertical_active (void)
2336 if (READ_REG32 (DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA)
2337 return 0;
2339 return 1;
2342 /*---------------------------------------------------------------------------
2343 * vg_wait_vertical_blank
2345 * This routine waits until the beginning of the vertical blank interval.
2346 * When the display is already in vertical blank, this routine will wait until
2347 * the beginning of the next vertical blank.
2348 *---------------------------------------------------------------------------*/
2350 int vg_wait_vertical_blank(void)
2352 if (vg_test_timing_active())
2354 while (!vg_test_vertical_active());
2355 while (vg_test_vertical_active());
2357 return CIM_STATUS_OK;
2360 /*---------------------------------------------------------------------------
2361 * vg_test_even_field
2363 * This routine tests the odd/even status of the current VG output field.
2364 *---------------------------------------------------------------------------*/
2366 int vg_test_even_field(void)
2368 if (READ_REG32 (DC3_LINE_CNT_STATUS) & DC3_LNCNT_EVEN_FIELD)
2369 return 1;
2371 return 0;
2374 /*---------------------------------------------------------------------------
2375 * vg_configure_line_interrupt
2377 * This routine configures the display controller's line count interrupt. This
2378 * interrupt can be used to interrupt mid-frame or to interrupt at the beginning
2379 * of vertical blank.
2380 *---------------------------------------------------------------------------*/
2382 int vg_configure_line_interrupt (VG_INTERRUPT_PARAMS *interrupt_info)
2384 unsigned long irq_line, irq_enable;
2385 unsigned long lock;
2387 irq_line = READ_REG32 (DC3_IRQ_FILT_CTL);
2388 irq_enable = READ_REG32 (DC3_IRQ);
2389 lock = READ_REG32 (DC3_UNLOCK);
2391 irq_line = (irq_line & ~DC3_IRQFILT_LINE_MASK) | ((interrupt_info->line << 16) & DC3_IRQFILT_LINE_MASK);
2393 /* ENABLE OR DISABLE THE INTERRUPT */
2394 /* The line count is set before enabling and after disabling to */
2395 /* minimize spurious interrupts. The line count is set even */
2396 /* when interrupts are disabled to allow polling-based or debug */
2397 /* applications. */
2399 WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
2400 if (interrupt_info->enable)
2402 WRITE_REG32 (DC3_IRQ_FILT_CTL, irq_line);
2403 WRITE_REG32 (DC3_IRQ, ((irq_enable & ~DC3_IRQ_MASK) | DC3_IRQ_STATUS));
2405 else
2407 WRITE_REG32 (DC3_IRQ, (irq_enable | DC3_IRQ_MASK));
2408 WRITE_REG32 (DC3_IRQ_FILT_CTL, irq_line);
2410 WRITE_REG32 (DC3_UNLOCK, lock);
2411 return CIM_STATUS_OK;
2414 /*---------------------------------------------------------------------------
2415 * vg_test_and_clear_interrupt
2417 * This routine resets any pending interrupt in the video generator. The return
2418 * value indicates the interrupt status prior to the reset.
2419 *---------------------------------------------------------------------------*/
2421 unsigned long vg_test_and_clear_interrupt (void)
2423 unsigned long irq_enable;
2424 unsigned long lock;
2426 irq_enable = READ_REG32 (DC3_IRQ);
2427 lock = READ_REG32 (DC3_UNLOCK);
2429 /* NO ACTION IF INTERRUPTS ARE MASKED */
2430 /* We are assuming that a driver or application will not want to receive */
2431 /* the status of the interrupt when it is masked. */
2433 if ((irq_enable & (DC3_IRQ_MASK | DC3_VSYNC_IRQ_MASK)) == (DC3_IRQ_MASK | DC3_VSYNC_IRQ_MASK))
2434 return 0;
2436 WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
2437 WRITE_REG32 (DC3_IRQ, irq_enable);
2438 WRITE_REG32 (DC3_UNLOCK, lock);
2440 return (irq_enable & (DC3_IRQ_STATUS | DC3_VSYNC_IRQ_STATUS));
2443 /*---------------------------------------------------------------------------
2444 * vg_test_flip_status
2446 * This routine tests if a new display offset has been latched.
2447 *---------------------------------------------------------------------------*/
2449 unsigned long vg_test_flip_status (void)
2451 return (READ_REG32 (DC3_LINE_CNT_STATUS) & DC3_LNCNT_FLIP);
2454 /*---------------------------------------------------------------------------
2455 * vg_save_state
2457 * This routine saves all persistent VG state information.
2458 *---------------------------------------------------------------------------*/
2460 int vg_save_state (VG_SAVE_RESTORE *vg_state)
2462 Q_WORD msr_value;
2463 unsigned long irqfilt;
2464 unsigned long offset, i;
2465 unsigned long lock;
2467 /* READ ALL CURRENT REGISTER SETTINGS */
2469 vg_state->unlock = READ_REG32 (DC3_UNLOCK);
2470 vg_state->gcfg = READ_REG32 (DC3_GENERAL_CFG);
2471 vg_state->dcfg = READ_REG32 (DC3_DISPLAY_CFG);
2472 vg_state->arb_cfg = READ_REG32 (DC3_ARB_CFG);
2473 vg_state->fb_offset = READ_REG32 (DC3_FB_ST_OFFSET);
2474 vg_state->cb_offset = READ_REG32 (DC3_CB_ST_OFFSET);
2475 vg_state->cursor_offset = READ_REG32 (DC3_CURS_ST_OFFSET);
2476 vg_state->video_y_offset = READ_REG32 (DC3_VID_Y_ST_OFFSET);
2477 vg_state->video_u_offset = READ_REG32 (DC3_VID_U_ST_OFFSET);
2478 vg_state->video_v_offset = READ_REG32 (DC3_VID_V_ST_OFFSET);
2479 vg_state->dv_top = READ_REG32 (DC3_DV_TOP);
2480 vg_state->line_size = READ_REG32 (DC3_LINE_SIZE);
2481 vg_state->gfx_pitch = READ_REG32 (DC3_GFX_PITCH);
2482 vg_state->video_yuv_pitch = READ_REG32 (DC3_VID_YUV_PITCH);
2483 vg_state->h_active = READ_REG32 (DC3_H_ACTIVE_TIMING);
2484 vg_state->h_blank = READ_REG32 (DC3_H_BLANK_TIMING);
2485 vg_state->h_sync = READ_REG32 (DC3_H_SYNC_TIMING);
2486 vg_state->v_active = READ_REG32 (DC3_V_ACTIVE_TIMING);
2487 vg_state->v_blank = READ_REG32 (DC3_V_BLANK_TIMING);
2488 vg_state->v_sync = READ_REG32 (DC3_V_SYNC_TIMING);
2489 vg_state->fb_active = READ_REG32 (DC3_FB_ACTIVE);
2490 vg_state->cursor_x = READ_REG32 (DC3_CURSOR_X);
2491 vg_state->cursor_y = READ_REG32 (DC3_CURSOR_Y);
2492 vg_state->vid_ds_delta = READ_REG32 (DC3_VID_DS_DELTA);
2493 vg_state->fb_base = READ_REG32 (DC3_PHY_MEM_OFFSET);
2494 vg_state->dv_ctl = READ_REG32 (DC3_DV_CTL);
2495 vg_state->gfx_scale = READ_REG32 (DC3_GFX_SCALE);
2496 vg_state->irq_ctl = READ_REG32 (DC3_IRQ_FILT_CTL);
2497 vg_state->vbi_even_ctl = READ_REG32 (DC3_VBI_EVEN_CTL);
2498 vg_state->vbi_odd_ctl = READ_REG32 (DC3_VBI_ODD_CTL);
2499 vg_state->vbi_hor_ctl = READ_REG32 (DC3_VBI_HOR);
2500 vg_state->vbi_odd_line_enable = READ_REG32 (DC3_VBI_LN_ODD);
2501 vg_state->vbi_even_line_enable = READ_REG32 (DC3_VBI_LN_EVEN);
2502 vg_state->vbi_pitch = READ_REG32 (DC3_VBI_PITCH);
2503 vg_state->color_key = READ_REG32 (DC3_COLOR_KEY);
2504 vg_state->color_key_mask = READ_REG32 (DC3_COLOR_MASK);
2505 vg_state->color_key_x = READ_REG32 (DC3_CLR_KEY_X);
2506 vg_state->color_key_y = READ_REG32 (DC3_CLR_KEY_Y);
2507 vg_state->irq = READ_REG32 (DC3_IRQ);
2508 vg_state->genlk_ctl = READ_REG32 (DC3_GENLK_CTL);
2509 vg_state->vid_y_even_offset = READ_REG32 (DC3_VID_EVEN_Y_ST_OFFSET);
2510 vg_state->vid_u_even_offset = READ_REG32 (DC3_VID_EVEN_U_ST_OFFSET);
2511 vg_state->vid_v_even_offset = READ_REG32 (DC3_VID_EVEN_V_ST_OFFSET);
2512 vg_state->vactive_even = READ_REG32 (DC3_V_ACTIVE_EVEN);
2513 vg_state->vblank_even = READ_REG32 (DC3_V_BLANK_EVEN);
2514 vg_state->vsync_even = READ_REG32 (DC3_V_SYNC_EVEN);
2516 /* READ THE CURRENT PALETTE */
2518 lock = READ_REG32 (DC3_UNLOCK);
2519 WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
2520 WRITE_REG32 (DC3_PAL_ADDRESS, 0);
2521 for (i = 0; i < 261; i++)
2522 vg_state->palette[i] = READ_REG32 (DC3_PAL_DATA);
2524 /* READ THE CURRENT FILTER COEFFICIENTS */
2526 /* ENABLE ACCESS TO THE HORIZONTAL COEFFICIENTS */
2528 irqfilt = READ_REG32 (DC3_IRQ_FILT_CTL);
2529 irqfilt |= DC3_IRQFILT_H_FILT_SEL;
2531 /* READ HORIZONTAL COEFFICIENTS */
2533 for (i = 0; i < 256; i++)
2535 WRITE_REG32 (DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
2537 vg_state->h_coeff[(i << 1)] = READ_REG32 (DC3_FILT_COEFF1);
2538 vg_state->h_coeff[(i << 1) + 1] = READ_REG32 (DC3_FILT_COEFF2);
2541 /* ENABLE ACCESS TO THE VERTICAL COEFFICIENTS */
2543 irqfilt &= ~DC3_IRQFILT_H_FILT_SEL;
2545 /* READ COEFFICIENTS */
2547 for (i = 0; i < 256; i++)
2549 WRITE_REG32 (DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
2551 vg_state->v_coeff[i] = READ_REG32 (DC3_FILT_COEFF1);
2554 /* READ THE CURSOR DATA */
2556 offset = READ_REG32 (DC3_CURS_ST_OFFSET) & 0x0FFFFFFF;
2557 for (i = 0; i < 3072; i++)
2558 vg_state->cursor_data[i] = READ_FB32 (offset + (i << 2));
2560 /* READ THE CURRENT PLL */
2562 msr_read64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DOTPLL, &msr_value);
2564 vg_state->pll_flags = 0;
2565 for (i = 0; i < NUM_CIMARRON_PLL_FREQUENCIES; i++)
2567 if (CimarronPLLFrequencies[i].pll_value == (msr_value.high & 0x7FFF))
2569 vg_state->dot_pll = CimarronPLLFrequencies[i].frequency;
2570 break;
2574 if (i == NUM_CIMARRON_PLL_FREQUENCIES)
2576 /* NO MATCH */
2577 /* Enter the frequency as a manual frequency. */
2579 vg_state->dot_pll = msr_value.high;
2580 vg_state->pll_flags |= VG_PLL_MANUAL;
2582 if (msr_value.low & GLCP_DOTPLL_HALFPIX)
2583 vg_state->pll_flags |= VG_PLL_DIVIDE_BY_2;
2584 if (msr_value.low & GLCP_DOTPLL_BYPASS)
2585 vg_state->pll_flags |= VG_PLL_BYPASS;
2586 if (msr_value.high & GLCP_DOTPLL_DIV4)
2587 vg_state->pll_flags |= VG_PLL_DIVIDE_BY_4;
2588 if (msr_value.high & GLCP_DOTPLL_VIPCLK)
2589 vg_state->pll_flags |= VG_PLL_VIP_CLOCK;
2591 /* READ ALL VG MSRS */
2593 msr_read64 (MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_CAP, &(vg_state->msr_cap));
2594 msr_read64 (MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_CONFIG, &(vg_state->msr_config));
2595 msr_read64 (MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_SMI, &(vg_state->msr_smi));
2596 msr_read64 (MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_ERROR, &(vg_state->msr_error));
2597 msr_read64 (MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_PM, &(vg_state->msr_pm));
2598 msr_read64 (MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_DIAG, &(vg_state->msr_diag));
2599 msr_read64 (MSR_DEVICE_GEODELX_VG, DC3_SPARE_MSR, &(vg_state->msr_spare));
2600 msr_read64 (MSR_DEVICE_GEODELX_VG, DC3_RAM_CTL, &(vg_state->msr_ram_ctl));
2602 WRITE_REG32 (DC3_UNLOCK, lock);
2604 return CIM_STATUS_OK;
2607 /*---------------------------------------------------------------------------
2608 * vg_restore_state
2610 * This routine restores all persistent VG state information.
2611 *---------------------------------------------------------------------------*/
2613 int vg_restore_state (VG_SAVE_RESTORE *vg_state)
2615 unsigned long irqfilt, i;
2616 unsigned long memoffset;
2618 /* TEMPORARILY UNLOCK ALL REGISTERS */
2620 WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
2622 /* RESTORE THE FRAME BUFFER OFFSET */
2624 WRITE_REG32 (DC3_PHY_MEM_OFFSET, vg_state->fb_base);
2626 /* BLANK GCFG AND DCFG */
2628 WRITE_REG32 (DC3_GENERAL_CFG, 0);
2629 WRITE_REG32 (DC3_DISPLAY_CFG, 0);
2631 /* RESTORE ALL REGISTERS */
2633 WRITE_REG32 (DC3_ARB_CFG, vg_state->arb_cfg);
2634 WRITE_REG32 (DC3_FB_ST_OFFSET, vg_state->fb_offset);
2635 WRITE_REG32 (DC3_CB_ST_OFFSET, vg_state->cb_offset);
2636 WRITE_REG32 (DC3_CURS_ST_OFFSET, vg_state->cursor_offset);
2637 WRITE_REG32 (DC3_VID_Y_ST_OFFSET, vg_state->video_y_offset);
2638 WRITE_REG32 (DC3_VID_U_ST_OFFSET, vg_state->video_u_offset);
2639 WRITE_REG32 (DC3_VID_V_ST_OFFSET, vg_state->video_v_offset);
2640 WRITE_REG32 (DC3_DV_TOP, vg_state->dv_top);
2641 WRITE_REG32 (DC3_LINE_SIZE, vg_state->line_size);
2642 WRITE_REG32 (DC3_GFX_PITCH, vg_state->gfx_pitch);
2643 WRITE_REG32 (DC3_VID_YUV_PITCH, vg_state->video_yuv_pitch);
2644 WRITE_REG32 (DC3_H_ACTIVE_TIMING, vg_state->h_active);
2645 WRITE_REG32 (DC3_H_BLANK_TIMING, vg_state->h_blank);
2646 WRITE_REG32 (DC3_H_SYNC_TIMING, vg_state->h_sync);
2647 WRITE_REG32 (DC3_V_ACTIVE_TIMING, vg_state->v_active);
2648 WRITE_REG32 (DC3_V_BLANK_TIMING, vg_state->v_blank);
2649 WRITE_REG32 (DC3_V_SYNC_TIMING, vg_state->v_sync);
2650 WRITE_REG32 (DC3_FB_ACTIVE, vg_state->fb_active);
2651 WRITE_REG32 (DC3_CURSOR_X, vg_state->cursor_x);
2652 WRITE_REG32 (DC3_CURSOR_Y, vg_state->cursor_y);
2653 WRITE_REG32 (DC3_VID_DS_DELTA, vg_state->vid_ds_delta);
2654 WRITE_REG32 (DC3_PHY_MEM_OFFSET, vg_state->fb_base);
2655 WRITE_REG32 (DC3_DV_CTL, vg_state->dv_ctl | 0x00000001);
2656 WRITE_REG32 (DC3_GFX_SCALE, vg_state->gfx_scale);
2657 WRITE_REG32 (DC3_IRQ_FILT_CTL, vg_state->irq_ctl);
2658 WRITE_REG32 (DC3_VBI_EVEN_CTL, vg_state->vbi_even_ctl);
2659 WRITE_REG32 (DC3_VBI_ODD_CTL, vg_state->vbi_odd_ctl);
2660 WRITE_REG32 (DC3_VBI_HOR, vg_state->vbi_hor_ctl);
2661 WRITE_REG32 (DC3_VBI_LN_ODD, vg_state->vbi_odd_line_enable);
2662 WRITE_REG32 (DC3_VBI_LN_EVEN, vg_state->vbi_even_line_enable);
2663 WRITE_REG32 (DC3_VBI_PITCH, vg_state->vbi_pitch);
2664 WRITE_REG32 (DC3_COLOR_KEY, vg_state->color_key);
2665 WRITE_REG32 (DC3_COLOR_MASK, vg_state->color_key_mask);
2666 WRITE_REG32 (DC3_CLR_KEY_X, vg_state->color_key_x);
2667 WRITE_REG32 (DC3_CLR_KEY_Y, vg_state->color_key_y);
2668 WRITE_REG32 (DC3_IRQ, vg_state->irq);
2669 WRITE_REG32 (DC3_GENLK_CTL, vg_state->genlk_ctl);
2670 WRITE_REG32 (DC3_VID_EVEN_Y_ST_OFFSET, vg_state->vid_y_even_offset);
2671 WRITE_REG32 (DC3_VID_EVEN_U_ST_OFFSET, vg_state->vid_u_even_offset);
2672 WRITE_REG32 (DC3_VID_EVEN_V_ST_OFFSET, vg_state->vid_v_even_offset);
2673 WRITE_REG32 (DC3_V_ACTIVE_EVEN, vg_state->vactive_even);
2674 WRITE_REG32 (DC3_V_BLANK_EVEN, vg_state->vblank_even);
2675 WRITE_REG32 (DC3_V_SYNC_EVEN, vg_state->vsync_even);
2677 /* RESTORE THE PALETTE */
2679 WRITE_REG32 (DC3_PAL_ADDRESS, 0);
2680 for (i = 0; i < 261; i++)
2681 WRITE_REG32 (DC3_PAL_DATA, vg_state->palette[i]);
2683 /* RESTORE THE HORIZONTAL FILTER COEFFICIENTS */
2685 irqfilt = READ_REG32 (DC3_IRQ_FILT_CTL);
2686 irqfilt |= DC3_IRQFILT_H_FILT_SEL;
2688 for (i = 0; i < 256; i++)
2690 WRITE_REG32 (DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
2691 WRITE_REG32 (DC3_FILT_COEFF1, vg_state->h_coeff[(i << 1)]);
2692 WRITE_REG32 (DC3_FILT_COEFF2, vg_state->h_coeff[(i << 1) + 1]);
2695 /* RESTORE VERTICAL COEFFICIENTS */
2697 irqfilt &= ~DC3_IRQFILT_H_FILT_SEL;
2699 for (i = 0; i < 256; i++)
2701 WRITE_REG32 (DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
2702 WRITE_REG32 (DC3_FILT_COEFF1, vg_state->v_coeff[i]);
2705 /* RESTORE THE CURSOR DATA */
2707 memoffset = READ_REG32 (DC3_CURS_ST_OFFSET) & 0x0FFFFFFF;
2708 WRITE_FB_STRING32 (memoffset, (unsigned char *)&(vg_state->cursor_data[0]), 3072);
2710 /* RESTORE THE PLL */
2711 /* Use a common routine to use common code to poll for lock bit */
2713 vg_set_clock_frequency (vg_state->dot_pll, vg_state->pll_flags);
2715 /* RESTORE ALL VG MSRS */
2717 msr_write64 (MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_CAP, &(vg_state->msr_cap));
2718 msr_write64 (MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_CONFIG, &(vg_state->msr_config));
2719 msr_write64 (MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_SMI, &(vg_state->msr_smi));
2720 msr_write64 (MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_ERROR, &(vg_state->msr_error));
2721 msr_write64 (MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_PM, &(vg_state->msr_pm));
2722 msr_write64 (MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_DIAG, &(vg_state->msr_diag));
2723 msr_write64 (MSR_DEVICE_GEODELX_VG, DC3_SPARE_MSR, &(vg_state->msr_spare));
2724 msr_write64 (MSR_DEVICE_GEODELX_VG, DC3_RAM_CTL, &(vg_state->msr_ram_ctl));
2726 /* NOW RESTORE GCFG AND DCFG */
2728 WRITE_REG32 (DC3_DISPLAY_CFG, vg_state->dcfg);
2729 WRITE_REG32 (DC3_GENERAL_CFG, vg_state->gcfg);
2731 /* FINALLY RESTORE UNLOCK */
2733 WRITE_REG32 (DC3_UNLOCK, vg_state->unlock);
2735 return CIM_STATUS_OK;
2738 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2739 * CIMARRON VG READ ROUTINES
2740 * These routines are included for use in diagnostics or when debugging. They
2741 * can be optionally excluded from a project.
2742 *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
2744 #if CIMARRON_INCLUDE_VG_READ_ROUTINES
2746 /*---------------------------------------------------------------------------
2747 * vg_read_graphics_crc
2749 * This routine reads the Cyclic Redundancy Check (CRC) value for the graphics
2750 * frame.
2751 *---------------------------------------------------------------------------*/
2753 unsigned long vg_read_graphics_crc (int crc_source)
2755 unsigned long gcfg, unlock;
2756 unsigned long crc, vbi_even;
2757 unsigned long interlaced;
2758 unsigned long line, field;
2760 if (!(READ_REG32 (DC3_DISPLAY_CFG) & DC3_DCFG_TGEN))
2761 return 0xFFFFFFFF;
2763 unlock = READ_REG32 (DC3_UNLOCK);
2764 gcfg = READ_REG32 (DC3_GENERAL_CFG);
2765 vbi_even = READ_REG32 (DC3_VBI_EVEN_CTL);
2767 vbi_even &= ~DC3_VBI_EVEN_ENABLE_CRC;
2769 gcfg |= DC3_GCFG_SGRE | DC3_GCFG_CRC_MODE;
2770 gcfg &= ~(DC3_GCFG_SGFR | DC3_GCFG_SIG_SEL | DC3_GCFG_FILT_SIG_SEL);
2772 switch (crc_source)
2774 case VG_CRC_SOURCE_PREFILTER_EVEN:
2775 case VG_CRC_SOURCE_PREFILTER: gcfg |= DC3_GCFG_SIG_SEL; break;
2776 case VG_CRC_SOURCE_PREFLICKER:
2777 case VG_CRC_SOURCE_PREFLICKER_EVEN: gcfg |= DC3_GCFG_FILT_SIG_SEL; break;
2778 case VG_CRC_SOURCE_POSTFLICKER:
2779 case VG_CRC_SOURCE_POSTFLICKER_EVEN: /* NO WORK */ break;
2781 default:
2782 return 0xFFFFFFFF;
2785 if (crc_source & VG_CRC_SOURCE_EVEN) field = 0;
2786 else field = DC3_LNCNT_EVEN_FIELD;
2788 if ((interlaced = (READ_REG32 (DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN)))
2790 /* WAIT FOR THE BEGINNING OF THE FIELD (LINE 1-5) */
2791 /* Note that we wait for the field to be odd when CRCing the even */
2792 /* field and vice versa. This is because the CRC will not begin */
2793 /* until the following field. */
2797 line = READ_REG32 (DC3_LINE_CNT_STATUS);
2798 } while ((line & DC3_LNCNT_EVEN_FIELD) != field ||
2799 ((line & DC3_LNCNT_V_LINE_CNT) >> 16) < 10 ||
2800 ((line & DC3_LNCNT_V_LINE_CNT) >> 16) > 15);
2802 else
2804 /* NON-INTERLACED - EVEN FIELD CRCS ARE INVALID */
2806 if (crc_source & VG_CRC_SOURCE_EVEN)
2807 return 0xFFFFFFFF;
2810 WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
2811 WRITE_REG32 (DC3_VBI_EVEN_CTL, vbi_even);
2812 WRITE_REG32 (DC3_GENERAL_CFG, gcfg & ~DC3_GCFG_SIGE);
2813 WRITE_REG32 (DC3_GENERAL_CFG, gcfg | DC3_GCFG_SIGE);
2815 /* WAIT FOR THE CRC TO BE COMPLETED */
2817 while (!(READ_REG32 (DC3_LINE_CNT_STATUS) & DC3_LNCNT_SIGC))
2820 /* READ THE COMPLETED CRC */
2822 crc = READ_REG32 (DC3_PAL_DATA);
2824 /* RESTORE THE PALETTE SETTINGS */
2826 gcfg &= ~DC3_GCFG_SGRE;
2827 WRITE_REG32 (DC3_GENERAL_CFG, gcfg);
2828 WRITE_REG32 (DC3_UNLOCK, unlock);
2830 return crc;
2833 /*---------------------------------------------------------------------------
2834 * vg_read_window_crc
2836 * This routine reads the Cyclic Redundancy Check (CRC) value for a sub-section
2837 * of the frame.
2838 *---------------------------------------------------------------------------*/
2840 unsigned long vg_read_window_crc (int crc_source, unsigned long x, unsigned long y,
2841 unsigned long width, unsigned long height)
2843 Q_WORD msr_value;
2844 unsigned long crc = 0;
2845 unsigned long hactive, hblankstart;
2846 unsigned long htotal, hblankend;
2847 unsigned long line, field;
2848 unsigned long diag;
2850 hactive = ((READ_REG32 (DC3_H_ACTIVE_TIMING)) & 0xFFF) + 1;
2851 hblankstart = ((READ_REG32 (DC3_H_BLANK_TIMING)) & 0xFFF) + 1;
2852 htotal = ((READ_REG32 (DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
2853 hblankend = ((READ_REG32 (DC3_H_BLANK_TIMING) >> 16) & 0xFFF) + 1;
2855 /* TIMINGS MUST BE ACTIVE */
2857 if (!(READ_REG32 (DC3_DISPLAY_CFG) & DC3_DCFG_TGEN))
2858 return 0xFFFFFFFF;
2860 /* DISABLE GLCP ACTIONS */
2862 msr_value.low = 0;
2863 msr_value.high = 0;
2864 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DIAGCTL, &msr_value);
2866 if ((x == 0 && width == 1) || x == 1)
2868 /* SPECIAL CASE FOR X == 0 */
2869 /* The comparator output is a clock late in the MCP, so we cannot */
2870 /* easily catch the first pixel. If the first pixel is desired, */
2871 /* we will insert a special state machine to CRC just the first */
2872 /* pixel. */
2874 /* N2 - DISPE HIGH AND Y == 1 */
2875 /* Goto state YState = 2 */
2877 msr_value.high = 0x00000002;
2878 msr_value.low = 0x00000C00;
2879 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 2, &msr_value);
2881 /* M3 - DISPE HIGH AND Y == 0 */
2882 /* Goto YState = 1 */
2884 msr_value.high = 0x00000002;
2885 msr_value.low = 0x00000A00;
2886 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_SETM0CTL + 3, &msr_value);
2888 /* N3 - DISPE LOW */
2889 /* Goto YState = 0 */
2891 msr_value.high = 0x00080000;
2892 msr_value.low = 0x00000000;
2893 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 3, &msr_value);
2895 /* Y0 -> Y1 (SET M3) */
2897 msr_value.high = 0x00000000;
2898 msr_value.low = 0x0000C000;
2899 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 18, &msr_value);
2901 /* Y1 -> Y0 (SET N3) */
2903 msr_value.low = 0x0000A000;
2904 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 17, &msr_value);
2906 /* Y1 -> Y2 (SET N2) */
2908 msr_value.low = 0x00000A00;
2909 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 19, &msr_value);
2911 /* N5 (XSTATE = 10 && CMP2 <= V. COUNTER <= CMP3) && DISPE && Y == 0 */
2912 /* CRC into REGB */
2914 msr_value.high = 0x00000002;
2915 msr_value.low = 0x10800B20;
2916 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 5, &msr_value);
2918 /* N6 (XSTATE = 10 && CMP2 <= V. COUNTER <= CMP3) && DISPE && Y == 1 */
2919 /* CRC into REGB */
2921 msr_value.high = 0x00000002;
2922 msr_value.low = 0x10800D20;
2923 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 6, &msr_value);
2926 /* M4 (XSTATE = 00 AND VSYNC HIGH) */
2927 /* Goto state 01 */
2928 /* Note: VSync = H3A */
2930 msr_value.high = 0x00000001;
2931 msr_value.low = 0x000000A0;
2932 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_SETM0CTL + 4, &msr_value);
2934 /* N0 (XSTATE = 01 AND VSYNC LOW) */
2935 /* Goto state 02 */
2936 /* Note: VSync low = H3B */
2938 msr_value.high = 0x00040000;
2939 msr_value.low = 0x000000C0;
2940 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL, &msr_value);
2942 /* M5 (XSTATE = 10 AND VSYNC HIGH) */
2943 /* Goto state 11 */
2945 msr_value.high = 0x00000001;
2946 msr_value.low = 0x00000120;
2947 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_SETM0CTL + 5, &msr_value);
2949 /* N1 (XSTATE = 10 and DISPE HIGH) */
2950 /* Increment H. Counter */
2951 /* Note: DispE = H4 */
2953 msr_value.high = 0x00000002;
2954 msr_value.low = 0x00000120;
2955 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 1, &msr_value);
2957 /* M0 (XSTATE = 10 and H. COUNTER == LIMIT) */
2958 /* Clear H. Counter and increment V. Counter */
2960 msr_value.high = 0x00000000;
2961 msr_value.low = 0x00000122;
2962 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_SETM0CTL, &msr_value);
2964 /* N4 (XSTATE = 10 && CMP0 <= H. COUNTER <= CMP1 && CMP2 <= V. COUNTER <= CMP3) && DISPE */
2965 /* CRC into REGB */
2967 msr_value.high = 0x00000002;
2968 msr_value.low = 0x10C20120;
2969 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 4, &msr_value);
2971 /* COMPARATOR 0 VALUE */
2972 /* We subtract 1 to account for a pipeline delay in the GLCP. */
2973 /* When the x coordinate is 0, we must play a special game. */
2974 /* If the width is exactly 1, we will set up a state machine */
2975 /* to only CRC the first pixel. Otherwise, we will set it */
2976 /* as an OR combination of a state that CRCs the first pixel */
2977 /* and a state that CRCs 1 clock delayed width (width - 1) */
2979 msr_value.high = 0;
2980 if (x > 1) msr_value.low = (x - 1) & 0xFFFF;
2981 else msr_value.low = x;
2982 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0, &msr_value);
2984 /* COMPARATOR 1 VALUE */
2986 if ((x == 0 || x == 1) && width > 1) msr_value.low += width - 2;
2987 else msr_value.low += width - 1;
2988 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0 + 2, &msr_value);
2990 /* COMPARATOR 2 VALUE */
2992 msr_value.low = y << 16;
2993 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0 + 4, &msr_value);
2995 /* COMPARATOR 3 VALUE */
2997 msr_value.low += (height - 1) << 16;
2998 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0 + 6, &msr_value);
3000 /* COMPARATOR MASKS */
3001 /* Comparators 0 and 1 refer to lower 16 bits of RegB */
3003 msr_value.low = 0x0000FFFF;
3004 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_CMPMASK0, &msr_value);
3005 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_CMPMASK0 + 2, &msr_value);
3007 /* Comparators 2 and 3 refer to upper 16 bits of RegB */
3009 msr_value.low = 0xFFFF0000;
3010 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_CMPMASK0 + 4, &msr_value);
3011 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_CMPMASK0 + 6, &msr_value);
3013 /* SET REGB MASK */
3014 /* We set the mask such that all all 32 bits of data are CRCed */
3016 msr_value.low = 0xFFFFFFFF;
3017 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_REGBMASK, &msr_value);
3019 /* ACTIONS */
3021 /* STATE 00->01 (SET 4M) */
3023 msr_value.low = 0x000C0000;
3024 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 14, &msr_value);
3026 /* STATE 01->10 (SET 0N) */
3028 msr_value.low = 0x0000000A;
3029 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 15, &msr_value);
3031 /* STATE 10->11 (SET 5M) */
3033 msr_value.low = 0x00C00000;
3034 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 16, &msr_value);
3036 /* CLEAR REGA WHEN TRANSITIONING TO STATE 10 */
3037 /* Do not clear RegB as the initial value must be 0x00000001 */
3039 msr_value.low = 0x0000000A;
3040 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0, &msr_value);
3042 /* REGISTER ACTION 1 */
3043 /* CRC into RegB if cmp0 <= h.counter <= cmp1 && cmp2 <= v. counter < cmp3 && 7 xstate = 10 */
3044 /* Increment h.counter if xstate = 10 and HSync is low. */
3046 msr_value.low = 0x000A00A0;
3047 if (x == 0 && width == 1)
3048 msr_value.low = 0x00A000A0;
3049 else if (x == 1 && width == 1)
3050 msr_value.low = 0x0A0000A0;
3051 else if (x == 1 && width > 1)
3052 msr_value.low |= 0x0A000000;
3054 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 1, &msr_value);
3056 /* REGISTER ACTION 2 */
3057 /* Increment V. Counter in REGA */
3059 msr_value.low = 0x0000000C;
3060 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 2, &msr_value);
3062 /* SET REGB TO 0x00000001 */
3064 msr_value.low = 0x00000001;
3065 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_REGB, &msr_value);
3067 /* SET XSTATE TO 0 */
3069 msr_value.low = 0x00000000;
3070 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_XSTATE, &msr_value);
3072 /* SET YSTATE TO 0 */
3074 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_YSTATE, &msr_value);
3076 /* CLEAR ALL OTHER ACTIONS */
3077 /* This prevents side-effects from previous accesses to the GLCP */
3078 /* debug logic. */
3080 msr_value.low = 0x00000000;
3081 msr_value.high = 0x00000000;
3082 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 3, &msr_value);
3083 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 4, &msr_value);
3084 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 5, &msr_value);
3085 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 6, &msr_value);
3086 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 7, &msr_value);
3087 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 8, &msr_value);
3088 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 9, &msr_value);
3089 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 10, &msr_value);
3090 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 11, &msr_value);
3091 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 12, &msr_value);
3092 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 13, &msr_value);
3093 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 20, &msr_value);
3095 /* SET DIAG SETTINGS BASED ON DESIRED CRC */
3097 if (crc_source == VG_CRC_SOURCE_POSTFLICKER || crc_source == VG_CRC_SOURCE_POSTFLICKER_EVEN)
3099 diag = 0x80808086;
3101 /* ENABLE HW CLOCK GATING AND SET GLCP CLOCK TO DOT CLOCK */
3103 msr_value.high = 0;
3104 msr_value.low = 5;
3105 msr_write64 (MSR_DEVICE_GEODELX_GLCP, MSR_GEODELINK_PM, &msr_value);
3106 msr_value.low = 0;
3107 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
3108 msr_value.low = 3;
3109 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
3111 /* SET REGA LIMITS */
3112 /* Lower counter uses pixels/line */
3113 /* Upper counter is 0xFFFF to prevent rollover. */
3115 msr_value.low = 0xFFFF0000 | (hactive - 1);
3116 if (READ_REG32 (DC3_DISPLAY_CFG) & DC3_DCFG_DCEN)
3118 msr_value.low += hblankstart - hactive;
3119 msr_value.low += htotal - hblankend;
3121 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_REGAVAL, &msr_value);
3123 /* USE H4 FUNCTION A FOR DISPE AND H4 FUNCTION B FOR NOT DISPE */
3124 /* DISPE is bit 34 */
3126 msr_value.high = 0x00000002;
3127 msr_value.low = 0x20000FF0;
3128 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 4, &msr_value);
3130 /* USE H3 FUNCTION A FOR VSYNC AND H3 FUNCTION B FOR NOT VSYNC */
3131 /* VSYNC is bit 32. */
3133 msr_value.high = 0x00000000;
3134 msr_value.low = 0x002055AA;
3135 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 3, &msr_value);
3137 else if (crc_source == VG_CRC_SOURCE_PREFLICKER || crc_source == VG_CRC_SOURCE_PREFLICKER_EVEN)
3139 diag = 0x801F8032;
3141 /* ENABLE HW CLOCK GATING AND SET GLCP CLOCK TO GEODELINK CLOCK */
3143 msr_value.high = 0;
3144 msr_value.low = 5;
3145 msr_write64 (MSR_DEVICE_GEODELX_GLCP, MSR_GEODELINK_PM, &msr_value);
3146 msr_value.low = 0;
3147 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
3148 msr_value.low = 2;
3149 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
3151 /* SET REGA LIMITS */
3152 /* Lower counter uses pixels/line */
3153 /* Upper counter is 0xFFFF to prevent rollover. */
3155 msr_value.low = 0xFFFF0000 | (hactive - 1);
3156 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_REGAVAL, &msr_value);
3158 /* USE H4 FUNCTION A FOR DISPE AND H4 FUNCTION B FOR NOT DISPE */
3159 /* DISPE is bit 47 */
3161 msr_value.high = 0x00000002;
3162 msr_value.low = 0xF0000FF0;
3163 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 4, &msr_value);
3165 /* USE H3 FUNCTION A FOR VSYNC AND H3 FUNCTION B FOR NOT VSYNC */
3166 /* VSYNC is bit 45. */
3168 msr_value.high = 0x00000000;
3169 msr_value.low = 0x002D55AA;
3170 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 3, &msr_value);
3172 else
3174 /* PREFILTER CRC */
3176 diag = 0x80138048;
3177 msr_write64 (MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_DIAG, &msr_value);
3179 /* ENABLE HW CLOCK GATING AND SET GLCP CLOCK TO GEODELINK CLOCK */
3181 msr_value.high = 0;
3182 msr_value.low = 5;
3183 msr_write64 (MSR_DEVICE_GEODELX_GLCP, MSR_GEODELINK_PM, &msr_value);
3184 msr_value.low = 0;
3185 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
3186 msr_value.low = 2;
3187 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
3189 /* SET REGA LIMITS */
3190 /* Lower counter uses pixels/line */
3191 /* Upper counter is 0xFFFF to prevent rollover. */
3192 /* Note that we are assuming that the number of */
3193 /* source pixels is specified in the FB_ACTIVE register */
3195 msr_value.low = 0xFFFF0000 | ((READ_REG32 (DC3_FB_ACTIVE) >> 16) & 0xFFF);
3196 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_REGAVAL, &msr_value);
3198 /* USE H4 FUNCTION A FOR DISPE AND H4 FUNCTION B FOR NOT DISPE */
3199 /* DISPE is bit 55 */
3201 msr_value.high = 0x00000003;
3202 msr_value.low = 0x70000FF0;
3203 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 4, &msr_value);
3205 /* USE H3 FUNCTION A FOR VSYNC AND H3 FUNCTION B FOR NOT VSYNC */
3206 /* VSYNC is bit 53. */
3208 msr_value.high = 0x00000000;
3209 msr_value.low = 0x003555AA;
3210 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 3, &msr_value);
3213 /* WAIT FOR THE CORRECT FIELD */
3214 /* We use the VG line count and field indicator to determine when */
3215 /* to kick off a CRC. */
3217 if (crc_source & VG_CRC_SOURCE_EVEN) field = 0;
3218 else field = DC3_LNCNT_EVEN_FIELD;
3220 if (READ_REG32 (DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN)
3222 /* WAIT FOR THE BEGINNING OF THE FIELD (LINE 1-5) */
3223 /* Note that we wait for the field to be odd when CRCing the even */
3224 /* field and vice versa. This is because the CRC will not begin */
3225 /* until the following field. */
3229 line = READ_REG32 (DC3_LINE_CNT_STATUS);
3230 } while ((line & DC3_LNCNT_EVEN_FIELD) != field ||
3231 ((line & DC3_LNCNT_V_LINE_CNT) >> 16) < 1 ||
3232 ((line & DC3_LNCNT_V_LINE_CNT) >> 16) > 5);
3234 else
3236 /* NON-INTERLACED - EVEN FIELD CRCS ARE INVALID */
3238 if (crc_source & VG_CRC_SOURCE_EVEN)
3239 return 0xFFFFFFFF;
3242 /* UPDATE VG DIAG OUTPUT */
3244 msr_value.high = 0;
3245 msr_value.low = diag;
3246 msr_write64 (MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_DIAG, &msr_value);
3248 /* CONFIGURE DIAG CONTROL */
3249 /* Set RegA action1 to increment lower 16 bits and clear at limit. (5) */
3250 /* Set RegA action2 to increment upper 16 bits. (6) */
3251 /* Set RegB action1 to CRC32 (1) */
3252 /* Set all comparators to REGA override (0,1 lower mbus, 2,3 upper mbus) */
3253 /* Enable all actions */
3255 msr_value.low = 0x80EA20A0;
3256 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DIAGCTL, &msr_value);
3258 /* DELAY TWO FRAMES */
3260 while (READ_REG32 (DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA);
3261 while (!(READ_REG32 (DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA));
3262 while (READ_REG32 (DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA);
3263 while (!(READ_REG32 (DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA));
3264 while (READ_REG32 (DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA);
3266 /* VERIFY THAT XSTATE = 11 */
3268 msr_read64 (MSR_DEVICE_GEODELX_GLCP, GLCP_XSTATE, &msr_value);
3269 if ((msr_value.low & 3) == 3)
3271 msr_read64 (MSR_DEVICE_GEODELX_GLCP, GLCP_REGB, &msr_value);
3273 crc = msr_value.low;
3276 /* DISABLE VG DIAG BUS OUTPUTS */
3278 msr_value.low = 0x00000000;
3279 msr_value.high = 0x00000000;
3280 msr_write64 (MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_DIAG, &msr_value);
3282 /* DISABLE GLCP ACTIONS */
3284 msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DIAGCTL, &msr_value);
3286 return crc;
3289 /*---------------------------------------------------------------------------
3290 * vg_get_scaler_filter_coefficients
3292 * This routine gets the vertical and horizontal filter coefficients for
3293 * graphics scaling. The coefficients are sign extended to 32-bit values.
3294 *---------------------------------------------------------------------------*/
3296 int vg_get_scaler_filter_coefficients (long h_taps[][5], long v_taps[][3])
3298 unsigned long irqfilt, i;
3299 unsigned long temp;
3300 long coeff0, coeff1, coeff2;
3301 unsigned long lock;
3303 /* ENABLE ACCESS TO THE HORIZONTAL COEFFICIENTS */
3305 lock = READ_REG32 (DC3_UNLOCK);
3306 irqfilt = READ_REG32 (DC3_IRQ_FILT_CTL);
3307 irqfilt |= DC3_IRQFILT_H_FILT_SEL;
3309 /* WRITE COEFFICIENTS */
3310 /* Coefficient indexes do not auto-increment, so we must */
3311 /* write the address for every phase */
3313 WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
3315 for (i = 0; i < 256; i++)
3317 WRITE_REG32 (DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
3319 temp = READ_REG32 (DC3_FILT_COEFF1);
3320 coeff0 = (temp & 0x3FF);
3321 coeff1 = (temp >> 10) & 0x3FF;
3322 coeff2 = (temp >> 20) & 0x3FF;
3324 h_taps[i][0] = (coeff0 << 22) >> 22;
3325 h_taps[i][1] = (coeff1 << 22) >> 22;
3326 h_taps[i][2] = (coeff2 << 22) >> 22;
3328 temp = READ_REG32 (DC3_FILT_COEFF2);
3329 coeff0 = (temp & 0x3FF);
3330 coeff1 = (temp >> 10) & 0x3FF;
3332 h_taps[i][3] = (coeff0 << 22) >> 22;
3333 h_taps[i][4] = (coeff1 << 22) >> 22;
3336 /* ENABLE ACCESS TO THE VERTICAL COEFFICIENTS */
3338 irqfilt &= ~DC3_IRQFILT_H_FILT_SEL;
3340 /* WRITE COEFFICIENTS */
3342 for (i = 0; i < 256; i++)
3344 WRITE_REG32 (DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
3346 temp = READ_REG32 (DC3_FILT_COEFF1);
3347 coeff0 = (temp & 0x3FF);
3348 coeff1 = (temp >> 10) & 0x3FF;
3349 coeff2 = (temp >> 20) & 0x3FF;
3351 v_taps[i][0] = (coeff0 << 22) >> 22;
3352 v_taps[i][1] = (coeff1 << 22) >> 22;
3353 v_taps[i][2] = (coeff2 << 22) >> 22;
3356 WRITE_REG32 (DC3_UNLOCK, lock);
3358 return CIM_STATUS_OK;
3361 /*---------------------------------------------------------------------------
3362 * vg_get_flicker_filter_configuration
3364 * This routine returns the current VG flicker filter configuration.
3365 *---------------------------------------------------------------------------*/
3367 int vg_get_flicker_filter_configuration (unsigned long *strength, int *flicker_alpha)
3369 unsigned long genlk_ctl;
3371 if (!strength || !flicker_alpha)
3372 return CIM_STATUS_INVALIDPARAMS;
3374 genlk_ctl = READ_REG32 (DC3_GENLK_CTL);
3375 *strength = genlk_ctl & DC3_GC_FLICKER_FILTER_MASK;
3376 if (genlk_ctl & DC3_GC_ALPHA_FLICK_ENABLE)
3377 *flicker_alpha = 1;
3378 else
3379 *flicker_alpha = 0;
3381 return CIM_STATUS_OK;
3384 /*---------------------------------------------------------------------------
3385 * vg_get_display_pitch
3387 * This routine returns the current stride between successive lines of frame
3388 * buffer data.
3389 *---------------------------------------------------------------------------*/
3391 unsigned long vg_get_display_pitch (void)
3393 return ((READ_REG32 (DC3_GFX_PITCH) & 0x0000FFFF) << 3);
3396 /*---------------------------------------------------------------------------
3397 * vg_get_frame_buffer_line_size
3399 * This routine returns the current size in bytes of one line of frame buffer
3400 * data.
3401 *---------------------------------------------------------------------------*/
3403 unsigned long vg_get_frame_buffer_line_size (void)
3405 return ((READ_REG32 (DC3_LINE_SIZE) & 0x3FF) << 3);
3408 /*---------------------------------------------------------------------------
3409 * vg_get_current_vline
3411 * This routine returns the number of the current line that is being displayed
3412 * by the display controller.
3413 *---------------------------------------------------------------------------*/
3415 unsigned long vg_get_current_vline (void)
3417 unsigned long current_line;
3419 /* READ THE REGISTER TWICE TO ENSURE THAT THE VALUE IS NOT TRANSITIONING */
3423 current_line = READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_V_LINE_CNT;
3425 while (current_line != (READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_V_LINE_CNT));
3427 return (current_line >> 16);
3430 /*---------------------------------------------------------------------------
3431 * vg_get_display_offset
3433 * This routine returns the offset into the frame buffer for the first pixel
3434 * of the display.
3435 *---------------------------------------------------------------------------*/
3437 unsigned long vg_get_display_offset (void)
3439 return (READ_REG32(DC3_FB_ST_OFFSET) & 0x0FFFFFFF);
3442 /*---------------------------------------------------------------------------
3443 * vg_get_cursor_info
3445 * This routine returns the current settings for the hardware cursor.
3446 *---------------------------------------------------------------------------*/
3448 int vg_get_cursor_info (VG_CURSOR_DATA *cursor_data)
3450 unsigned long temp;
3452 /* CURSOR OFFSET */
3454 cursor_data->cursor_offset = READ_REG32 (DC3_CURS_ST_OFFSET) & 0x0FFFFFFF;
3456 /* CURSOR X POSITION */
3458 temp = READ_REG32 (DC3_CURSOR_X);
3459 cursor_data->cursor_x = temp & 0x7FF;
3460 cursor_data->clipx = (temp >> 11) & 0x3F;
3462 /* CURSOR Y POSITION */
3464 temp = READ_REG32 (DC3_CURSOR_Y);
3465 cursor_data->cursor_y = temp & 0x7FF;
3466 cursor_data->clipy = (temp >> 11) & 0x3F;
3468 /* CURSOR COLORS */
3470 WRITE_REG32 (DC3_PAL_ADDRESS, 0x100);
3471 cursor_data->mono_color0 = READ_REG32 (DC3_PAL_DATA);
3472 cursor_data->mono_color1 = READ_REG32 (DC3_PAL_DATA);
3474 /* CURSOR ENABLES */
3476 temp = READ_REG32 (DC3_GENERAL_CFG);
3477 if (temp & DC3_GCFG_CURE) cursor_data->enable = 1;
3478 else cursor_data->enable = 0;
3479 if (temp & DC3_GCFG_CLR_CUR) cursor_data->color_cursor = 1;
3480 else cursor_data->color_cursor = 0;
3482 return CIM_STATUS_OK;
3485 /*-----------------------------------------------------------------------------
3486 * vg_get_display_palette_entry
3488 * This routine reads a single entry in the 8BPP display palette.
3489 *----------------------------------------------------------------------------*/
3491 int vg_get_display_palette_entry (unsigned long index, unsigned long *entry)
3493 if (index > 0xFF)
3494 return CIM_STATUS_INVALIDPARAMS;
3496 WRITE_REG32 (DC3_PAL_ADDRESS, index);
3497 *entry = READ_REG32 (DC3_PAL_DATA);
3499 return CIM_STATUS_OK;
3502 /*-----------------------------------------------------------------------------
3503 * vg_get_border_color
3505 * This routine reads the current border color for centered displays.
3506 *----------------------------------------------------------------------------*/
3508 unsigned long vg_get_border_color (void)
3510 WRITE_REG32 (DC3_PAL_ADDRESS, 0x104);
3511 return READ_REG32 (DC3_PAL_DATA);
3514 /*-----------------------------------------------------------------------------
3515 * vg_get_display_palette
3517 * This routines reads the entire contents of the display palette into a buffer.
3518 * The display palette consists of 256 X:R:G:B values.
3519 *----------------------------------------------------------------------------*/
3521 int vg_get_display_palette (unsigned long *palette)
3523 unsigned long i;
3525 if (palette)
3527 WRITE_REG32 (DC3_PAL_ADDRESS, 0);
3528 for (i = 0; i < 256; i++)
3530 palette[i] = READ_REG32 (DC3_PAL_DATA);
3532 return CIM_STATUS_OK;
3534 return CIM_STATUS_INVALIDPARAMS;
3537 /*-----------------------------------------------------------------------------
3538 * vg_get_compression_info
3540 * This routines reads the current status of the display compression hardware.
3541 *----------------------------------------------------------------------------*/
3543 int vg_get_compression_info (VG_COMPRESSION_DATA *comp_data)
3545 comp_data->compression_offset = READ_REG32 (DC3_CB_ST_OFFSET) & 0x0FFFFFFF;
3546 comp_data->pitch = (READ_REG32 (DC3_GFX_PITCH) >> 13) & 0x7FFF8;
3547 comp_data->size = ((READ_REG32 (DC3_LINE_SIZE) >> (DC3_LINE_SIZE_CB_SHIFT - 3)) & 0x3F8) + 24;
3549 return CIM_STATUS_OK;
3552 /*-----------------------------------------------------------------------------
3553 * vg_get_compression_enable
3555 * This routines reads the current enable status of the display compression hardware.
3556 *----------------------------------------------------------------------------*/
3558 int vg_get_compression_enable (void)
3560 if (READ_REG32 (DC3_GENERAL_CFG) & DC3_GCFG_CMPE)
3561 return 1;
3563 return 0;
3566 /*-----------------------------------------------------------------------------
3567 * vg_get_valid_bit
3568 *----------------------------------------------------------------------------*/
3570 int vg_get_valid_bit (int line)
3572 unsigned long offset;
3573 unsigned long valid;
3574 unsigned long lock;
3576 lock = READ_REG32 (DC3_UNLOCK);
3577 offset = READ_REG32 (DC3_PHY_MEM_OFFSET) & 0xFF000000;
3578 offset |= line;
3580 WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
3581 WRITE_REG32 (DC3_PHY_MEM_OFFSET, offset);
3582 WRITE_REG32 (DC3_UNLOCK, lock);
3583 valid = READ_REG32 (DC3_DV_ACC) & 2;
3585 if (valid) return 1;
3586 return 0;
3589 #endif