3 * Copyright (C) 2005 Advanced Micro Devices, Inc. All Rights Reserved.
10 * Cimarron display controller routines. These routines program the display
11 * mode and configure the hardware cursor and video buffers.
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
39 *---------------------------------------------------------------------------*/
41 int vg_delay_milliseconds (unsigned long ms
)
43 /* ASSUME 500 MHZ 20 CLOCKS PER READ */
45 unsigned long loop
= ms
* 25000;
48 READ_REG32 (DC3_UNLOCK
);
53 /*---------------------------------------------------------------------------
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
,
64 VG_QUERY_MODE crt_query
;
65 VG_DISPLAY_MODE crt_mode
;
68 crt_query
.active_width
= dst_width
;
69 crt_query
.active_height
= dst_height
;
72 crt_query
.query_flags
= VG_QUERYFLAG_ACTIVEWIDTH
|
73 VG_QUERYFLAG_ACTIVEHEIGHT
|
77 mode
= vg_get_display_mode_index (&crt_query
);
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 /*---------------------------------------------------------------------------
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
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
;
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 */
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
|
152 mode
= vg_get_display_mode_index (&panel_query
);
154 /* COPY THE DATA FROM THE MODE TABLE TO A TEMPORARY STRUCTURE */
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 /*---------------------------------------------------------------------------
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
;
233 if (!src_width
|| !src_height
)
234 return CIM_STATUS_INVALIDPARAMS
;
237 tv_query
.encoder
= encoder
;
238 tv_query
.tvmode
= tvres
;
239 tv_query
.query_flags
= VG_QUERYFLAG_BPP
|
241 VG_QUERYFLAG_ENCODER
|
244 mode
= vg_get_display_mode_index (&tv_query
);
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
;
273 *src_height
+= CimarronDisplayModes
[mode
].vactive_even
;
274 *src_height
-= v_overscan
<< 1;
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 */
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
;
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
;
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 /*---------------------------------------------------------------------------
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
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
;
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
;
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. */
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
);
428 starting_width
= mode_params
->hactive
;
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
);
439 starting_height
= output_height
;
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
);
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
);
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 */
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
;
506 /* CLEAR PANNING OFFSETS */
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
;
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
;
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
;
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
);
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 /*-------------------------------------------------------------------*/
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
);
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
;
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. */
784 size
= mode_params
->src_width
;
785 line_size
= starting_width
;
792 size
= mode_params
->src_width
<< 1;
793 line_size
= starting_width
<< 1;
800 size
= mode_params
->src_width
<< 2;
801 line_size
= starting_width
<< 2; break;
804 /* CALCULATE DV RAM SETTINGS AND POWER OF 2 PITCH */
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
)
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
;
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 */
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
))
878 /* Set agressive watermarks and disallow forced low priority */
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. */
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;
909 else if ((mode_params
->flags
& VG_MODEFLAG_BANDWIDTHMASK
) == VG_MODEFLAG_LOW_BAND
)
912 /* Set low watermarks and allow larger regions of forced low priority. */
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;
933 /* LEGACY CHARACTERISTICS */
934 /* Arbitration from a single set of watermarks. */
937 msr_value
.low
|= DC3_SPARE_DISABLE_VFIFO_WM
| DC3_SPARE_DISABLE_INIT_VID_PRI
;
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
|
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 /*---------------------------------------------------------------------------
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
;
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
);
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
)
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;
1064 if (!query
|| !query
->query_flags
)
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
;
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
;
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
;
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)
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
;
1193 /* RETURN DISPLAY MODE INDEX */
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
)
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
)
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 */
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
;
1336 flags
|= VG_MODEFLAG_INT_LINEDOUBLE
;
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
;
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
;
1355 else if (temp
== DC3_DCFG_DISP_MODE_24BPP
)
1357 iflags
|= VG_SUPPORTFLAG_24BPP
;
1360 else if (temp
== DC3_DCFG_DISP_MODE_32BPP
)
1362 iflags
|= VG_SUPPORTFLAG_32BPP
;
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
;
1373 else if (temp
== DC3_DCFG_15BPP
)
1375 iflags
|= VG_SUPPORTFLAG_15BPP
;
1378 else if (temp
== DC3_DCFG_12BPP
)
1380 iflags
|= VG_SUPPORTFLAG_12BPP
;
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
;
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
)
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: */
1432 /* Fout = 48.000 * -------------- */
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
)
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
;
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
));
1512 temp0
= CimarronHorizontalGraphicsFilter
[i
][0];
1513 temp1
= CimarronHorizontalGraphicsFilter
[i
][1];
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
));
1540 temp0
= CimarronVerticalGraphicsFilter
[i
];
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
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
;
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
)
1606 unsigned long timeout
;
1607 unsigned long index
= 0;
1608 unsigned long unlock
, i
;
1609 unsigned long pll_high
, pll_low
;
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. */
1618 if (!(pll_flags
& VG_PLL_MANUAL
))
1620 min
= (long)CimarronPLLFrequencies
[0].frequency
- (long)frequency
;
1624 for (i
= 1; i
< NUM_CIMARRON_PLL_FREQUENCIES
; i
++)
1626 diff
= (long)CimarronPLLFrequencies
[i
].frequency
- (long)frequency
;
1637 pll_high
= CimarronPLLFrequencies
[index
].pll_value
& 0x00007FFF;
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
)
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 */
1706 return CIM_STATUS_OK
;
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
;
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 */
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
;
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
;
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
)
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
]);
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);
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
)
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
]);
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
)
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 */
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 /*---------------------------------------------------------------------------
2007 * This routine sets the correct display offset based on the current cursor
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
)
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
)
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. */
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
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
;
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
;
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);
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
)
2215 unsigned long unlock
, gcfg
;
2218 unlock
= READ_REG32 (DC3_UNLOCK
);
2219 gcfg
= READ_REG32 (DC3_GENERAL_CFG
);
2220 WRITE_REG32 (DC3_UNLOCK
, DC3_UNLOCK_VALUE
);
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
;
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
)
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
)
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
)
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
;
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 */
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
));
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
;
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
))
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 /*---------------------------------------------------------------------------
2457 * This routine saves all persistent VG state information.
2458 *---------------------------------------------------------------------------*/
2460 int vg_save_state (VG_SAVE_RESTORE
*vg_state
)
2463 unsigned long irqfilt
;
2464 unsigned long offset
, i
;
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
;
2574 if (i
== NUM_CIMARRON_PLL_FREQUENCIES
)
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 /*---------------------------------------------------------------------------
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
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
))
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
);
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;
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);
2804 /* NON-INTERLACED - EVEN FIELD CRCS ARE INVALID */
2806 if (crc_source
& VG_CRC_SOURCE_EVEN
)
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
);
2833 /*---------------------------------------------------------------------------
2834 * vg_read_window_crc
2836 * This routine reads the Cyclic Redundancy Check (CRC) value for a sub-section
2838 *---------------------------------------------------------------------------*/
2840 unsigned long vg_read_window_crc (int crc_source
, unsigned long x
, unsigned long y
,
2841 unsigned long width
, unsigned long height
)
2844 unsigned long crc
= 0;
2845 unsigned long hactive
, hblankstart
;
2846 unsigned long htotal
, hblankend
;
2847 unsigned long line
, field
;
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
))
2860 /* DISABLE GLCP ACTIONS */
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 */
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 */
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 */
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) */
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) */
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) */
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 */
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) */
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
);
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
);
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 */
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
)
3101 /* ENABLE HW CLOCK GATING AND SET GLCP CLOCK TO DOT CLOCK */
3105 msr_write64 (MSR_DEVICE_GEODELX_GLCP
, MSR_GEODELINK_PM
, &msr_value
);
3107 msr_write64 (MSR_DEVICE_GEODELX_GLCP
, GLCP_DBGCLKCTL
, &msr_value
);
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
)
3141 /* ENABLE HW CLOCK GATING AND SET GLCP CLOCK TO GEODELINK CLOCK */
3145 msr_write64 (MSR_DEVICE_GEODELX_GLCP
, MSR_GEODELINK_PM
, &msr_value
);
3147 msr_write64 (MSR_DEVICE_GEODELX_GLCP
, GLCP_DBGCLKCTL
, &msr_value
);
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
);
3177 msr_write64 (MSR_DEVICE_GEODELX_VG
, MSR_GEODELINK_DIAG
, &msr_value
);
3179 /* ENABLE HW CLOCK GATING AND SET GLCP CLOCK TO GEODELINK CLOCK */
3183 msr_write64 (MSR_DEVICE_GEODELX_GLCP
, MSR_GEODELINK_PM
, &msr_value
);
3185 msr_write64 (MSR_DEVICE_GEODELX_GLCP
, GLCP_DBGCLKCTL
, &msr_value
);
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);
3236 /* NON-INTERLACED - EVEN FIELD CRCS ARE INVALID */
3238 if (crc_source
& VG_CRC_SOURCE_EVEN
)
3242 /* UPDATE VG DIAG OUTPUT */
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
);
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
;
3300 long coeff0
, coeff1
, coeff2
;
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
)
3381 return CIM_STATUS_OK
;
3384 /*---------------------------------------------------------------------------
3385 * vg_get_display_pitch
3387 * This routine returns the current stride between successive lines of frame
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
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
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
)
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;
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
)
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
)
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
)
3566 /*-----------------------------------------------------------------------------
3568 *----------------------------------------------------------------------------*/
3570 int vg_get_valid_bit (int line
)
3572 unsigned long offset
;
3573 unsigned long valid
;
3576 lock
= READ_REG32 (DC3_UNLOCK
);
3577 offset
= READ_REG32 (DC3_PHY_MEM_OFFSET
) & 0xFF000000;
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;