2
* Copyright (c) 2006 Advanced Micro Devices, Inc.
4
* Permission is hereby granted, free of charge, to any person obtaining a
5
* copy of this software and associated documentation files (the "Software"),
6
* to deal in the Software without restriction, including without limitation
7
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
* and/or sell copies of the Software, and to permit persons to whom the
9
* Software is furnished to do so, subject to the following conditions:
11
* The above copyright notice and this permission notice shall be included in
12
* all copies or substantial portions of the Software.
14
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20
* DEALINGS IN THE SOFTWARE.
22
* Neither the name of the Advanced Micro Devices, Inc. nor the names of its
23
* contributors may be used to endorse or promote products derived from this
24
* software without specific prior written permission.
28
* Cimarron display controller routines. These routines program the display
29
* mode and configure the hardware cursor and video buffers.
32
/*---------------------*/
33
/* CIMARRON VG GLOBALS */
34
/*---------------------*/
36
CIMARRON_STATIC unsigned long vg3_x_hotspot = 0;
37
CIMARRON_STATIC unsigned long vg3_y_hotspot = 0;
38
CIMARRON_STATIC unsigned long vg3_cursor_offset = 0;
39
CIMARRON_STATIC unsigned long vg3_mode_width = 0;
40
CIMARRON_STATIC unsigned long vg3_mode_height = 0;
41
CIMARRON_STATIC unsigned long vg3_panel_width = 0;
42
CIMARRON_STATIC unsigned long vg3_panel_height = 0;
43
CIMARRON_STATIC unsigned long vg3_delta_x = 0;
44
CIMARRON_STATIC unsigned long vg3_delta_y = 0;
45
CIMARRON_STATIC unsigned long vg3_bpp = 0;
47
CIMARRON_STATIC unsigned long vg3_color_cursor = 0;
48
CIMARRON_STATIC unsigned long vg3_panel_enable = 0;
50
/*---------------------------------------------------------------------------
51
* vg_delay_milliseconds
53
* This routine delays for a number of milliseconds based on a crude
55
*--------------------------------------------------------------------------*/
58
vg_delay_milliseconds(unsigned long ms)
60
/* ASSUME 500 MHZ 20 CLOCKS PER READ */
62
unsigned long loop = ms * 25000;
65
READ_REG32(DC3_UNLOCK);
70
/*---------------------------------------------------------------------------
73
* This routine sets a CRT display mode using predefined Cimarron timings.
74
* The source width and height are specified to allow scaling.
75
*--------------------------------------------------------------------------*/
78
vg_set_display_mode(unsigned long src_width, unsigned long src_height,
79
unsigned long dst_width, unsigned long dst_height,
80
int bpp, int hz, unsigned long flags)
82
VG_QUERY_MODE crt_query;
83
VG_DISPLAY_MODE crt_mode;
86
crt_query.active_width = dst_width;
87
crt_query.active_height = dst_height;
90
crt_query.query_flags = VG_QUERYFLAG_ACTIVEWIDTH |
91
VG_QUERYFLAG_ACTIVEHEIGHT | VG_QUERYFLAG_BPP | VG_QUERYFLAG_REFRESH;
93
mode = vg_get_display_mode_index(&crt_query);
95
crt_mode = CimarronDisplayModes[mode];
96
crt_mode.src_width = src_width;
97
crt_mode.src_height = src_height;
99
/* ADD USER-REQUESTED FLAGS */
101
crt_mode.flags |= (flags & VG_MODEFLAG_VALIDUSERFLAGS);
103
if (flags & VG_MODEFLAG_OVERRIDE_BAND) {
104
crt_mode.flags &= ~VG_MODEFLAG_BANDWIDTHMASK;
105
crt_mode.flags |= (flags & VG_MODEFLAG_BANDWIDTHMASK);
107
if (flags & VG_MODEFLAG_INT_OVERRIDE) {
108
crt_mode.flags &= ~VG_MODEFLAG_INT_MASK;
109
crt_mode.flags |= (flags & VG_MODEFLAG_INT_MASK);
112
return vg_set_custom_mode(&crt_mode, bpp);
114
return CIM_STATUS_ERROR;
117
/*---------------------------------------------------------------------------
120
* This routine sets a panel mode using predefined Cimarron fixed timings.
121
* The source width and height specify the width and height of the data in
122
* the frame buffer. The destination width and height specify the width and
123
* height of the active data to be displayed. The panel width and height
124
* specify the dimensions of the panel. This interface allows the user to
125
* scale or center graphics data or both. To perform scaling, the src width
126
* or height should be different than the destination width or height. To
127
* perform centering or panning, the destination width and height should be
128
* different than the panel resolution.
129
*--------------------------------------------------------------------------*/
132
vg_set_panel_mode(unsigned long src_width, unsigned long src_height,
133
unsigned long dst_width, unsigned long dst_height,
134
unsigned long panel_width, unsigned long panel_height,
135
int bpp, unsigned long flags)
137
unsigned long sync_width;
138
unsigned long sync_offset;
139
VG_QUERY_MODE panel_query;
140
VG_DISPLAY_MODE panel_mode;
143
/* SEARCH CIMARRON'S TABLE OF PREDEFINED PANEL MODES */
144
/* If the destination resolution is larger than the panel resolution, */
145
/* panning will be performed. However, the timings for a panned mode */
146
/* are identical to the timings without panning. To save space in the */
147
/* mode tables, there are no additional table entries for modes with */
148
/* panning. Instead, we read the timings for a mode without panning */
149
/* and override the structure entries that specify the width and */
150
/* height of the mode. We perform a similar procedure for centered */
151
/* modes, except that certain timing parameters are dynamically */
154
panel_query.active_width = panel_width;
155
panel_query.active_height = panel_height;
156
panel_query.panel_width = panel_width;
157
panel_query.panel_height = panel_height;
158
panel_query.bpp = bpp;
159
panel_query.query_flags = VG_QUERYFLAG_ACTIVEWIDTH |
160
VG_QUERYFLAG_ACTIVEHEIGHT |
161
VG_QUERYFLAG_PANELWIDTH |
162
VG_QUERYFLAG_PANELHEIGHT | VG_QUERYFLAG_PANEL | VG_QUERYFLAG_BPP;
164
mode = vg_get_display_mode_index(&panel_query);
166
/* COPY THE DATA FROM THE MODE TABLE TO A TEMPORARY STRUCTURE */
169
panel_mode = CimarronDisplayModes[mode];
170
panel_mode.mode_width = dst_width;
171
panel_mode.mode_height = dst_height;
172
panel_mode.src_width = src_width;
173
panel_mode.src_height = src_height;
175
/* ADD USER-REQUESTED FLAGS */
177
panel_mode.flags |= (flags & VG_MODEFLAG_VALIDUSERFLAGS);
179
if (flags & VG_MODEFLAG_OVERRIDE_BAND) {
180
panel_mode.flags &= ~VG_MODEFLAG_BANDWIDTHMASK;
181
panel_mode.flags |= (flags & VG_MODEFLAG_BANDWIDTHMASK);
183
if (flags & VG_MODEFLAG_INT_OVERRIDE) {
184
panel_mode.flags &= ~VG_MODEFLAG_INT_MASK;
185
panel_mode.flags |= (flags & VG_MODEFLAG_INT_MASK);
188
/* DYNAMICALLY CALCULATE CENTERED TIMINGS */
189
/* For centered timings the blank start and blank end are set to */
190
/* half the difference between the mode dimension and the panel */
191
/* dimension. The sync pulse preserves the width and offset from */
192
/* blanking whenever possible. */
194
if (dst_width < panel_width) {
195
sync_width = panel_mode.hsyncend - panel_mode.hsyncstart;
196
sync_offset = panel_mode.hsyncstart - panel_mode.hblankstart;
198
panel_mode.hactive = dst_width;
199
panel_mode.hblankstart =
200
panel_mode.hactive + ((panel_width - dst_width) >> 1);
201
panel_mode.hblankend =
202
panel_mode.htotal - ((panel_width - dst_width) >> 1);
203
panel_mode.hsyncstart = panel_mode.hblankstart + sync_offset;
204
panel_mode.hsyncend = panel_mode.hsyncstart + sync_width;
206
panel_mode.flags |= VG_MODEFLAG_CENTERED;
208
if (dst_height < panel_height) {
209
sync_width = panel_mode.vsyncend - panel_mode.vsyncstart;
210
sync_offset = panel_mode.vsyncstart - panel_mode.vblankstart;
212
panel_mode.vactive = dst_height;
213
panel_mode.vblankstart =
214
panel_mode.vactive + ((panel_height - dst_height) >> 1);
215
panel_mode.vblankend =
216
panel_mode.vtotal - ((panel_height - dst_height) >> 1);
217
panel_mode.vsyncstart = panel_mode.vblankstart + sync_offset;
218
panel_mode.vsyncend = panel_mode.vsyncstart + sync_width;
220
panel_mode.flags |= VG_MODEFLAG_CENTERED;
222
return vg_set_custom_mode(&panel_mode, bpp);
224
return CIM_STATUS_ERROR;
227
/*---------------------------------------------------------------------------
230
* This routine sets a TV display mode using predefined Cimarron timings. The
231
* source width and height are specified to allow scaling.
232
*--------------------------------------------------------------------------*/
235
vg_set_tv_mode(unsigned long *src_width, unsigned long *src_height,
236
unsigned long encoder, unsigned long tvres, int bpp,
237
unsigned long flags, unsigned long h_overscan,
238
unsigned long v_overscan)
240
unsigned long sync_width;
241
unsigned long sync_offset;
242
VG_QUERY_MODE tv_query;
243
VG_DISPLAY_MODE tv_mode;
246
if (!src_width || !src_height)
247
return CIM_STATUS_INVALIDPARAMS;
250
tv_query.encoder = encoder;
251
tv_query.tvmode = tvres;
252
tv_query.query_flags = VG_QUERYFLAG_BPP | VG_QUERYFLAG_TVOUT |
253
VG_QUERYFLAG_ENCODER | VG_QUERYFLAG_TVMODE;
255
mode = vg_get_display_mode_index(&tv_query);
257
/* RETRIEVE THE UNSCALED RESOLUTION
258
* As we are indexing here simply by a mode and encoder, the actual
259
* timings may vary. A 0 value for source or height will thus query
260
* the unscaled resolution.
263
if (!(*src_width) || !(*src_height)) {
264
*src_width = CimarronDisplayModes[mode].hactive - (h_overscan << 1);
265
*src_height = CimarronDisplayModes[mode].vactive;
267
if (CimarronDisplayModes[mode].flags & VG_MODEFLAG_INTERLACED) {
268
if (((flags & VG_MODEFLAG_INT_OVERRIDE) &&
269
(flags & VG_MODEFLAG_INT_MASK) ==
270
VG_MODEFLAG_INT_LINEDOUBLE)
271
|| (!(flags & VG_MODEFLAG_INT_OVERRIDE)
272
&& (CimarronDisplayModes[mode].flags &
273
VG_MODEFLAG_INT_MASK) ==
274
VG_MODEFLAG_INT_LINEDOUBLE)) {
275
if (CimarronDisplayModes[mode].vactive_even >
276
CimarronDisplayModes[mode].vactive)
277
*src_height = CimarronDisplayModes[mode].vactive_even;
279
/* ONLY 1/2 THE OVERSCAN FOR LINE DOUBLED MODES */
281
*src_height -= v_overscan;
284
*src_height += CimarronDisplayModes[mode].vactive_even;
285
*src_height -= v_overscan << 1;
289
*src_height -= v_overscan << 1;
292
return CIM_STATUS_OK;
295
tv_mode = CimarronDisplayModes[mode];
296
tv_mode.src_width = *src_width;
297
tv_mode.src_height = *src_height;
299
/* ADD USER-REQUESTED FLAGS */
301
tv_mode.flags |= (flags & VG_MODEFLAG_VALIDUSERFLAGS);
303
if (flags & VG_MODEFLAG_OVERRIDE_BAND) {
304
tv_mode.flags &= ~VG_MODEFLAG_BANDWIDTHMASK;
305
tv_mode.flags |= (flags & VG_MODEFLAG_BANDWIDTHMASK);
307
if (flags & VG_MODEFLAG_INT_OVERRIDE) {
308
tv_mode.flags &= ~VG_MODEFLAG_INT_MASK;
309
tv_mode.flags |= (flags & VG_MODEFLAG_INT_MASK);
312
/* ADJUST FOR OVERSCAN */
315
sync_width = tv_mode.hsyncend - tv_mode.hsyncstart;
316
sync_offset = tv_mode.hsyncstart - tv_mode.hblankstart;
318
tv_mode.hactive -= h_overscan << 1;
319
tv_mode.hblankstart = tv_mode.hactive + h_overscan;
320
tv_mode.hblankend = tv_mode.htotal - h_overscan;
321
tv_mode.hsyncstart = tv_mode.hblankstart + sync_offset;
322
tv_mode.hsyncend = tv_mode.hsyncstart + sync_width;
324
tv_mode.flags |= VG_MODEFLAG_CENTERED;
327
sync_width = tv_mode.vsyncend - tv_mode.vsyncstart;
328
sync_offset = tv_mode.vsyncstart - tv_mode.vblankstart;
330
if (tv_mode.flags & VG_MODEFLAG_INTERLACED) {
331
tv_mode.vactive -= v_overscan;
332
tv_mode.vblankstart = tv_mode.vactive + (v_overscan >> 1);
333
tv_mode.vblankend = tv_mode.vtotal - (v_overscan >> 1);
334
tv_mode.vsyncstart = tv_mode.vblankstart + sync_offset;
335
tv_mode.vsyncend = tv_mode.vsyncstart + sync_width;
337
sync_width = tv_mode.vsyncend_even - tv_mode.vsyncstart_even;
338
sync_offset = tv_mode.vsyncstart_even -
339
tv_mode.vblankstart_even;
341
tv_mode.vactive_even -= v_overscan;
342
tv_mode.vblankstart_even =
343
tv_mode.vactive_even + (v_overscan >> 1);
344
tv_mode.vblankend_even =
345
tv_mode.vtotal_even - (v_overscan >> 1);
346
tv_mode.vsyncstart_even =
347
tv_mode.vblankstart_even + sync_offset;
348
tv_mode.vsyncend_even = tv_mode.vsyncstart_even + sync_width;
351
tv_mode.vactive -= v_overscan << 1;
352
tv_mode.vblankstart = tv_mode.vactive + v_overscan;
353
tv_mode.vblankend = tv_mode.vtotal - v_overscan;
354
tv_mode.vsyncstart = tv_mode.vblankstart + sync_offset;
355
tv_mode.vsyncend = tv_mode.vsyncstart + sync_width;
358
tv_mode.flags |= VG_MODEFLAG_CENTERED;
361
/* TV MODES WILL NEVER ALLOW PANNING */
363
tv_mode.panel_width = tv_mode.hactive;
364
tv_mode.panel_height = tv_mode.vactive;
365
tv_mode.mode_width = tv_mode.hactive;
366
tv_mode.mode_height = tv_mode.vactive;
368
return vg_set_custom_mode(&tv_mode, bpp);
370
return CIM_STATUS_ERROR;
373
/*---------------------------------------------------------------------------
376
* This routine sets a display mode. The API is structured such that this
377
* routine can be called from four sources:
378
* - vg_set_display_mode
379
* - vg_set_panel_mode
381
* - directly by the user for a custom mode.
382
*--------------------------------------------------------------------------*/
385
vg_set_custom_mode(VG_DISPLAY_MODE * mode_params, int bpp)
387
unsigned long config, misc, temp;
388
unsigned long irq_ctl, genlk_ctl;
389
unsigned long unlock, flags;
390
unsigned long acfg, gcfg, dcfg;
391
unsigned long size, line_size, pitch;
392
unsigned long bpp_mask, dv_size;
393
unsigned long hscale, vscale, starting_width;
394
unsigned long starting_height, output_height;
397
/* DETERMINE DIMENSIONS FOR SCALING */
398
/* Scaling is performed before flicker filtering and interlacing */
400
output_height = mode_params->vactive;
402
if (mode_params->flags & VG_MODEFLAG_INTERLACED) {
403
/* EVEN AND ODD FIELDS ARE SEPARATE
404
* The composite image height is the sum of the height of both
408
if ((mode_params->flags & VG_MODEFLAG_INT_MASK) ==
409
VG_MODEFLAG_INT_FLICKER
410
|| (mode_params->flags & VG_MODEFLAG_INT_MASK) ==
411
VG_MODEFLAG_INT_ADDRESS) {
412
output_height += mode_params->vactive_even;
416
* The composite image height is the greater of the two field
420
else if (mode_params->vactive_even > output_height)
421
output_height = mode_params->vactive_even;
424
/* CHECK FOR VALID SCALING FACTOR
425
* GeodeLX supports only 2:1 vertical downscale (before interlacing) and
426
* 2:1 horizontal downscale. The source width when scaling must be
427
* less than or equal to 1024 pixels. The destination can be any size,
428
* except when flicker filtering is enabled.
432
if (mode_params->flags & VG_MODEFLAG_PANELOUT) {
433
if (mode_params->src_width != mode_params->mode_width) {
434
starting_width = (mode_params->hactive * mode_params->src_width) /
435
mode_params->mode_width;
436
hscale = (mode_params->src_width << 14) /
437
(mode_params->mode_width - 1);
438
irq_ctl |= (DC3_IRQFILT_ALPHA_FILT_EN | DC3_IRQFILT_GFX_FILT_EN);
441
starting_width = mode_params->hactive;
444
if (mode_params->src_height != mode_params->mode_height) {
445
starting_height = (output_height * mode_params->src_height) /
446
mode_params->mode_height;
447
vscale = (mode_params->src_height << 14) /
448
(mode_params->mode_height - 1);
449
irq_ctl |= (DC3_IRQFILT_ALPHA_FILT_EN | DC3_IRQFILT_GFX_FILT_EN);
452
starting_height = output_height;
457
starting_width = mode_params->src_width;
458
starting_height = mode_params->src_height;
459
if (mode_params->src_width != mode_params->hactive) {
460
hscale = (mode_params->src_width << 14) /
461
(mode_params->hactive - 1);
462
irq_ctl |= (DC3_IRQFILT_ALPHA_FILT_EN | DC3_IRQFILT_GFX_FILT_EN);
467
if (mode_params->src_height != output_height) {
468
vscale = (mode_params->src_height << 14) / (output_height - 1);
469
irq_ctl |= (DC3_IRQFILT_ALPHA_FILT_EN | DC3_IRQFILT_GFX_FILT_EN);
476
starting_width = (starting_width + 7) & 0xFFFF8;
478
if (mode_params->hactive < (starting_width >> 1) ||
479
output_height < (starting_height >> 1) ||
480
(irq_ctl && (starting_width > 1024))) {
481
return CIM_STATUS_INVALIDSCALE;
484
/* VERIFY INTERLACED SCALING */
485
/* The output width must be less than or equal to 1024 pixels when the */
486
/* flicker filter is enabled. Also, scaling should be disabled when */
487
/* the interlacing mode is set to interlaced addressing. */
489
if (mode_params->flags & VG_MODEFLAG_INTERLACED) {
490
if ((((mode_params->flags & VG_MODEFLAG_INT_MASK) ==
491
VG_MODEFLAG_INT_FLICKER) && (mode_params->hactive > 1024))
492
|| (((mode_params->flags & VG_MODEFLAG_INT_MASK) ==
493
VG_MODEFLAG_INT_ADDRESS) && irq_ctl)) {
494
return CIM_STATUS_INVALIDSCALE;
498
/* CHECK FOR VALID BPP */
502
bpp_mask = DC3_DCFG_DISP_MODE_8BPP;
505
bpp_mask = DC3_DCFG_DISP_MODE_24BPP;
508
bpp_mask = DC3_DCFG_DISP_MODE_32BPP;
511
bpp_mask = DC3_DCFG_DISP_MODE_16BPP | DC3_DCFG_12BPP;
514
bpp_mask = DC3_DCFG_DISP_MODE_16BPP | DC3_DCFG_15BPP;
517
bpp_mask = DC3_DCFG_DISP_MODE_16BPP | DC3_DCFG_16BPP;
520
return CIM_STATUS_INVALIDPARAMS;
525
/* CLEAR PANNING OFFSETS */
530
/* SAVE PANEL PARAMETERS */
532
if (mode_params->flags & VG_MODEFLAG_PANELOUT) {
533
vg3_panel_enable = 1;
534
vg3_panel_width = mode_params->panel_width;
535
vg3_panel_height = mode_params->panel_height;
536
vg3_mode_width = mode_params->mode_width;
537
vg3_mode_height = mode_params->mode_height;
539
/* INVERT THE SHIFT CLOCK IF REQUESTED */
540
/* Note that we avoid writing the power management register if */
541
/* we can help it. */
543
temp = READ_VID32(DF_POWER_MANAGEMENT);
544
if ((mode_params->flags & VG_MODEFLAG_INVERT_SHFCLK) &&
545
!(temp & DF_PM_INVERT_SHFCLK)) {
546
WRITE_VID32(DF_POWER_MANAGEMENT, (temp | DF_PM_INVERT_SHFCLK));
548
else if (!(mode_params->flags & VG_MODEFLAG_INVERT_SHFCLK) &&
549
(temp & DF_PM_INVERT_SHFCLK)) {
550
WRITE_VID32(DF_POWER_MANAGEMENT, (temp & ~DF_PM_INVERT_SHFCLK));
553
/* SET PANEL TIMING VALUES */
555
if (!(mode_params->flags & VG_MODEFLAG_NOPANELTIMINGS)) {
556
unsigned long pmtim1, pmtim2, dith_ctl;
558
if (mode_params->flags & VG_MODEFLAG_XVGA_TFT) {
559
pmtim1 = DF_DEFAULT_XVGA_PMTIM1;
560
pmtim2 = DF_DEFAULT_XVGA_PMTIM2;
561
dith_ctl = DF_DEFAULT_DITHCTL;
562
msr_value.low = DF_DEFAULT_XVGA_PAD_SEL_LOW;
563
msr_value.high = DF_DEFAULT_XVGA_PAD_SEL_HIGH;
565
else if (mode_params->flags & VG_MODEFLAG_CUSTOM_PANEL) {
566
pmtim1 = mode_params->panel_tim1;
567
pmtim2 = mode_params->panel_tim2;
568
dith_ctl = mode_params->panel_dither_ctl;
569
msr_value.low = mode_params->panel_pad_sel_low;
570
msr_value.high = mode_params->panel_pad_sel_high;
573
pmtim1 = DF_DEFAULT_TFT_PMTIM1;
574
pmtim2 = DF_DEFAULT_TFT_PMTIM2;
575
dith_ctl = DF_DEFAULT_DITHCTL;
576
msr_value.low = DF_DEFAULT_TFT_PAD_SEL_LOW;
577
msr_value.high = DF_DEFAULT_TFT_PAD_SEL_HIGH;
580
WRITE_VID32(DF_VIDEO_PANEL_TIM1, pmtim1);
581
WRITE_VID32(DF_VIDEO_PANEL_TIM2, pmtim2);
582
WRITE_VID32(DF_DITHER_CONTROL, dith_ctl);
583
msr_write64(MSR_DEVICE_GEODELX_DF, DF_MSR_PAD_SEL, &msr_value);
586
/* SET APPROPRIATE PANEL OUTPUT MODE */
588
msr_read64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
590
msr_value.low &= ~DF_CONFIG_OUTPUT_MASK;
591
msr_value.low |= DF_OUTPUT_PANEL;
592
if (mode_params->flags & VG_MODEFLAG_CRT_AND_FP)
593
msr_value.low |= DF_SIMULTANEOUS_CRT_FP;
595
msr_value.low &= ~DF_SIMULTANEOUS_CRT_FP;
597
msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
600
else if (mode_params->flags & VG_MODEFLAG_TVOUT) {
601
vg3_panel_enable = 0;
603
/* SET APPROPRIATE TV OUTPUT MODE */
605
msr_read64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
607
msr_value.low &= ~DF_CONFIG_OUTPUT_MASK;
608
msr_value.low |= DF_OUTPUT_PANEL;
609
if (mode_params->flags & VG_MODEFLAG_CRT_AND_FP)
610
msr_value.low |= DF_SIMULTANEOUS_CRT_FP;
612
msr_value.low &= ~DF_SIMULTANEOUS_CRT_FP;
614
msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
616
/* CONFIGURE PADS FOR VOP OUTPUT */
617
/* Note that the VOP clock is currently always inverted. */
619
msr_value.low = DF_DEFAULT_TV_PAD_SEL_LOW;
620
msr_value.high = DF_DEFAULT_TV_PAD_SEL_HIGH;
621
msr_write64(MSR_DEVICE_GEODELX_DF, DF_MSR_PAD_SEL, &msr_value);
624
vg3_panel_enable = 0;
626
/* SET OUTPUT TO CRT ONLY */
628
msr_read64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
629
msr_value.low &= ~DF_CONFIG_OUTPUT_MASK;
630
msr_value.low |= DF_OUTPUT_CRT;
631
msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
634
/* SET UNLOCK VALUE */
636
unlock = READ_REG32(DC3_UNLOCK);
637
WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
639
/*-------------------------------------------------------------------*/
640
/* MAKE THE SYSTEM "SAFE" */
641
/* Before setting a mode, we first ensure that the system is in a */
642
/* benign quiescent state. This involves disabling compression and */
643
/* all interrupt sources. It also involves terminating all accesses */
644
/* to memory, including video, FIFO load, VIP and the GP. */
645
/*-------------------------------------------------------------------*/
648
* VGA *MUST* be turned off before TGEN is enabled. If not, a condition
649
* will result where VGA Enable is waiting for a VSync to be latched but
650
* a VSync will not be generated until VGA is disabled.
653
temp = READ_REG32(DC3_GENERAL_CFG) & ~DC3_GCFG_VGAE;
655
/* DISABLE VIDEO (INCLUDING ALPHA WINDOWS) */
657
WRITE_VID32(DF_ALPHA_CONTROL_1, 0);
658
WRITE_VID32(DF_ALPHA_CONTROL_1 + 32, 0);
659
WRITE_VID32(DF_ALPHA_CONTROL_1 + 64, 0);
661
WRITE_REG32(DC3_GENERAL_CFG, (temp & ~DC3_GCFG_VIDE));
662
temp = READ_VID32(DF_VIDEO_CONFIG);
663
WRITE_VID32(DF_VIDEO_CONFIG, (temp & ~DF_VCFG_VID_EN));
665
/* DISABLE VG INTERRUPTS */
667
WRITE_REG32(DC3_IRQ, DC3_IRQ_MASK | DC3_VSYNC_IRQ_MASK |
668
DC3_IRQ_STATUS | DC3_VSYNC_IRQ_STATUS);
670
/* DISABLE GENLOCK */
672
genlk_ctl = READ_REG32(DC3_GENLK_CTL);
673
WRITE_REG32(DC3_GENLK_CTL, (genlk_ctl & ~DC3_GC_GENLOCK_ENABLE));
675
/* DISABLE VIP CAPTURE AND VIP INTERRUPTS */
677
WRITE_VIP32(VIP_CONTROL1, 0);
678
WRITE_VIP32(VIP_CONTROL2, 0);
679
WRITE_VIP32(VIP_INTERRUPT, VIP_ALL_INTERRUPTS | (VIP_ALL_INTERRUPTS >> 16));
681
/* DISABLE COLOR KEYING
682
* The color key mechanism should be disabled whenever a mode switch
686
temp = READ_REG32(DC3_COLOR_KEY);
687
WRITE_REG32(DC3_COLOR_KEY, (temp & ~DC3_CLR_KEY_ENABLE));
690
* Note that we never blank the panel. Most flat panels have very long
691
* latency requirements when setting their power low. Some panels require
692
* upwards of 500ms before VDD goes high again. Needless to say, we are
693
* not planning to take over one half a second inside this routine.
696
misc = READ_VID32(DF_VID_MISC);
697
config = READ_VID32(DF_DISPLAY_CONFIG);
699
WRITE_VID32(DF_VID_MISC, (misc | DF_DAC_POWER_DOWN));
700
WRITE_VID32(DF_DISPLAY_CONFIG,
701
(config & ~(DF_DCFG_DIS_EN | DF_DCFG_HSYNC_EN |
702
DF_DCFG_VSYNC_EN | DF_DCFG_DAC_BL_EN)));
704
/* DISABLE COMPRESSION */
706
gcfg = READ_REG32(DC3_GENERAL_CFG);
707
gcfg &= ~(DC3_GCFG_CMPE | DC3_GCFG_DECE);
708
WRITE_REG32(DC3_GENERAL_CFG, gcfg);
710
/* DISABLE THE TIMING GENERATOR */
712
dcfg = READ_REG32(DC3_DISPLAY_CFG);
713
dcfg &= ~DC3_DCFG_TGEN;
714
WRITE_REG32(DC3_DISPLAY_CFG, dcfg);
716
/* WAIT FOR PENDING MEMORY REQUESTS */
718
vg_delay_milliseconds(1);
720
/* DISABLE DISPLAY FIFO LOAD */
722
gcfg &= ~DC3_GCFG_DFLE;
723
WRITE_REG32(DC3_GENERAL_CFG, gcfg);
727
/* WAIT FOR THE GP TO BE IDLE (JUST IN CASE) */
729
while (((temp = READ_GP32(GP3_BLT_STATUS)) & GP3_BS_BLT_BUSY) ||
730
!(temp & GP3_BS_CB_EMPTY)) {
734
/* SET THE DOT CLOCK FREQUENCY */
736
if (!(mode_params->flags & VG_MODEFLAG_EXCLUDEPLL)) {
737
if (mode_params->flags & VG_MODEFLAG_HALFCLOCK)
738
flags = VG_PLL_DIVIDE_BY_2;
739
else if (mode_params->flags & VG_MODEFLAG_QVGA)
740
flags = VG_PLL_DIVIDE_BY_4;
744
/* ALLOW DOTREF TO BE USED AS THE PLL */
745
/* This is useful for some external TV encoders. */
747
if (mode_params->flags & VG_MODEFLAG_PLL_BYPASS)
748
flags |= VG_PLL_BYPASS;
750
/* ALLOW THE USER TO MANUALLY ENTER THE MSR VALUE */
752
if (mode_params->flags & VG_MODEFLAG_MANUAL_FREQUENCY)
753
flags |= VG_PLL_MANUAL;
754
if (mode_params->flags & VG_MODEFLAG_VIP_TO_DOT_CLOCK)
755
flags |= VG_PLL_VIP_CLOCK;
757
vg_set_clock_frequency(mode_params->frequency, flags);
760
/* CLEAR ALL BUFFER OFFSETS */
762
WRITE_REG32(DC3_FB_ST_OFFSET, 0);
763
WRITE_REG32(DC3_CB_ST_OFFSET, 0);
764
WRITE_REG32(DC3_CURS_ST_OFFSET, 0);
766
genlk_ctl = READ_REG32(DC3_GENLK_CTL) & ~(DC3_GC_ALPHA_FLICK_ENABLE |
767
DC3_GC_FLICKER_FILTER_ENABLE |
768
DC3_GC_FLICKER_FILTER_MASK);
770
/* ENABLE INTERLACING */
772
if (mode_params->flags & VG_MODEFLAG_INTERLACED) {
773
irq_ctl |= DC3_IRQFILT_INTL_EN;
775
if ((mode_params->flags & VG_MODEFLAG_INT_MASK) ==
776
VG_MODEFLAG_INT_ADDRESS)
777
irq_ctl |= DC3_IRQFILT_INTL_ADDR;
778
else if ((mode_params->flags & VG_MODEFLAG_INT_MASK) ==
779
VG_MODEFLAG_INT_FLICKER) {
780
genlk_ctl |= DC3_GC_FLICKER_FILTER_1_8 |
781
DC3_GC_FLICKER_FILTER_ENABLE | DC3_GC_ALPHA_FLICK_ENABLE;
785
WRITE_REG32(DC3_GFX_SCALE, (vscale << 16) | (hscale & 0xFFFF));
786
WRITE_REG32(DC3_IRQ_FILT_CTL, irq_ctl);
787
WRITE_REG32(DC3_GENLK_CTL, genlk_ctl);
789
/* SET LINE SIZE AND PITCH
790
* The line size and pitch are calculated from the src_width parameter
791
* passed in to this routine. All other parameters are ignored.
792
* The pitch is set either to a power of 2 to allow efficient
793
* compression or to a linear value to allow efficient memory management.
798
size = mode_params->src_width;
799
line_size = starting_width;
806
size = mode_params->src_width << 1;
807
line_size = starting_width << 1;
814
size = mode_params->src_width << 2;
815
line_size = starting_width << 2;
819
/* CALCULATE DV RAM SETTINGS AND POWER OF 2 PITCH */
822
dv_size = DC3_DV_LINE_SIZE_1024;
826
dv_size = DC3_DV_LINE_SIZE_2048;
830
dv_size = DC3_DV_LINE_SIZE_4096;
834
dv_size = DC3_DV_LINE_SIZE_8192;
837
/* OVERRIDE SETTINGS FOR LINEAR PITCH */
839
if (mode_params->flags & VG_MODEFLAG_LINEARPITCH) {
843
/* CALCULATE MAXIMUM ADDRESS (1K ALIGNED) */
845
max = size * output_height;
846
max = (max + 0x3FF) & 0xFFFFFC00;
847
WRITE_REG32(DC3_DV_TOP, max | DC3_DVTOP_ENABLE);
849
gcfg |= DC3_GCFG_FDTY;
853
WRITE_REG32(DC3_DV_TOP, 0);
857
/* WRITE PITCH AND DV RAM SETTINGS */
858
/* The DV RAM line length is programmed at a power of 2 boundary */
859
/* in case the user wants to toggle back to a power of 2 pitch */
860
/* later. It could happen... */
862
temp = READ_REG32(DC3_DV_CTL);
863
WRITE_REG32(DC3_GFX_PITCH, pitch >> 3);
864
WRITE_REG32(DC3_DV_CTL, (temp & ~DC3_DV_LINE_SIZE_MASK) | dv_size);
866
/* SET THE LINE SIZE */
868
WRITE_REG32(DC3_LINE_SIZE, (line_size + 7) >> 3);
870
/* ALWAYS ENABLE VIDEO AND GRAPHICS DATA */
871
/* These bits are relics from a previous design and */
872
/* should always be enabled. */
874
dcfg |= (DC3_DCFG_VDEN | DC3_DCFG_GDEN);
876
/* SET PIXEL FORMAT */
880
/* ENABLE TIMING GENERATOR, TIM. REG. UPDATES, PALETTE BYPASS */
881
/* AND VERT. INT. SELECT */
883
dcfg |= (unsigned long) (DC3_DCFG_TGEN | DC3_DCFG_TRUP | DC3_DCFG_PALB |
886
/* SET FIFO PRIORITIES AND DISPLAY FIFO LOAD ENABLE
887
* Note that the bandwidth setting gets upgraded when scaling or flicker
888
* filtering are enabled, as they require more data throughput.
891
msr_read64(MSR_DEVICE_GEODELX_VG, DC3_SPARE_MSR, &msr_value);
892
msr_value.low &= ~(DC3_SPARE_DISABLE_CFIFO_HGO |
893
DC3_SPARE_VFIFO_ARB_SELECT |
894
DC3_SPARE_LOAD_WM_LPEN_MASK | DC3_SPARE_WM_LPEN_OVRD |
895
DC3_SPARE_DISABLE_INIT_VID_PRI |
896
DC3_SPARE_DISABLE_VFIFO_WM);
898
if ((mode_params->flags & VG_MODEFLAG_BANDWIDTHMASK) ==
899
VG_MODEFLAG_HIGH_BAND || ((mode_params->flags & VG_MODEFLAG_INTERLACED)
901
flags & VG_MODEFLAG_INT_MASK) ==
902
VG_MODEFLAG_INT_FLICKER) ||
903
(irq_ctl & DC3_IRQFILT_GFX_FILT_EN)) {
905
/* Set agressive watermarks and disallow forced low priority */
911
msr_value.low |= DC3_SPARE_DISABLE_CFIFO_HGO |
912
DC3_SPARE_VFIFO_ARB_SELECT | DC3_SPARE_WM_LPEN_OVRD;
914
else if ((mode_params->flags & VG_MODEFLAG_BANDWIDTHMASK) ==
915
VG_MODEFLAG_AVG_BAND) {
917
* Set average watermarks and allow small regions of forced low
925
msr_value.low |= DC3_SPARE_DISABLE_CFIFO_HGO |
926
DC3_SPARE_VFIFO_ARB_SELECT | DC3_SPARE_WM_LPEN_OVRD;
928
/* SET THE NUMBER OF LOW PRIORITY LINES TO 1/2 THE TOTAL AVAILABLE */
930
temp = ((READ_REG32(DC3_V_ACTIVE_TIMING) >> 16) & 0x7FF) + 1;
931
temp -= (READ_REG32(DC3_V_SYNC_TIMING) & 0x7FF) + 1;
938
else if ((mode_params->flags & VG_MODEFLAG_BANDWIDTHMASK) ==
939
VG_MODEFLAG_LOW_BAND) {
941
* Set low watermarks and allow larger regions of forced low priority
948
msr_value.low |= DC3_SPARE_DISABLE_CFIFO_HGO |
949
DC3_SPARE_VFIFO_ARB_SELECT | DC3_SPARE_WM_LPEN_OVRD;
951
/* SET THE NUMBER OF LOW PRIORITY LINES TO 3/4 THE TOTAL AVAILABLE */
953
temp = ((READ_REG32(DC3_V_ACTIVE_TIMING) >> 16) & 0x7FF) + 1;
954
temp -= (READ_REG32(DC3_V_SYNC_TIMING) & 0x7FF) + 1;
955
temp = (temp * 3) >> 2;
962
/* LEGACY CHARACTERISTICS */
963
/* Arbitration from a single set of watermarks. */
966
msr_value.low |= DC3_SPARE_DISABLE_VFIFO_WM |
967
DC3_SPARE_DISABLE_INIT_VID_PRI;
971
msr_write64(MSR_DEVICE_GEODELX_VG, DC3_SPARE_MSR, &msr_value);
973
/* ENABLE FLAT PANEL CENTERING */
974
/* For panel modes having a resolution smaller than the */
975
/* panel resolution, turn on data centering. */
977
if (mode_params->flags & VG_MODEFLAG_CENTERED)
978
dcfg |= DC3_DCFG_DCEN;
980
/* COMBINE AND SET TIMING VALUES */
982
temp = (mode_params->hactive - 1) | ((mode_params->htotal - 1) << 16);
983
WRITE_REG32(DC3_H_ACTIVE_TIMING, temp);
984
temp = (mode_params->hblankstart - 1) |
985
((mode_params->hblankend - 1) << 16);
986
WRITE_REG32(DC3_H_BLANK_TIMING, temp);
987
temp = (mode_params->hsyncstart - 1) | ((mode_params->hsyncend - 1) << 16);
988
WRITE_REG32(DC3_H_SYNC_TIMING, temp);
989
temp = (mode_params->vactive - 1) | ((mode_params->vtotal - 1) << 16);
990
WRITE_REG32(DC3_V_ACTIVE_TIMING, temp);
991
temp = (mode_params->vblankstart - 1) |
992
((mode_params->vblankend - 1) << 16);
993
WRITE_REG32(DC3_V_BLANK_TIMING, temp);
994
temp = (mode_params->vsyncstart - 1) | ((mode_params->vsyncend - 1) << 16);
995
WRITE_REG32(DC3_V_SYNC_TIMING, temp);
996
temp = (mode_params->vactive_even - 1) | ((mode_params->vtotal_even -
998
WRITE_REG32(DC3_V_ACTIVE_EVEN, temp);
999
temp = (mode_params->vblankstart_even - 1) |
1000
((mode_params->vblankend_even - 1) << 16);
1001
WRITE_REG32(DC3_V_BLANK_EVEN, temp);
1002
temp = (mode_params->vsyncstart_even - 1) |
1003
((mode_params->vsyncend_even - 1) << 16);
1004
WRITE_REG32(DC3_V_SYNC_EVEN, temp);
1006
/* SET THE VIDEO REQUEST REGISTER */
1008
WRITE_VID32(DF_VIDEO_REQUEST, 0);
1010
/* SET SOURCE DIMENSIONS */
1012
WRITE_REG32(DC3_FB_ACTIVE, ((starting_width - 1) << 16) |
1013
(starting_height - 1));
1015
/* SET SYNC POLARITIES */
1017
temp = READ_VID32(DF_DISPLAY_CONFIG);
1019
temp &= ~(DF_DCFG_CRT_SYNC_SKW_MASK | DF_DCFG_PWR_SEQ_DLY_MASK |
1020
DF_DCFG_CRT_HSYNC_POL | DF_DCFG_CRT_VSYNC_POL);
1022
temp |= DF_DCFG_CRT_SYNC_SKW_INIT | DF_DCFG_PWR_SEQ_DLY_INIT;
1024
if (mode_params->flags & VG_MODEFLAG_NEG_HSYNC)
1025
temp |= DF_DCFG_CRT_HSYNC_POL;
1026
if (mode_params->flags & VG_MODEFLAG_NEG_VSYNC)
1027
temp |= DF_DCFG_CRT_VSYNC_POL;
1029
WRITE_VID32(DF_DISPLAY_CONFIG, temp);
1031
WRITE_REG32(DC3_DISPLAY_CFG, dcfg);
1032
WRITE_REG32(DC3_ARB_CFG, acfg);
1033
WRITE_REG32(DC3_GENERAL_CFG, gcfg);
1035
/* RESTORE VALUE OF DC3_UNLOCK */
1037
WRITE_REG32(DC3_UNLOCK, unlock);
1039
return CIM_STATUS_OK;
1042
/*---------------------------------------------------------------------------
1045
* This routine changes the display BPP on the fly. It is intended only to
1046
* switch between pixel depths of the same pixel size 24<->32 or 15<->16, NOT
1047
* between pixel depths of differing sizes 16<->32
1048
*--------------------------------------------------------------------------*/
1051
vg_set_display_bpp(int bpp)
1053
unsigned long unlock, dcfg, bpp_mask;
1057
bpp_mask = DC3_DCFG_DISP_MODE_8BPP;
1060
bpp_mask = DC3_DCFG_DISP_MODE_24BPP;
1063
bpp_mask = DC3_DCFG_DISP_MODE_32BPP;
1066
bpp_mask = DC3_DCFG_DISP_MODE_16BPP | DC3_DCFG_12BPP;
1069
bpp_mask = DC3_DCFG_DISP_MODE_16BPP | DC3_DCFG_15BPP;
1072
bpp_mask = DC3_DCFG_DISP_MODE_16BPP | DC3_DCFG_16BPP;
1075
return CIM_STATUS_INVALIDPARAMS;
1078
unlock = READ_REG32(DC3_UNLOCK);
1079
dcfg = READ_REG32(DC3_DISPLAY_CFG) & ~(DC3_DCFG_DISP_MODE_MASK |
1080
DC3_DCFG_16BPP_MODE_MASK);
1083
WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
1084
WRITE_REG32(DC3_DISPLAY_CFG, dcfg);
1085
WRITE_REG32(DC3_UNLOCK, unlock);
1087
return CIM_STATUS_OK;
1090
/*---------------------------------------------------------------------------
1091
* vg_get_display_mode_index
1093
* This routine searches the Cimarron mode table for a mode that matches the
1094
* input parameters. If a match is found, the return value is the index into
1095
* the mode table. If no match is found, the return value is -1.
1096
*--------------------------------------------------------------------------*/
1099
vg_get_display_mode_index(VG_QUERY_MODE * query)
1102
unsigned long hz_flag = 0xFFFFFFFF;
1103
unsigned long bpp_flag = 0xFFFFFFFF;
1104
unsigned long enc_flag = 0xFFFFFFFF;
1105
unsigned long tv_flag = 0;
1106
unsigned long interlaced = 0;
1107
unsigned long halfclock = 0;
1108
long minimum = 0x7FFFFFFF;
1112
if (!query || !query->query_flags)
1115
if (query->query_flags & VG_QUERYFLAG_REFRESH) {
1116
/* SET FLAGS TO MATCH REFRESH RATE */
1118
if (query->hz == 56)
1119
hz_flag = VG_SUPPORTFLAG_56HZ;
1120
else if (query->hz == 60)
1121
hz_flag = VG_SUPPORTFLAG_60HZ;
1122
else if (query->hz == 70)
1123
hz_flag = VG_SUPPORTFLAG_70HZ;
1124
else if (query->hz == 72)
1125
hz_flag = VG_SUPPORTFLAG_72HZ;
1126
else if (query->hz == 75)
1127
hz_flag = VG_SUPPORTFLAG_75HZ;
1128
else if (query->hz == 85)
1129
hz_flag = VG_SUPPORTFLAG_85HZ;
1130
else if (query->hz == 90)
1131
hz_flag = VG_SUPPORTFLAG_90HZ;
1132
else if (query->hz == 100)
1133
hz_flag = VG_SUPPORTFLAG_100HZ;
1138
if (query->query_flags & VG_QUERYFLAG_BPP) {
1139
/* SET BPP FLAGS TO LIMIT MODE SELECTION */
1141
if (query->bpp == 8)
1142
bpp_flag = VG_SUPPORTFLAG_8BPP;
1143
else if (query->bpp == 12)
1144
bpp_flag = VG_SUPPORTFLAG_12BPP;
1145
else if (query->bpp == 15)
1146
bpp_flag = VG_SUPPORTFLAG_15BPP;
1147
else if (query->bpp == 16)
1148
bpp_flag = VG_SUPPORTFLAG_16BPP;
1149
else if (query->bpp == 24)
1150
bpp_flag = VG_SUPPORTFLAG_24BPP;
1151
else if (query->bpp == 32)
1152
bpp_flag = VG_SUPPORTFLAG_32BPP;
1157
if (query->query_flags & VG_QUERYFLAG_ENCODER) {
1158
/* SET ENCODER FLAGS TO LIMIT MODE SELECTION */
1160
if (query->encoder == VG_ENCODER_ADV7171)
1161
enc_flag = VG_SUPPORTFLAG_ADV7171;
1162
else if (query->encoder == VG_ENCODER_SAA7127)
1163
enc_flag = VG_SUPPORTFLAG_SAA7127;
1164
else if (query->encoder == VG_ENCODER_FS454)
1165
enc_flag = VG_SUPPORTFLAG_FS454;
1166
else if (query->encoder == VG_ENCODER_ADV7300)
1167
enc_flag = VG_SUPPORTFLAG_ADV7300;
1172
if (query->query_flags & VG_QUERYFLAG_TVMODE) {
1173
/* SET ENCODER FLAGS TO LIMIT MODE SELECTION */
1175
if (query->tvmode == VG_TVMODE_NTSC)
1176
tv_flag = VG_SUPPORTFLAG_NTSC;
1177
else if (query->tvmode == VG_TVMODE_PAL)
1178
tv_flag = VG_SUPPORTFLAG_PAL;
1179
else if (query->tvmode == VG_TVMODE_480P)
1180
tv_flag = VG_SUPPORTFLAG_480P;
1181
else if (query->tvmode == VG_TVMODE_720P)
1182
tv_flag = VG_SUPPORTFLAG_720P;
1183
else if (query->tvmode == VG_TVMODE_1080I)
1184
tv_flag = VG_SUPPORTFLAG_1080I;
1185
else if (query->tvmode == VG_TVMODE_6X4_NTSC)
1186
tv_flag = VG_SUPPORTFLAG_6X4_NTSC;
1187
else if (query->tvmode == VG_TVMODE_8X6_NTSC)
1188
tv_flag = VG_SUPPORTFLAG_8X6_NTSC;
1189
else if (query->tvmode == VG_TVMODE_10X7_NTSC)
1190
tv_flag = VG_SUPPORTFLAG_10X7_NTSC;
1191
else if (query->tvmode == VG_TVMODE_6X4_PAL)
1192
tv_flag = VG_SUPPORTFLAG_6X4_PAL;
1193
else if (query->tvmode == VG_TVMODE_8X6_PAL)
1194
tv_flag = VG_SUPPORTFLAG_8X6_PAL;
1195
else if (query->tvmode == VG_TVMODE_10X7_PAL)
1196
tv_flag = VG_SUPPORTFLAG_10X7_PAL;
1198
tv_flag = 0xFFFFFFFF;
1201
/* SET APPROPRIATE TV AND VOP FLAGS */
1203
if (query->query_flags & VG_QUERYFLAG_INTERLACED)
1204
interlaced = query->interlaced ? VG_MODEFLAG_INTERLACED : 0;
1205
if (query->query_flags & VG_QUERYFLAG_HALFCLOCK)
1206
halfclock = query->halfclock ? VG_MODEFLAG_HALFCLOCK : 0;
1208
/* CHECK FOR INVALID REQUEST */
1210
if (!hz_flag || !bpp_flag || !enc_flag || tv_flag == 0xFFFFFFFF)
1213
/* LOOP THROUGH THE AVAILABLE MODES TO FIND A MATCH */
1215
for (mode = 0; mode < NUM_CIMARRON_DISPLAY_MODES; mode++) {
1216
if ((!(query->query_flags & VG_QUERYFLAG_PANEL) ||
1217
(CimarronDisplayModes[mode].internal_flags & VG_SUPPORTFLAG_PANEL))
1218
&& (!(query->query_flags & VG_QUERYFLAG_TVOUT)
1219
|| (CimarronDisplayModes[mode].internal_flags &
1220
VG_SUPPORTFLAG_TVOUT))
1221
&& (!(query->query_flags & VG_QUERYFLAG_INTERLACED)
1222
|| (CimarronDisplayModes[mode].flags & VG_MODEFLAG_INTERLACED)
1224
&& (!(query->query_flags & VG_QUERYFLAG_HALFCLOCK)
1225
|| (CimarronDisplayModes[mode].flags & VG_MODEFLAG_HALFCLOCK) ==
1227
&& (!(query->query_flags & VG_QUERYFLAG_PANELWIDTH)
1228
|| (CimarronDisplayModes[mode].panel_width ==
1229
query->panel_width))
1230
&& (!(query->query_flags & VG_QUERYFLAG_PANELHEIGHT)
1231
|| (CimarronDisplayModes[mode].panel_height ==
1232
query->panel_height))
1233
&& (!(query->query_flags & VG_QUERYFLAG_ACTIVEWIDTH)
1234
|| (CimarronDisplayModes[mode].hactive == query->active_width))
1235
&& (!(query->query_flags & VG_QUERYFLAG_ACTIVEHEIGHT)
1236
|| (CimarronDisplayModes[mode].vactive == query->active_height))
1237
&& (!(query->query_flags & VG_QUERYFLAG_TOTALWIDTH)
1238
|| (CimarronDisplayModes[mode].htotal == query->total_width))
1239
&& (!(query->query_flags & VG_QUERYFLAG_TOTALHEIGHT)
1240
|| (CimarronDisplayModes[mode].vtotal == query->total_height))
1241
&& (!(query->query_flags & VG_QUERYFLAG_BPP)
1242
|| (CimarronDisplayModes[mode].internal_flags & bpp_flag))
1243
&& (!(query->query_flags & VG_QUERYFLAG_REFRESH)
1244
|| (CimarronDisplayModes[mode].internal_flags & hz_flag))
1245
&& (!(query->query_flags & VG_QUERYFLAG_ENCODER)
1246
|| (CimarronDisplayModes[mode].internal_flags & enc_flag))
1247
&& (!(query->query_flags & VG_QUERYFLAG_TVMODE)
1249
((CimarronDisplayModes[mode].internal_flags &
1250
VG_SUPPORTFLAG_TVMODEMASK) == tv_flag))
1251
&& (!(query->query_flags & VG_QUERYFLAG_PIXELCLOCK)
1252
|| (CimarronDisplayModes[mode].frequency == query->frequency))) {
1253
/* ALLOW SEARCHING BASED ON AN APPROXIMATE PIXEL CLOCK */
1255
if (query->query_flags & VG_QUERYFLAG_PIXELCLOCK_APPROX) {
1256
diff = query->frequency - CimarronDisplayModes[mode].frequency;
1260
if (diff < minimum) {
1272
/* RETURN DISPLAY MODE INDEX */
1277
/*---------------------------------------------------------------------------
1278
* vg_get_display_mode_information
1280
* This routine retrieves all information for a display mode contained
1281
* within Cimarron's mode tables.
1282
*--------------------------------------------------------------------------*/
1285
vg_get_display_mode_information(unsigned int index, VG_DISPLAY_MODE * vg_mode)
1287
if (index > NUM_CIMARRON_DISPLAY_MODES)
1288
return CIM_STATUS_INVALIDPARAMS;
1290
*vg_mode = CimarronDisplayModes[index];
1291
return CIM_STATUS_OK;
1294
/*---------------------------------------------------------------------------
1295
* vg_get_display_mode_count
1297
* This routine retrieves the count of all predefined Cimarron modes.
1298
*--------------------------------------------------------------------------*/
1301
vg_get_display_mode_count(void)
1303
return NUM_CIMARRON_DISPLAY_MODES;
1306
/*---------------------------------------------------------------------------
1307
* vg_get_current_display_mode
1309
* This routine retrieves the settings for the current display. This includes
1310
* any panel settings.
1311
*--------------------------------------------------------------------------*/
1314
vg_get_current_display_mode(VG_DISPLAY_MODE * current_display, int *bpp)
1317
unsigned long active, blank, sync;
1318
unsigned long i, m, n, p;
1319
unsigned long genlk, irq, temp;
1320
unsigned long flags = 0;
1321
unsigned long iflags = 0;
1323
/* READ THE CURRENT HORIZONTAL DISPLAY TIMINGS */
1325
active = READ_REG32(DC3_H_ACTIVE_TIMING);
1326
blank = READ_REG32(DC3_H_BLANK_TIMING);
1327
sync = READ_REG32(DC3_H_SYNC_TIMING);
1329
current_display->hactive = (active & 0xFFF) + 1;
1330
current_display->hblankstart = (blank & 0xFFF) + 1;
1331
current_display->hsyncstart = (sync & 0xFFF) + 1;
1333
current_display->htotal = ((active >> 16) & 0xFFF) + 1;
1334
current_display->hblankend = ((blank >> 16) & 0xFFF) + 1;
1335
current_display->hsyncend = ((sync >> 16) & 0xFFF) + 1;
1337
/* READ THE CURRENT VERTICAL DISPLAY TIMINGS */
1339
active = READ_REG32(DC3_V_ACTIVE_TIMING);
1340
blank = READ_REG32(DC3_V_BLANK_TIMING);
1341
sync = READ_REG32(DC3_V_SYNC_TIMING);
1343
current_display->vactive = (active & 0x7FF) + 1;
1344
current_display->vblankstart = (blank & 0x7FF) + 1;
1345
current_display->vsyncstart = (sync & 0x7FF) + 1;
1347
current_display->vtotal = ((active >> 16) & 0x7FF) + 1;
1348
current_display->vblankend = ((blank >> 16) & 0x7FF) + 1;
1349
current_display->vsyncend = ((sync >> 16) & 0x7FF) + 1;
1351
/* READ THE CURRENT EVEN FIELD VERTICAL DISPLAY TIMINGS */
1353
active = READ_REG32(DC3_V_ACTIVE_EVEN);
1354
blank = READ_REG32(DC3_V_BLANK_EVEN);
1355
sync = READ_REG32(DC3_V_SYNC_EVEN);
1357
current_display->vactive_even = (active & 0x7FF) + 1;
1358
current_display->vblankstart_even = (blank & 0x7FF) + 1;
1359
current_display->vsyncstart_even = (sync & 0x7FF) + 1;
1361
current_display->vtotal_even = ((active >> 16) & 0x7FF) + 1;
1362
current_display->vblankend_even = ((blank >> 16) & 0x7FF) + 1;
1363
current_display->vsyncend_even = ((sync >> 16) & 0x7FF) + 1;
1365
/* READ THE CURRENT SOURCE DIMENSIONS */
1366
/* The DC3_FB_ACTIVE register is only used when scaling is enabled. */
1367
/* As the goal of this routine is to return a structure that can be */
1368
/* passed to vg_set_custom_mode to exactly recreate the current mode, */
1369
/* we must check the status of the scaler/filter. */
1371
genlk = READ_REG32(DC3_GENLK_CTL);
1372
irq = READ_REG32(DC3_IRQ_FILT_CTL);
1373
temp = READ_REG32(DC3_FB_ACTIVE);
1375
current_display->src_height = (temp & 0xFFFF) + 1;
1376
current_display->src_width = ((temp >> 16) & 0xFFF8) + 8;
1378
/* READ THE CURRENT PANEL CONFIGURATION */
1379
/* We can only infer some of the panel settings based on hardware */
1380
/* (like when panning). We will instead assume that the current */
1381
/* mode was set using Cimarron and use the panel variables inside */
1382
/* Cimarron when returning the current mode information. */
1384
if (vg3_panel_enable) {
1387
flags |= VG_MODEFLAG_PANELOUT;
1389
current_display->panel_width = vg3_panel_width;
1390
current_display->panel_height = vg3_panel_height;
1391
current_display->mode_width = vg3_mode_width;
1392
current_display->mode_height = vg3_mode_height;
1394
if (READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_DCEN)
1395
flags |= VG_MODEFLAG_CENTERED;
1397
msr_read64(MSR_DEVICE_GEODELX_DF, DF_MSR_PAD_SEL, &msr_value);
1398
current_display->panel_tim1 = READ_VID32(DF_VIDEO_PANEL_TIM1);
1399
current_display->panel_tim2 = READ_VID32(DF_VIDEO_PANEL_TIM2);
1400
current_display->panel_dither_ctl = READ_VID32(DF_DITHER_CONTROL);
1401
current_display->panel_pad_sel_low = msr_value.low;
1402
current_display->panel_pad_sel_high = msr_value.high;
1405
/* SET MISCELLANEOUS MODE FLAGS */
1409
if (irq & DC3_IRQFILT_INTL_EN) {
1410
flags |= VG_MODEFLAG_INTERLACED;
1411
if (irq & DC3_IRQFILT_INTL_ADDR)
1412
flags |= VG_MODEFLAG_INT_ADDRESS;
1413
else if (genlk & DC3_GC_FLICKER_FILTER_ENABLE)
1414
flags |= VG_MODEFLAG_INT_FLICKER;
1416
flags |= VG_MODEFLAG_INT_LINEDOUBLE;
1421
temp = READ_VID32(DF_DISPLAY_CONFIG);
1422
if (temp & DF_DCFG_CRT_HSYNC_POL)
1423
flags |= VG_MODEFLAG_NEG_HSYNC;
1424
if (temp & DF_DCFG_CRT_VSYNC_POL)
1425
flags |= VG_MODEFLAG_NEG_VSYNC;
1429
temp = READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_DISP_MODE_MASK;
1430
if (temp == DC3_DCFG_DISP_MODE_8BPP) {
1431
iflags |= VG_SUPPORTFLAG_8BPP;
1434
else if (temp == DC3_DCFG_DISP_MODE_24BPP) {
1435
iflags |= VG_SUPPORTFLAG_24BPP;
1438
else if (temp == DC3_DCFG_DISP_MODE_32BPP) {
1439
iflags |= VG_SUPPORTFLAG_32BPP;
1442
else if (temp == DC3_DCFG_DISP_MODE_16BPP) {
1443
temp = READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_16BPP_MODE_MASK;
1444
if (temp == DC3_DCFG_16BPP) {
1445
iflags |= VG_SUPPORTFLAG_16BPP;
1448
else if (temp == DC3_DCFG_15BPP) {
1449
iflags |= VG_SUPPORTFLAG_15BPP;
1452
else if (temp == DC3_DCFG_12BPP) {
1453
iflags |= VG_SUPPORTFLAG_12BPP;
1458
/* TV RELATED FLAGS */
1460
msr_read64(MSR_DEVICE_GEODELX_DF, DF_MSR_PAD_SEL, &msr_value);
1461
if (msr_value.high & DF_INVERT_VOP_CLOCK)
1462
flags |= VG_MODEFLAG_TVOUT;
1466
temp = (READ_REG32(DC3_GFX_PITCH) & 0x0000FFFF) << 3;
1467
if (temp != 1024 && temp != 2048 && temp != 4096 && temp != 8192)
1468
flags |= VG_MODEFLAG_LINEARPITCH;
1470
/* SIMULTANEOUS CRT/FP */
1472
msr_read64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
1473
if (msr_value.low & DF_SIMULTANEOUS_CRT_FP)
1474
flags |= VG_MODEFLAG_CRT_AND_FP;
1476
/* SET PLL-RELATED FLAGS */
1478
msr_read64(MSR_DEVICE_GEODELX_GLCP, GLCP_DOTPLL, &msr_value);
1479
if (msr_value.high & GLCP_DOTPLL_DIV4)
1480
flags |= VG_MODEFLAG_QVGA;
1481
if (msr_value.low & GLCP_DOTPLL_HALFPIX)
1482
flags |= VG_MODEFLAG_HALFCLOCK;
1484
/* SAVE THE FLAGS IN THE MODE STRUCTURE */
1486
current_display->internal_flags = iflags;
1487
current_display->flags = flags;
1489
/* READ PIXEL CLOCK FREQUENCY */
1490
/* We first search for an exact match. If none is found, we try */
1491
/* a fixed point calculation and return CIM_STATUS_INEXACTMATCH. */
1493
for (i = 0; i < NUM_CIMARRON_PLL_FREQUENCIES; i++) {
1494
if (CimarronPLLFrequencies[i].pll_value == msr_value.high)
1498
if (i == NUM_CIMARRON_PLL_FREQUENCIES) {
1499
/* ATTEMPT 16.16 CALCULATION */
1500
/* We assume the input frequency is 48 MHz, which is represented */
1501
/* in 16.16 fixed point as 0x300000. The PLL calculation is: */
1503
/* Fout = 48.000 * -------------- */
1506
p = msr_value.high & 0xF;
1507
n = (msr_value.high >> 4) & 0xFF;
1508
m = (msr_value.high >> 12) & 0x7;
1509
current_display->frequency = (0x300000 * (n + 1)) / ((p + 1) * (m + 1));
1511
return CIM_STATUS_INEXACTMATCH;
1514
current_display->frequency = CimarronPLLFrequencies[i].frequency;
1516
/* NOW SEARCH FOR AN IDENTICAL MODE */
1517
/* This is just to inform the user that an exact match was found. */
1518
/* With an exact match, the user can use the refresh rate flag that */
1519
/* is returned in the VG_DISPLAY_MODE structure. */
1521
for (i = 0; i < NUM_CIMARRON_DISPLAY_MODES; i++) {
1522
if ((CimarronDisplayModes[i].flags & current_display->flags) &&
1523
CimarronDisplayModes[i].frequency ==
1524
current_display->frequency &&
1525
CimarronDisplayModes[i].hactive == current_display->hactive &&
1526
CimarronDisplayModes[i].hblankstart ==
1527
current_display->hblankstart
1528
&& CimarronDisplayModes[i].hsyncstart ==
1529
current_display->hsyncstart
1530
&& CimarronDisplayModes[i].hsyncend ==
1531
current_display->hsyncend
1532
&& CimarronDisplayModes[i].hblankend ==
1533
current_display->hblankend
1534
&& CimarronDisplayModes[i].htotal == current_display->htotal
1535
&& CimarronDisplayModes[i].vactive == current_display->vactive
1536
&& CimarronDisplayModes[i].vblankstart ==
1537
current_display->vblankstart
1538
&& CimarronDisplayModes[i].vsyncstart ==
1539
current_display->vsyncstart
1540
&& CimarronDisplayModes[i].vsyncend ==
1541
current_display->vsyncend
1542
&& CimarronDisplayModes[i].vblankend ==
1543
current_display->vblankend
1544
&& CimarronDisplayModes[i].vtotal == current_display->vtotal) {
1549
if (i == NUM_CIMARRON_DISPLAY_MODES)
1550
return CIM_STATUS_INEXACTMATCH;
1552
current_display->internal_flags |=
1553
(CimarronDisplayModes[i].internal_flags & VG_SUPPORTFLAG_HZMASK);
1554
return CIM_STATUS_OK;
1557
/*---------------------------------------------------------------------------
1558
* vg_set_scaler_filter_coefficients
1560
* This routine sets the vertical and horizontal filter coefficients for
1561
* graphics scaling. If either of the input arrays is specified as NULL, a
1562
* set of default coeffecients will be used.
1563
*--------------------------------------------------------------------------*/
1566
vg_set_scaler_filter_coefficients(long h_taps[][5], long v_taps[][3])
1568
unsigned long irqfilt, i;
1569
unsigned long temp0, temp1;
1572
/* ENABLE ACCESS TO THE HORIZONTAL COEFFICIENTS */
1574
irqfilt = READ_REG32(DC3_IRQ_FILT_CTL);
1575
irqfilt |= DC3_IRQFILT_H_FILT_SEL;
1577
/* UNLOCK THE COEFFICIENT REGISTERS */
1579
lock = READ_REG32(DC3_UNLOCK);
1580
WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
1582
/* WRITE COEFFICIENTS */
1583
/* Coefficient indexes do not auto-increment, so we must */
1584
/* write the address for every phase */
1586
for (i = 0; i < 256; i++) {
1587
WRITE_REG32(DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
1590
temp0 = CimarronHorizontalGraphicsFilter[i][0];
1591
temp1 = CimarronHorizontalGraphicsFilter[i][1];
1594
temp0 = ((unsigned long) h_taps[i][0] & 0x3FF) |
1595
(((unsigned long) h_taps[i][1] & 0x3FF) << 10) |
1596
(((unsigned long) h_taps[i][2] & 0x3FF) << 20);
1598
temp1 = ((unsigned long) h_taps[i][3] & 0x3FF) |
1599
(((unsigned long) h_taps[i][4] & 0x3FF) << 10);
1601
WRITE_REG32(DC3_FILT_COEFF1, temp0);
1602
WRITE_REG32(DC3_FILT_COEFF2, temp1);
1605
/* ENABLE ACCESS TO THE VERTICAL COEFFICIENTS */
1607
irqfilt &= ~DC3_IRQFILT_H_FILT_SEL;
1609
/* WRITE COEFFICIENTS */
1611
for (i = 0; i < 256; i++) {
1612
WRITE_REG32(DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
1615
temp0 = CimarronVerticalGraphicsFilter[i];
1618
temp0 = ((unsigned long) v_taps[i][0] & 0x3FF) |
1619
(((unsigned long) v_taps[i][1] & 0x3FF) << 10) |
1620
(((unsigned long) v_taps[i][2] & 0x3FF) << 20);
1623
WRITE_REG32(DC3_FILT_COEFF1, temp0);
1626
WRITE_REG32(DC3_UNLOCK, lock);
1628
return CIM_STATUS_OK;
1631
/*---------------------------------------------------------------------------
1632
* vg_configure_flicker_filter
1634
* This routine updates the VG flicker filter settings when in an interlaced
1635
* mode. Note that flicker filtering is enabled inside a mode set. This routine
1636
* is provided to change from the default flicker filter setting of
1638
*--------------------------------------------------------------------------*/
1641
vg_configure_flicker_filter(unsigned long flicker_strength, int flicker_alpha)
1643
unsigned long unlock;
1644
unsigned long genlk_ctl;
1646
/* CHECK FOR VALID FLICKER SETTING */
1648
if (flicker_strength != VG_FLICKER_FILTER_NONE &&
1649
flicker_strength != VG_FLICKER_FILTER_1_16 &&
1650
flicker_strength != VG_FLICKER_FILTER_1_8 &&
1651
flicker_strength != VG_FLICKER_FILTER_1_4 &&
1652
flicker_strength != VG_FLICKER_FILTER_5_16) {
1653
return CIM_STATUS_INVALIDPARAMS;
1656
unlock = READ_REG32(DC3_UNLOCK);
1657
genlk_ctl = READ_REG32(DC3_GENLK_CTL) & ~(DC3_GC_FLICKER_FILTER_MASK |
1658
DC3_GC_ALPHA_FLICK_ENABLE);
1659
genlk_ctl |= flicker_strength;
1661
genlk_ctl |= DC3_GC_ALPHA_FLICK_ENABLE;
1663
WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
1664
WRITE_REG32(DC3_GENLK_CTL, genlk_ctl);
1665
WRITE_REG32(DC3_UNLOCK, unlock);
1667
return CIM_STATUS_OK;
1670
/*---------------------------------------------------------------------------
1671
* vg_set_clock_frequency
1673
* This routine sets the frequency of the dot clock. The input to this
1674
* routine is a 16.16 fraction. If an exact match is not found, this
1675
* routine will program the closest available frequency and return
1676
* CIM_STATUS_INEXACTMATCH.
1677
*--------------------------------------------------------------------------*/
1680
vg_set_clock_frequency(unsigned long frequency, unsigned long pll_flags)
1683
unsigned long timeout;
1684
unsigned long index = 0;
1685
unsigned long unlock, i;
1686
unsigned long pll_high, pll_low;
1689
/* FIND THE REGISTER VALUES FOR THE DESIRED FREQUENCY */
1690
/* Search the table for the closest frequency (16.16 format). */
1691
/* This search is skipped if the user is manually specifying */
1692
/* the MSR value. */
1695
if (!(pll_flags & VG_PLL_MANUAL)) {
1696
min = (long) CimarronPLLFrequencies[0].frequency - (long) frequency;
1700
for (i = 1; i < NUM_CIMARRON_PLL_FREQUENCIES; i++) {
1701
diff = (long) CimarronPLLFrequencies[i].frequency -
1712
pll_high = CimarronPLLFrequencies[index].pll_value & 0x00007FFF;
1715
pll_high = frequency;
1718
if (pll_flags & VG_PLL_DIVIDE_BY_2)
1719
pll_low |= GLCP_DOTPLL_HALFPIX;
1720
if (pll_flags & VG_PLL_DIVIDE_BY_4)
1721
pll_high |= GLCP_DOTPLL_DIV4;
1722
if (pll_flags & VG_PLL_BYPASS)
1723
pll_low |= GLCP_DOTPLL_BYPASS;
1724
if (pll_flags & VG_PLL_VIP_CLOCK)
1725
pll_high |= GLCP_DOTPLL_VIPCLK;
1727
/* VERIFY THAT WE ARE NOT WRITING WHAT IS ALREADY IN THE REGISTERS */
1728
/* The Dot PLL reset bit is tied to VDD for flat panels. This can */
1729
/* cause a brief drop in flat panel power, which can cause serious */
1730
/* glitches on some panels. */
1732
msr_read64(MSR_DEVICE_GEODELX_GLCP, GLCP_DOTPLL, &msr_value);
1734
if ((msr_value.low & GLCP_DOTPLL_LOCK) &&
1735
((msr_value.low & (GLCP_DOTPLL_HALFPIX | GLCP_DOTPLL_BYPASS)) ==
1736
pll_low) && (msr_value.high == pll_high)) {
1737
return CIM_STATUS_OK;
1740
/* PROGRAM THE SETTINGS WITH THE RESET BIT SET */
1741
/* Clear the bypass bit to ensure that the programmed */
1742
/* M, N and P values are being used. */
1744
msr_value.high = pll_high;
1745
msr_value.low &= ~(GLCP_DOTPLL_BYPASS | GLCP_DOTPLL_HALFPIX);
1746
msr_value.low |= (pll_low | 0x00000001);
1747
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DOTPLL, &msr_value);
1749
/* WAIT FOR THE LOCK BIT */
1750
/* The PLL spec states that the PLL may take up to 100 us to */
1751
/* properly lock. Furthermore, the lock signal is not 100% */
1752
/* reliable. To address this, we add a hefty delay followed */
1753
/* by a polling loop that times out after a 1000 reads. */
1755
unlock = READ_REG32(DC3_UNLOCK);
1756
for (timeout = 0; timeout < 1280; timeout++)
1757
WRITE_REG32(DC3_UNLOCK, unlock);
1759
for (timeout = 0; timeout < 1000; timeout++) {
1760
msr_read64(MSR_DEVICE_GEODELX_GLCP, GLCP_DOTPLL, &msr_value);
1761
if (msr_value.low & GLCP_DOTPLL_LOCK)
1765
/* CLEAR THE RESET BIT */
1767
msr_value.low &= 0xFFFFFFFE;
1768
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DOTPLL, &msr_value);
1770
/* DID THE PLL SUCCESSFULLY LOCK? */
1772
if (!(msr_value.low & GLCP_DOTPLL_LOCK))
1773
return CIM_STATUS_NOLOCK;
1775
/* RETURN THE APPROPRIATE CODE */
1778
return CIM_STATUS_OK;
1780
return CIM_STATUS_INEXACTMATCH;
1783
/*---------------------------------------------------------------------------
1784
* vg_set_border_color
1786
* This routine sets the color used as the border in centered panel modes.
1787
*--------------------------------------------------------------------------*/
1790
vg_set_border_color(unsigned long border_color)
1792
unsigned long lock = READ_REG32(DC3_UNLOCK);
1794
WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
1795
WRITE_REG32(DC3_PAL_ADDRESS, 0x104);
1796
WRITE_REG32(DC3_PAL_DATA, border_color);
1797
WRITE_REG32(DC3_UNLOCK, lock);
1799
return CIM_STATUS_OK;
1802
/*---------------------------------------------------------------------------
1803
* vg_set_cursor_enable
1805
* This routine enables or disables the hardware cursor. This routine should
1806
* only be called after the hardware cursor has been completely configured.
1807
*--------------------------------------------------------------------------*/
1810
vg_set_cursor_enable(int enable)
1812
unsigned long unlock, gcfg;
1814
/* SET OR CLEAR CURSOR ENABLE BIT */
1816
unlock = READ_REG32(DC3_UNLOCK);
1817
gcfg = READ_REG32(DC3_GENERAL_CFG);
1819
gcfg |= DC3_GCFG_CURE;
1821
gcfg &= ~(DC3_GCFG_CURE);
1823
/* WRITE NEW REGISTER VALUE */
1825
WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
1826
WRITE_REG32(DC3_GENERAL_CFG, gcfg);
1827
WRITE_REG32(DC3_UNLOCK, unlock);
1829
return CIM_STATUS_OK;
1832
/*---------------------------------------------------------------------------
1833
* vg_set_mono_cursor_colors
1835
* This routine sets the colors of the hardware monochrome cursor.
1836
*--------------------------------------------------------------------------*/
1839
vg_set_mono_cursor_colors(unsigned long bkcolor, unsigned long fgcolor)
1841
unsigned long lock = READ_REG32(DC3_UNLOCK);
1843
/* SET CURSOR COLORS */
1845
WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
1846
WRITE_REG32(DC3_PAL_ADDRESS, 0x100);
1847
WRITE_REG32(DC3_PAL_DATA, bkcolor);
1848
WRITE_REG32(DC3_PAL_DATA, fgcolor);
1849
WRITE_REG32(DC3_UNLOCK, lock);
1851
return CIM_STATUS_OK;
1854
/*---------------------------------------------------------------------------
1855
* vg_set_cursor_position
1857
* This routine sets the position of the hardware cursor. The cursor hotspots
1858
* and memory offset must have been specified in an earlier call to
1859
* a vg_set_cursor_shape_XX routine. The coordinates passed to this routine
1860
* generally specify the focal point of the cursor, NOT the upper left
1861
* coordinate of the cursor pattern. However, for operating systems that do
1862
* not include a hotspot the input parameters may be negative.
1863
*--------------------------------------------------------------------------*/
1866
vg_set_cursor_position(long xpos, long ypos, VG_PANNING_COORDINATES * panning)
1868
unsigned long unlock, memoffset;
1873
memoffset = vg3_cursor_offset;
1874
x = xpos - (long) vg3_x_hotspot;
1875
y = ypos - (long) vg3_y_hotspot;
1877
/* HANDLE NEGATIVE COORDINATES */
1878
/* This routine supports operating systems that use negative */
1879
/* coordinates, instead of positive coordinates with an appropriate */
1888
return CIM_STATUS_INVALIDPARAMS;
1890
return CIM_STATUS_INVALIDPARAMS;
1892
if (vg3_panel_enable) {
1893
if ((vg3_mode_width > vg3_panel_width)
1894
|| (vg3_mode_height > vg3_panel_height)) {
1895
vg_pan_desktop(xpos, ypos, panning);
1896
x = x - (unsigned short) vg3_delta_x;
1897
y = y - (unsigned short) vg3_delta_y;
1900
panning->start_x = 0;
1901
panning->start_y = 0;
1902
panning->start_updated = 0;
1906
/* ADJUST OFFSETS */
1907
/* Cursor movement and panning work as follows: The cursor position */
1908
/* refers to where the hotspot of the cursor is located. However, for */
1909
/* non-zero hotspots, the cursor buffer actually begins before the */
1910
/* specified position. */
1927
if (vg3_color_cursor)
1928
memoffset += (unsigned long) yoffset *192;
1931
memoffset += (unsigned long) yoffset << 4;
1933
/* SET COLOR CURSOR BIT */
1935
gcfg = READ_REG32(DC3_GENERAL_CFG);
1936
if (vg3_color_cursor)
1937
gcfg |= DC3_GCFG_CLR_CUR;
1939
gcfg &= ~DC3_GCFG_CLR_CUR;
1941
/* SET CURSOR POSITION */
1943
unlock = READ_REG32(DC3_UNLOCK);
1944
WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
1945
WRITE_REG32(DC3_CURS_ST_OFFSET, memoffset);
1946
WRITE_REG32(DC3_GENERAL_CFG, gcfg);
1947
WRITE_REG32(DC3_CURSOR_X, (unsigned long) x |
1948
(((unsigned long) xoffset) << 11));
1949
WRITE_REG32(DC3_CURSOR_Y, (unsigned long) y |
1950
(((unsigned long) yoffset) << 11));
1951
WRITE_REG32(DC3_UNLOCK, unlock);
1953
return CIM_STATUS_OK;
1956
/*---------------------------------------------------------------------------
1957
* vg_set_mono_cursor_shape32
1959
* This routine loads 32x32 cursor data into the cursor buffer in graphics
1960
* memory. The outside of the GeodeLX cursor buffer is padded with
1962
*--------------------------------------------------------------------------*/
1965
vg_set_mono_cursor_shape32(unsigned long memoffset, unsigned long *andmask,
1966
unsigned long *xormask, unsigned long x_hotspot,
1967
unsigned long y_hotspot)
1971
/* SAVE THE CURSOR OFFSET AND HOTSPOTS */
1972
/* These are reused later when updating the cursor position, panning */
1973
/* and clipping the cursor pointer. */
1975
vg3_x_hotspot = x_hotspot;
1976
vg3_y_hotspot = y_hotspot;
1977
vg3_cursor_offset = memoffset;
1978
vg3_color_cursor = 0;
1980
for (i = 0; i < 32; i++) {
1981
/* EVEN QWORDS CONTAIN THE AND MASK */
1983
WRITE_FB32(memoffset, 0xFFFFFFFF);
1984
WRITE_FB32(memoffset + 4, andmask[i]);
1986
/* ODD QWORDS CONTAIN THE XOR MASK */
1988
WRITE_FB32(memoffset + 8, 0x00000000);
1989
WRITE_FB32(memoffset + 12, xormask[i]);
1994
/* FILL THE LOWER HALF OF THE BUFFER WITH TRANSPARENT PIXELS */
1996
for (i = 0; i < 32; i++) {
1997
WRITE_FB32(memoffset, 0xFFFFFFFF);
1998
WRITE_FB32(memoffset + 4, 0xFFFFFFFF);
1999
WRITE_FB32(memoffset + 8, 0x00000000);
2000
WRITE_FB32(memoffset + 12, 0x00000000);
2005
return CIM_STATUS_OK;
2008
/*---------------------------------------------------------------------------
2009
* vg_set_mono_cursor_shape64
2011
* This routine loads 64x64 cursor data into the cursor buffer in graphics
2013
*--------------------------------------------------------------------------*/
2016
vg_set_mono_cursor_shape64(unsigned long memoffset, unsigned long *andmask,
2017
unsigned long *xormask, unsigned long x_hotspot,
2018
unsigned long y_hotspot)
2022
/* SAVE THE CURSOR OFFSET AND HOTSPOTS */
2023
/* These are reused later when updating the cursor position, panning */
2024
/* and clipping the cursor pointer. */
2026
vg3_x_hotspot = x_hotspot;
2027
vg3_y_hotspot = y_hotspot;
2028
vg3_cursor_offset = memoffset;
2029
vg3_color_cursor = 0;
2031
for (i = 0; i < 128; i += 2) {
2032
/* EVEN QWORDS CONTAIN THE AND MASK */
2033
/* We invert the dwords to prevent the calling */
2034
/* application from having to think in terms of Qwords. */
2035
/* The hardware data order is actually 63:0, or 31:0 of */
2036
/* the second dword followed by 31:0 of the first dword. */
2038
WRITE_FB32(memoffset, andmask[i + 1]);
2039
WRITE_FB32(memoffset + 4, andmask[i]);
2041
/* ODD QWORDS CONTAIN THE XOR MASK */
2043
WRITE_FB32(memoffset + 8, xormask[i + 1]);
2044
WRITE_FB32(memoffset + 12, xormask[i]);
2049
return CIM_STATUS_OK;
2052
/*---------------------------------------------------------------------------
2053
* vg_set_color_cursor_shape
2055
* This routine loads 8:8:8:8 cursor data into the color cursor buffer.
2056
*--------------------------------------------------------------------------*/
2059
vg_set_color_cursor_shape(unsigned long memoffset, unsigned char *data,
2060
unsigned long width, unsigned long height, long pitch,
2061
unsigned long x_hotspot, unsigned long y_hotspot)
2065
/* SAVE THE CURSOR OFFSET AND HOTSPOTS */
2066
/* These are reused later when updating the cursor position, panning */
2067
/* and clipping the cursor pointer. */
2069
vg3_x_hotspot = x_hotspot;
2070
vg3_y_hotspot = y_hotspot;
2071
vg3_cursor_offset = memoffset;
2072
vg3_color_cursor = 1;
2074
/* WRITE THE CURSOR DATA */
2075
/* The outside edges of the color cursor are filled with transparency */
2076
/* The cursor buffer dimensions are 48x64. */
2078
for (y = 0; y < height; y++) {
2079
/* WRITE THE ACTIVE AND TRANSPARENT DATA */
2080
/* We implement this as a macro in our dedication to squeaking */
2081
/* every ounce of performance out of our code... */
2083
WRITE_FB_STRING32(memoffset, data, width);
2084
WRITE_FB_CONSTANT((memoffset + (width << 2)), 0, (48 - width));
2086
/* INCREMENT PAST THE LINE */
2092
/* WRITE THE EXTRA TRANSPARENT LINES */
2093
/* Write the lines in one big bulk setting. */
2095
WRITE_FB_CONSTANT(memoffset, 0, ((64 - height) * 48));
2097
return CIM_STATUS_OK;
2100
/*---------------------------------------------------------------------------
2103
* This routine sets the correct display offset based on the current cursor
2105
*--------------------------------------------------------------------------*/
2108
vg_pan_desktop(unsigned long x, unsigned long y,
2109
VG_PANNING_COORDINATES * panning)
2111
unsigned long modeShiftPerPixel;
2112
unsigned long modeBytesPerScanline;
2113
unsigned long startAddress;
2115
/* TEST FOR NO-WORK */
2117
if (x >= vg3_delta_x && x < (vg3_panel_width + vg3_delta_x) &&
2118
y >= vg3_delta_y && y < (vg3_panel_height + vg3_delta_y)) {
2119
panning->start_x = vg3_delta_x;
2120
panning->start_y = vg3_delta_y;
2121
panning->start_updated = 0;
2122
return CIM_STATUS_OK;
2126
modeShiftPerPixel = 2;
2128
modeShiftPerPixel = (vg3_bpp + 7) >> 4;
2130
modeBytesPerScanline = (READ_REG32(DC3_GFX_PITCH) & 0x0000FFFF) << 3;
2132
/* ADJUST PANNING VARIABLES WHEN CURSOR EXCEEDS BOUNDARY */
2133
/* Test the boundary conditions for each coordinate and update */
2134
/* all variables and the starting offset accordingly. */
2136
if (x < vg3_delta_x)
2138
else if (x >= (vg3_delta_x + vg3_panel_width))
2139
vg3_delta_x = x - vg3_panel_width + 1;
2141
if (y < vg3_delta_y)
2143
else if (y >= (vg3_delta_y + vg3_panel_height))
2144
vg3_delta_y = y - vg3_panel_height + 1;
2146
/* CALCULATE THE START OFFSET */
2148
startAddress = (vg3_delta_x << modeShiftPerPixel) +
2149
(vg3_delta_y * modeBytesPerScanline);
2151
vg_set_display_offset(startAddress);
2153
panning->start_updated = 1;
2154
panning->start_x = vg3_delta_x;
2155
panning->start_y = vg3_delta_y;
2156
return CIM_STATUS_OK;
2159
/*---------------------------------------------------------------------------
2160
* vg_set_display_offset
2162
* This routine sets the start address of the frame buffer. It is
2163
* typically used to pan across a virtual desktop (frame buffer larger than
2164
* the displayed screen) or to flip the display between multiple buffers.
2165
*--------------------------------------------------------------------------*/
2168
vg_set_display_offset(unsigned long address)
2170
unsigned long lock, gcfg;
2172
lock = READ_REG32(DC3_UNLOCK);
2173
WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
2175
/* DISABLE COMPRESSION */
2176
/* When setting a non-zero display offset, we must disable display */
2177
/* compression. We could maintain a variable and re-enable */
2178
/* compression when the offset returns to zero. However, that */
2179
/* creates additional complexity for applications that perform */
2180
/* graphics animation. Re-enabling compression each time would */
2181
/* be tedious and slow for such applications, implying that they */
2182
/* would have to disable compression before starting the animation. */
2183
/* We will instead disable compression and force the user to */
2184
/* re-enable compression when they are ready. */
2187
if (READ_REG32(DC3_GENERAL_CFG) & DC3_GCFG_CMPE) {
2188
gcfg = READ_REG32(DC3_GENERAL_CFG);
2189
WRITE_REG32(DC3_GENERAL_CFG,
2190
(gcfg & ~(DC3_GCFG_CMPE | DC3_GCFG_DECE)));
2194
WRITE_REG32(DC3_FB_ST_OFFSET, address);
2195
WRITE_REG32(DC3_UNLOCK, lock);
2197
return CIM_STATUS_OK;
2200
/*---------------------------------------------------------------------------
2201
* vg_set_display_pitch
2203
* This routine sets the stride between successive lines of data in the frame
2205
*--------------------------------------------------------------------------*/
2208
vg_set_display_pitch(unsigned long pitch)
2210
unsigned long temp, dvsize, dvtop, value;
2211
unsigned long lock = READ_REG32(DC3_UNLOCK);
2213
value = READ_REG32(DC3_GFX_PITCH) & 0xFFFF0000;
2214
value |= (pitch >> 3);
2216
/* PROGRAM THE DISPLAY PITCH */
2218
WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
2219
WRITE_REG32(DC3_GFX_PITCH, value);
2221
/* SET THE COMPRESSION BEHAVIOR BASED ON THE PITCH */
2222
/* Strides that are not a power of two will not work with line */
2223
/* by line compression. For these cases, we enable full-screen */
2224
/* compression. In this mode, any write to the frame buffer */
2225
/* region marks the entire frame as dirty. Also, the DV line */
2226
/* size must be updated when the pitch is programmed outside of */
2227
/* the power of 2 range specified in a mode set. */
2230
dvsize = DC3_DV_LINE_SIZE_8192;
2232
else if (pitch > 2048) {
2233
dvsize = DC3_DV_LINE_SIZE_4096;
2235
else if (pitch > 1024) {
2236
dvsize = DC3_DV_LINE_SIZE_2048;
2239
dvsize = DC3_DV_LINE_SIZE_1024;
2242
temp = READ_REG32(DC3_DV_CTL);
2243
WRITE_REG32(DC3_DV_CTL,
2244
(temp & ~DC3_DV_LINE_SIZE_MASK) | dvsize | 0x00000001);
2246
value = READ_REG32(DC3_GENERAL_CFG);
2248
if (pitch == 1024 || pitch == 2048 || pitch == 4096 || pitch == 8192) {
2249
value &= ~DC3_GCFG_FDTY;
2253
value |= DC3_GCFG_FDTY;
2255
dvtop = (READ_REG32(DC3_FB_ACTIVE) & 0xFFF) + 1;
2256
dvtop = ((dvtop * pitch) + 0x3FF) & 0xFFFFFC00;
2257
dvtop |= DC3_DVTOP_ENABLE;
2260
WRITE_REG32(DC3_GENERAL_CFG, value);
2261
WRITE_REG32(DC3_DV_TOP, dvtop);
2262
WRITE_REG32(DC3_UNLOCK, lock);
2264
return CIM_STATUS_OK;
2267
/*---------------------------------------------------------------------------
2268
* vg_set_display_palette_entry
2270
* This routine sets a single 8BPP palette entry in the display controller.
2271
*--------------------------------------------------------------------------*/
2274
vg_set_display_palette_entry(unsigned long index, unsigned long palette)
2276
unsigned long dcfg, unlock;
2279
return CIM_STATUS_INVALIDPARAMS;
2281
unlock = READ_REG32(DC3_UNLOCK);
2282
dcfg = READ_REG32(DC3_DISPLAY_CFG);
2284
WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
2285
WRITE_REG32(DC3_DISPLAY_CFG, dcfg & ~DC3_DCFG_PALB);
2286
WRITE_REG32(DC3_UNLOCK, unlock);
2288
WRITE_REG32(DC3_PAL_ADDRESS, index);
2289
WRITE_REG32(DC3_PAL_DATA, palette);
2291
return CIM_STATUS_OK;
2294
/*---------------------------------------------------------------------------
2295
* vg_set_display_palette
2297
* This routine sets the entire palette in the display controller.
2298
* A pointer is provided to a 256 entry table of 32-bit X:R:G:B values.
2299
*--------------------------------------------------------------------------*/
2302
vg_set_display_palette(unsigned long *palette)
2304
unsigned long unlock, dcfg, i;
2306
WRITE_REG32(DC3_PAL_ADDRESS, 0);
2309
unlock = READ_REG32(DC3_UNLOCK);
2310
dcfg = READ_REG32(DC3_DISPLAY_CFG);
2312
WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
2313
WRITE_REG32(DC3_DISPLAY_CFG, dcfg & ~DC3_DCFG_PALB);
2314
WRITE_REG32(DC3_UNLOCK, unlock);
2316
for (i = 0; i < 256; i++)
2317
WRITE_REG32(DC3_PAL_DATA, palette[i]);
2319
return CIM_STATUS_OK;
2321
return CIM_STATUS_INVALIDPARAMS;
2324
/*---------------------------------------------------------------------------
2325
* vg_set_compression_enable
2327
* This routine enables or disables display compression.
2328
*--------------------------------------------------------------------------*/
2331
vg_set_compression_enable(int enable)
2334
unsigned long unlock, gcfg;
2337
unlock = READ_REG32(DC3_UNLOCK);
2338
gcfg = READ_REG32(DC3_GENERAL_CFG);
2339
WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
2342
/* DO NOT ENABLE IF THE DISPLAY OFFSET IS NOT ZERO */
2344
if (READ_REG32(DC3_FB_ST_OFFSET) & 0x0FFFFFFF)
2345
return CIM_STATUS_ERROR;
2347
/* ENABLE BIT 1 IN THE VG SPARE MSR
2348
* The bus can hang when the VG attempts to merge compression writes.
2349
* No performance is lost due to the GeodeLink QUACK features in
2350
* GeodeLX. We also enable the command word check for a valid
2351
* compression header.
2354
msr_read64(MSR_DEVICE_GEODELX_VG, DC3_SPARE_MSR, &msr_value);
2355
msr_value.low |= DC3_SPARE_FIRST_REQ_MASK;
2356
msr_value.low &= ~DC3_SPARE_DISABLE_CWD_CHECK;
2357
msr_write64(MSR_DEVICE_GEODELX_VG, DC3_SPARE_MSR, &msr_value);
2359
/* CLEAR DIRTY/VALID BITS IN MEMORY CONTROLLER
2360
* We don't want the controller to think that old lines are still
2361
* valid. Writing a 1 to bit 0 of the DV Control register will force
2362
* the hardware to clear all the valid bits.
2365
temp = READ_REG32(DC3_DV_CTL);
2366
WRITE_REG32(DC3_DV_CTL, temp | 0x00000001);
2368
/* ENABLE COMPRESSION BITS */
2370
gcfg |= DC3_GCFG_CMPE | DC3_GCFG_DECE;
2373
gcfg &= ~(DC3_GCFG_CMPE | DC3_GCFG_DECE);
2376
WRITE_REG32(DC3_GENERAL_CFG, gcfg);
2377
WRITE_REG32(DC3_UNLOCK, unlock);
2379
return CIM_STATUS_OK;
2382
/*---------------------------------------------------------------------------
2383
* vg_configure_compression
2385
* This routine configures all aspects of display compression, including
2386
* pitch, size and the offset of the compression buffer.
2387
*--------------------------------------------------------------------------*/
2390
vg_configure_compression(VG_COMPRESSION_DATA * comp_data)
2392
unsigned long delta, size;
2393
unsigned long comp_size, unlock;
2395
/* CHECK FOR VALID PARAMETERS */
2396
/* The maximum size for the compression buffer is 544 bytes (with */
2397
/* the header) Also, the pitch cannot be less than the line size */
2398
/* and the compression buffer offset must be 16-byte aligned. */
2400
if (comp_data->size > 544 || comp_data->pitch < comp_data->size ||
2401
comp_data->compression_offset & 0x0F) {
2402
return CIM_STATUS_INVALIDPARAMS;
2405
/* SUBTRACT 32 FROM SIZE */
2406
/* The display controller will actually write 4 extra QWords. So, */
2407
/* if we assume that "size" refers to the allocated size, we must */
2408
/* subtract 32 bytes. */
2410
comp_size = comp_data->size - 32;
2412
/* CALCULATE REGISTER VALUES */
2414
unlock = READ_REG32(DC3_UNLOCK);
2415
size = READ_REG32(DC3_LINE_SIZE) & ~DC3_LINE_SIZE_CBLS_MASK;
2416
delta = READ_REG32(DC3_GFX_PITCH) & ~DC3_GFX_PITCH_CBP_MASK;
2418
size |= ((comp_size >> 3) + 1) << DC3_LINE_SIZE_CB_SHIFT;
2419
delta |= ((comp_data->pitch >> 3) << 16);
2421
/* WRITE COMPRESSION PARAMETERS */
2423
WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
2424
WRITE_REG32(DC3_CB_ST_OFFSET, comp_data->compression_offset);
2425
WRITE_REG32(DC3_LINE_SIZE, size);
2426
WRITE_REG32(DC3_GFX_PITCH, delta);
2427
WRITE_REG32(DC3_UNLOCK, unlock);
2429
return CIM_STATUS_OK;
2432
/*---------------------------------------------------------------------------
2433
* vg_test_timing_active
2435
* This routine checks the status of the display timing generator.
2436
*--------------------------------------------------------------------------*/
2439
vg_test_timing_active(void)
2441
if (READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_TGEN)
2447
/*---------------------------------------------------------------------------
2448
* vg_test_vertical_active
2450
* This routine checks if the display is currently in the middle of a frame
2451
* (not in the VBlank interval)
2452
*--------------------------------------------------------------------------*/
2455
vg_test_vertical_active(void)
2457
if (READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA)
2463
/*---------------------------------------------------------------------------
2464
* vg_wait_vertical_blank
2466
* This routine waits until the beginning of the vertical blank interval.
2467
* When the display is already in vertical blank, this routine will wait until
2468
* the beginning of the next vertical blank.
2469
*--------------------------------------------------------------------------*/
2472
vg_wait_vertical_blank(void)
2474
if (vg_test_timing_active()) {
2475
while (!vg_test_vertical_active());
2476
while (vg_test_vertical_active());
2478
return CIM_STATUS_OK;
2481
/*---------------------------------------------------------------------------
2482
* vg_test_even_field
2484
* This routine tests the odd/even status of the current VG output field.
2485
*--------------------------------------------------------------------------*/
2488
vg_test_even_field(void)
2490
if (READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_EVEN_FIELD)
2496
/*---------------------------------------------------------------------------
2497
* vg_configure_line_interrupt
2499
* This routine configures the display controller's line count interrupt.
2500
* This interrupt can be used to interrupt mid-frame or to interrupt at the
2501
* beginning of vertical blank.
2502
*--------------------------------------------------------------------------*/
2505
vg_configure_line_interrupt(VG_INTERRUPT_PARAMS * interrupt_info)
2507
unsigned long irq_line, irq_enable;
2510
irq_line = READ_REG32(DC3_IRQ_FILT_CTL);
2511
irq_enable = READ_REG32(DC3_IRQ);
2512
lock = READ_REG32(DC3_UNLOCK);
2514
irq_line = (irq_line & ~DC3_IRQFILT_LINE_MASK) |
2515
((interrupt_info->line << 16) & DC3_IRQFILT_LINE_MASK);
2517
/* ENABLE OR DISABLE THE INTERRUPT */
2518
/* The line count is set before enabling and after disabling to */
2519
/* minimize spurious interrupts. The line count is set even */
2520
/* when interrupts are disabled to allow polling-based or debug */
2523
WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
2524
if (interrupt_info->enable) {
2525
WRITE_REG32(DC3_IRQ_FILT_CTL, irq_line);
2526
WRITE_REG32(DC3_IRQ, ((irq_enable & ~DC3_IRQ_MASK) | DC3_IRQ_STATUS));
2529
WRITE_REG32(DC3_IRQ, (irq_enable | DC3_IRQ_MASK));
2530
WRITE_REG32(DC3_IRQ_FILT_CTL, irq_line);
2532
WRITE_REG32(DC3_UNLOCK, lock);
2533
return CIM_STATUS_OK;
2536
/*---------------------------------------------------------------------------
2537
* vg_test_and_clear_interrupt
2539
* This routine resets any pending interrupt in the video generator. The
2540
* return value indicates the interrupt status prior to the reset.
2541
*--------------------------------------------------------------------------*/
2544
vg_test_and_clear_interrupt(void)
2546
unsigned long irq_enable;
2549
irq_enable = READ_REG32(DC3_IRQ);
2550
lock = READ_REG32(DC3_UNLOCK);
2552
/* NO ACTION IF INTERRUPTS ARE MASKED */
2553
/* We are assuming that a driver or application will not want to receive */
2554
/* the status of the interrupt when it is masked. */
2556
if ((irq_enable & (DC3_IRQ_MASK | DC3_VSYNC_IRQ_MASK)) ==
2557
(DC3_IRQ_MASK | DC3_VSYNC_IRQ_MASK))
2560
WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
2561
WRITE_REG32(DC3_IRQ, irq_enable);
2562
WRITE_REG32(DC3_UNLOCK, lock);
2564
return (irq_enable & (DC3_IRQ_STATUS | DC3_VSYNC_IRQ_STATUS));
2567
/*---------------------------------------------------------------------------
2568
* vg_test_flip_status
2570
* This routine tests if a new display offset has been latched.
2571
*--------------------------------------------------------------------------*/
2574
vg_test_flip_status(void)
2576
return (READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_FLIP);
2579
/*---------------------------------------------------------------------------
2582
* This routine saves all persistent VG state information.
2583
*--------------------------------------------------------------------------*/
2586
vg_save_state(VG_SAVE_RESTORE * vg_state)
2589
unsigned long irqfilt;
2590
unsigned long offset, i;
2593
/* READ ALL CURRENT REGISTER SETTINGS */
2595
vg_state->unlock = READ_REG32(DC3_UNLOCK);
2596
vg_state->gcfg = READ_REG32(DC3_GENERAL_CFG);
2597
vg_state->dcfg = READ_REG32(DC3_DISPLAY_CFG);
2598
vg_state->arb_cfg = READ_REG32(DC3_ARB_CFG);
2599
vg_state->fb_offset = READ_REG32(DC3_FB_ST_OFFSET);
2600
vg_state->cb_offset = READ_REG32(DC3_CB_ST_OFFSET);
2601
vg_state->cursor_offset = READ_REG32(DC3_CURS_ST_OFFSET);
2602
vg_state->video_y_offset = READ_REG32(DC3_VID_Y_ST_OFFSET);
2603
vg_state->video_u_offset = READ_REG32(DC3_VID_U_ST_OFFSET);
2604
vg_state->video_v_offset = READ_REG32(DC3_VID_V_ST_OFFSET);
2605
vg_state->dv_top = READ_REG32(DC3_DV_TOP);
2606
vg_state->line_size = READ_REG32(DC3_LINE_SIZE);
2607
vg_state->gfx_pitch = READ_REG32(DC3_GFX_PITCH);
2608
vg_state->video_yuv_pitch = READ_REG32(DC3_VID_YUV_PITCH);
2609
vg_state->h_active = READ_REG32(DC3_H_ACTIVE_TIMING);
2610
vg_state->h_blank = READ_REG32(DC3_H_BLANK_TIMING);
2611
vg_state->h_sync = READ_REG32(DC3_H_SYNC_TIMING);
2612
vg_state->v_active = READ_REG32(DC3_V_ACTIVE_TIMING);
2613
vg_state->v_blank = READ_REG32(DC3_V_BLANK_TIMING);
2614
vg_state->v_sync = READ_REG32(DC3_V_SYNC_TIMING);
2615
vg_state->fb_active = READ_REG32(DC3_FB_ACTIVE);
2616
vg_state->cursor_x = READ_REG32(DC3_CURSOR_X);
2617
vg_state->cursor_y = READ_REG32(DC3_CURSOR_Y);
2618
vg_state->vid_ds_delta = READ_REG32(DC3_VID_DS_DELTA);
2619
vg_state->fb_base = READ_REG32(DC3_PHY_MEM_OFFSET);
2620
vg_state->dv_ctl = READ_REG32(DC3_DV_CTL);
2621
vg_state->gfx_scale = READ_REG32(DC3_GFX_SCALE);
2622
vg_state->irq_ctl = READ_REG32(DC3_IRQ_FILT_CTL);
2623
vg_state->vbi_even_ctl = READ_REG32(DC3_VBI_EVEN_CTL);
2624
vg_state->vbi_odd_ctl = READ_REG32(DC3_VBI_ODD_CTL);
2625
vg_state->vbi_hor_ctl = READ_REG32(DC3_VBI_HOR);
2626
vg_state->vbi_odd_line_enable = READ_REG32(DC3_VBI_LN_ODD);
2627
vg_state->vbi_even_line_enable = READ_REG32(DC3_VBI_LN_EVEN);
2628
vg_state->vbi_pitch = READ_REG32(DC3_VBI_PITCH);
2629
vg_state->color_key = READ_REG32(DC3_COLOR_KEY);
2630
vg_state->color_key_mask = READ_REG32(DC3_COLOR_MASK);
2631
vg_state->color_key_x = READ_REG32(DC3_CLR_KEY_X);
2632
vg_state->color_key_y = READ_REG32(DC3_CLR_KEY_Y);
2633
vg_state->irq = READ_REG32(DC3_IRQ);
2634
vg_state->genlk_ctl = READ_REG32(DC3_GENLK_CTL);
2635
vg_state->vid_y_even_offset = READ_REG32(DC3_VID_EVEN_Y_ST_OFFSET);
2636
vg_state->vid_u_even_offset = READ_REG32(DC3_VID_EVEN_U_ST_OFFSET);
2637
vg_state->vid_v_even_offset = READ_REG32(DC3_VID_EVEN_V_ST_OFFSET);
2638
vg_state->vactive_even = READ_REG32(DC3_V_ACTIVE_EVEN);
2639
vg_state->vblank_even = READ_REG32(DC3_V_BLANK_EVEN);
2640
vg_state->vsync_even = READ_REG32(DC3_V_SYNC_EVEN);
2642
/* READ THE CURRENT PALETTE */
2644
lock = READ_REG32(DC3_UNLOCK);
2645
WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
2646
WRITE_REG32(DC3_PAL_ADDRESS, 0);
2647
for (i = 0; i < 261; i++)
2648
vg_state->palette[i] = READ_REG32(DC3_PAL_DATA);
2650
/* READ THE CURRENT FILTER COEFFICIENTS */
2652
/* ENABLE ACCESS TO THE HORIZONTAL COEFFICIENTS */
2654
irqfilt = READ_REG32(DC3_IRQ_FILT_CTL);
2655
irqfilt |= DC3_IRQFILT_H_FILT_SEL;
2657
/* READ HORIZONTAL COEFFICIENTS */
2659
for (i = 0; i < 256; i++) {
2660
WRITE_REG32(DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
2662
vg_state->h_coeff[(i << 1)] = READ_REG32(DC3_FILT_COEFF1);
2663
vg_state->h_coeff[(i << 1) + 1] = READ_REG32(DC3_FILT_COEFF2);
2666
/* ENABLE ACCESS TO THE VERTICAL COEFFICIENTS */
2668
irqfilt &= ~DC3_IRQFILT_H_FILT_SEL;
2670
/* READ COEFFICIENTS */
2672
for (i = 0; i < 256; i++) {
2673
WRITE_REG32(DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
2675
vg_state->v_coeff[i] = READ_REG32(DC3_FILT_COEFF1);
2678
/* READ THE CURSOR DATA */
2680
offset = READ_REG32(DC3_CURS_ST_OFFSET) & 0x0FFFFFFF;
2681
for (i = 0; i < 3072; i++)
2682
vg_state->cursor_data[i] = READ_FB32(offset + (i << 2));
2684
/* READ THE CURRENT PLL */
2686
msr_read64(MSR_DEVICE_GEODELX_GLCP, GLCP_DOTPLL, &msr_value);
2688
vg_state->pll_flags = 0;
2689
for (i = 0; i < NUM_CIMARRON_PLL_FREQUENCIES; i++) {
2690
if (CimarronPLLFrequencies[i].pll_value == (msr_value.high & 0x7FFF)) {
2691
vg_state->dot_pll = CimarronPLLFrequencies[i].frequency;
2696
if (i == NUM_CIMARRON_PLL_FREQUENCIES) {
2698
/* Enter the frequency as a manual frequency. */
2700
vg_state->dot_pll = msr_value.high;
2701
vg_state->pll_flags |= VG_PLL_MANUAL;
2703
if (msr_value.low & GLCP_DOTPLL_HALFPIX)
2704
vg_state->pll_flags |= VG_PLL_DIVIDE_BY_2;
2705
if (msr_value.low & GLCP_DOTPLL_BYPASS)
2706
vg_state->pll_flags |= VG_PLL_BYPASS;
2707
if (msr_value.high & GLCP_DOTPLL_DIV4)
2708
vg_state->pll_flags |= VG_PLL_DIVIDE_BY_4;
2709
if (msr_value.high & GLCP_DOTPLL_VIPCLK)
2710
vg_state->pll_flags |= VG_PLL_VIP_CLOCK;
2712
/* READ ALL VG MSRS */
2714
msr_read64(MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_CAP, &(vg_state->msr_cap));
2715
msr_read64(MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_CONFIG,
2716
&(vg_state->msr_config));
2717
msr_read64(MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_SMI, &(vg_state->msr_smi));
2718
msr_read64(MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_ERROR,
2719
&(vg_state->msr_error));
2720
msr_read64(MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_PM, &(vg_state->msr_pm));
2721
msr_read64(MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_DIAG,
2722
&(vg_state->msr_diag));
2723
msr_read64(MSR_DEVICE_GEODELX_VG, DC3_SPARE_MSR, &(vg_state->msr_spare));
2724
msr_read64(MSR_DEVICE_GEODELX_VG, DC3_RAM_CTL, &(vg_state->msr_ram_ctl));
2726
WRITE_REG32(DC3_UNLOCK, lock);
2728
return CIM_STATUS_OK;
2731
/*---------------------------------------------------------------------------
2734
* This routine restores all persistent VG state information.
2735
*--------------------------------------------------------------------------*/
2738
vg_restore_state(VG_SAVE_RESTORE * vg_state)
2740
unsigned long irqfilt, i;
2741
unsigned long memoffset;
2743
/* TEMPORARILY UNLOCK ALL REGISTERS */
2745
WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
2747
/* RESTORE THE FRAME BUFFER OFFSET */
2749
WRITE_REG32(DC3_PHY_MEM_OFFSET, vg_state->fb_base);
2751
/* BLANK GCFG AND DCFG */
2753
WRITE_REG32(DC3_GENERAL_CFG, 0);
2754
WRITE_REG32(DC3_DISPLAY_CFG, 0);
2756
/* RESTORE ALL REGISTERS */
2758
WRITE_REG32(DC3_ARB_CFG, vg_state->arb_cfg);
2759
WRITE_REG32(DC3_FB_ST_OFFSET, vg_state->fb_offset);
2760
WRITE_REG32(DC3_CB_ST_OFFSET, vg_state->cb_offset);
2761
WRITE_REG32(DC3_CURS_ST_OFFSET, vg_state->cursor_offset);
2762
WRITE_REG32(DC3_VID_Y_ST_OFFSET, vg_state->video_y_offset);
2763
WRITE_REG32(DC3_VID_U_ST_OFFSET, vg_state->video_u_offset);
2764
WRITE_REG32(DC3_VID_V_ST_OFFSET, vg_state->video_v_offset);
2765
WRITE_REG32(DC3_DV_TOP, vg_state->dv_top);
2766
WRITE_REG32(DC3_LINE_SIZE, vg_state->line_size);
2767
WRITE_REG32(DC3_GFX_PITCH, vg_state->gfx_pitch);
2768
WRITE_REG32(DC3_VID_YUV_PITCH, vg_state->video_yuv_pitch);
2769
WRITE_REG32(DC3_H_ACTIVE_TIMING, vg_state->h_active);
2770
WRITE_REG32(DC3_H_BLANK_TIMING, vg_state->h_blank);
2771
WRITE_REG32(DC3_H_SYNC_TIMING, vg_state->h_sync);
2772
WRITE_REG32(DC3_V_ACTIVE_TIMING, vg_state->v_active);
2773
WRITE_REG32(DC3_V_BLANK_TIMING, vg_state->v_blank);
2774
WRITE_REG32(DC3_V_SYNC_TIMING, vg_state->v_sync);
2775
WRITE_REG32(DC3_FB_ACTIVE, vg_state->fb_active);
2776
WRITE_REG32(DC3_CURSOR_X, vg_state->cursor_x);
2777
WRITE_REG32(DC3_CURSOR_Y, vg_state->cursor_y);
2778
WRITE_REG32(DC3_VID_DS_DELTA, vg_state->vid_ds_delta);
2779
WRITE_REG32(DC3_PHY_MEM_OFFSET, vg_state->fb_base);
2780
WRITE_REG32(DC3_DV_CTL, vg_state->dv_ctl | 0x00000001);
2781
WRITE_REG32(DC3_GFX_SCALE, vg_state->gfx_scale);
2782
WRITE_REG32(DC3_IRQ_FILT_CTL, vg_state->irq_ctl);
2783
WRITE_REG32(DC3_VBI_EVEN_CTL, vg_state->vbi_even_ctl);
2784
WRITE_REG32(DC3_VBI_ODD_CTL, vg_state->vbi_odd_ctl);
2785
WRITE_REG32(DC3_VBI_HOR, vg_state->vbi_hor_ctl);
2786
WRITE_REG32(DC3_VBI_LN_ODD, vg_state->vbi_odd_line_enable);
2787
WRITE_REG32(DC3_VBI_LN_EVEN, vg_state->vbi_even_line_enable);
2788
WRITE_REG32(DC3_VBI_PITCH, vg_state->vbi_pitch);
2789
WRITE_REG32(DC3_COLOR_KEY, vg_state->color_key);
2790
WRITE_REG32(DC3_COLOR_MASK, vg_state->color_key_mask);
2791
WRITE_REG32(DC3_CLR_KEY_X, vg_state->color_key_x);
2792
WRITE_REG32(DC3_CLR_KEY_Y, vg_state->color_key_y);
2793
WRITE_REG32(DC3_IRQ, vg_state->irq);
2794
WRITE_REG32(DC3_GENLK_CTL, vg_state->genlk_ctl);
2795
WRITE_REG32(DC3_VID_EVEN_Y_ST_OFFSET, vg_state->vid_y_even_offset);
2796
WRITE_REG32(DC3_VID_EVEN_U_ST_OFFSET, vg_state->vid_u_even_offset);
2797
WRITE_REG32(DC3_VID_EVEN_V_ST_OFFSET, vg_state->vid_v_even_offset);
2798
WRITE_REG32(DC3_V_ACTIVE_EVEN, vg_state->vactive_even);
2799
WRITE_REG32(DC3_V_BLANK_EVEN, vg_state->vblank_even);
2800
WRITE_REG32(DC3_V_SYNC_EVEN, vg_state->vsync_even);
2802
/* RESTORE THE PALETTE */
2804
WRITE_REG32(DC3_PAL_ADDRESS, 0);
2805
for (i = 0; i < 261; i++)
2806
WRITE_REG32(DC3_PAL_DATA, vg_state->palette[i]);
2808
/* RESTORE THE HORIZONTAL FILTER COEFFICIENTS */
2810
irqfilt = READ_REG32(DC3_IRQ_FILT_CTL);
2811
irqfilt |= DC3_IRQFILT_H_FILT_SEL;
2813
for (i = 0; i < 256; i++) {
2814
WRITE_REG32(DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
2815
WRITE_REG32(DC3_FILT_COEFF1, vg_state->h_coeff[(i << 1)]);
2816
WRITE_REG32(DC3_FILT_COEFF2, vg_state->h_coeff[(i << 1) + 1]);
2819
/* RESTORE VERTICAL COEFFICIENTS */
2821
irqfilt &= ~DC3_IRQFILT_H_FILT_SEL;
2823
for (i = 0; i < 256; i++) {
2824
WRITE_REG32(DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
2825
WRITE_REG32(DC3_FILT_COEFF1, vg_state->v_coeff[i]);
2828
/* RESTORE THE CURSOR DATA */
2830
memoffset = READ_REG32(DC3_CURS_ST_OFFSET) & 0x0FFFFFFF;
2831
WRITE_FB_STRING32(memoffset, (unsigned char *) &(vg_state->cursor_data[0]),
2834
/* RESTORE THE PLL */
2835
/* Use a common routine to use common code to poll for lock bit */
2837
vg_set_clock_frequency(vg_state->dot_pll, vg_state->pll_flags);
2839
/* RESTORE ALL VG MSRS */
2841
msr_write64(MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_CAP, &(vg_state->msr_cap));
2842
msr_write64(MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_CONFIG,
2843
&(vg_state->msr_config));
2844
msr_write64(MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_SMI, &(vg_state->msr_smi));
2845
msr_write64(MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_ERROR,
2846
&(vg_state->msr_error));
2847
msr_write64(MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_PM, &(vg_state->msr_pm));
2848
msr_write64(MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_DIAG,
2849
&(vg_state->msr_diag));
2850
msr_write64(MSR_DEVICE_GEODELX_VG, DC3_SPARE_MSR, &(vg_state->msr_spare));
2851
msr_write64(MSR_DEVICE_GEODELX_VG, DC3_RAM_CTL, &(vg_state->msr_ram_ctl));
2853
/* NOW RESTORE GCFG AND DCFG */
2855
WRITE_REG32(DC3_DISPLAY_CFG, vg_state->dcfg);
2856
WRITE_REG32(DC3_GENERAL_CFG, vg_state->gcfg);
2858
/* FINALLY RESTORE UNLOCK */
2860
WRITE_REG32(DC3_UNLOCK, vg_state->unlock);
2862
return CIM_STATUS_OK;
2865
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2866
* CIMARRON VG READ ROUTINES
2867
* These routines are included for use in diagnostics or when debugging. They
2868
* can be optionally excluded from a project.
2869
*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
2871
#if CIMARRON_INCLUDE_VG_READ_ROUTINES
2873
/*---------------------------------------------------------------------------
2874
* vg_read_graphics_crc
2876
* This routine reads the Cyclic Redundancy Check (CRC) value for the graphics
2878
*--------------------------------------------------------------------------*/
2881
vg_read_graphics_crc(int crc_source)
2883
unsigned long gcfg, unlock;
2884
unsigned long crc, vbi_even;
2885
unsigned long interlaced;
2886
unsigned long line, field;
2888
if (!(READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_TGEN))
2891
unlock = READ_REG32(DC3_UNLOCK);
2892
gcfg = READ_REG32(DC3_GENERAL_CFG);
2893
vbi_even = READ_REG32(DC3_VBI_EVEN_CTL);
2895
vbi_even &= ~DC3_VBI_EVEN_ENABLE_CRC;
2897
gcfg |= DC3_GCFG_SGRE | DC3_GCFG_CRC_MODE;
2898
gcfg &= ~(DC3_GCFG_SGFR | DC3_GCFG_SIG_SEL | DC3_GCFG_FILT_SIG_SEL);
2900
switch (crc_source) {
2901
case VG_CRC_SOURCE_PREFILTER_EVEN:
2902
case VG_CRC_SOURCE_PREFILTER:
2903
gcfg |= DC3_GCFG_SIG_SEL;
2905
case VG_CRC_SOURCE_PREFLICKER:
2906
case VG_CRC_SOURCE_PREFLICKER_EVEN:
2907
gcfg |= DC3_GCFG_FILT_SIG_SEL;
2909
case VG_CRC_SOURCE_POSTFLICKER:
2910
case VG_CRC_SOURCE_POSTFLICKER_EVEN: /* NO WORK */
2917
if (crc_source & VG_CRC_SOURCE_EVEN)
2920
field = DC3_LNCNT_EVEN_FIELD;
2922
if ((interlaced = (READ_REG32(DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN))) {
2923
/* WAIT FOR THE BEGINNING OF THE FIELD (LINE 1-5) */
2924
/* Note that we wait for the field to be odd when CRCing the even */
2925
/* field and vice versa. This is because the CRC will not begin */
2926
/* until the following field. */
2929
line = READ_REG32(DC3_LINE_CNT_STATUS);
2930
} while ((line & DC3_LNCNT_EVEN_FIELD) != field ||
2931
((line & DC3_LNCNT_V_LINE_CNT) >> 16) < 10 ||
2932
((line & DC3_LNCNT_V_LINE_CNT) >> 16) > 15);
2935
/* NON-INTERLACED - EVEN FIELD CRCS ARE INVALID */
2937
if (crc_source & VG_CRC_SOURCE_EVEN)
2941
WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
2942
WRITE_REG32(DC3_VBI_EVEN_CTL, vbi_even);
2943
WRITE_REG32(DC3_GENERAL_CFG, gcfg & ~DC3_GCFG_SIGE);
2944
WRITE_REG32(DC3_GENERAL_CFG, gcfg | DC3_GCFG_SIGE);
2946
/* WAIT FOR THE CRC TO BE COMPLETED */
2948
while (!(READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_SIGC));
2950
/* READ THE COMPLETED CRC */
2952
crc = READ_REG32(DC3_PAL_DATA);
2954
/* RESTORE THE PALETTE SETTINGS */
2956
gcfg &= ~DC3_GCFG_SGRE;
2957
WRITE_REG32(DC3_GENERAL_CFG, gcfg);
2958
WRITE_REG32(DC3_UNLOCK, unlock);
2963
/*---------------------------------------------------------------------------
2964
* vg_read_window_crc
2966
* This routine reads the Cyclic Redundancy Check (CRC) value for a sub-
2967
* section of the frame.
2968
*--------------------------------------------------------------------------*/
2971
vg_read_window_crc(int crc_source, unsigned long x, unsigned long y,
2972
unsigned long width, unsigned long height)
2975
unsigned long crc = 0;
2976
unsigned long hactive, hblankstart;
2977
unsigned long htotal, hblankend;
2978
unsigned long line, field;
2981
hactive = ((READ_REG32(DC3_H_ACTIVE_TIMING)) & 0xFFF) + 1;
2982
hblankstart = ((READ_REG32(DC3_H_BLANK_TIMING)) & 0xFFF) + 1;
2983
htotal = ((READ_REG32(DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
2984
hblankend = ((READ_REG32(DC3_H_BLANK_TIMING) >> 16) & 0xFFF) + 1;
2986
/* TIMINGS MUST BE ACTIVE */
2988
if (!(READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_TGEN))
2991
/* DISABLE GLCP ACTIONS */
2995
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DIAGCTL, &msr_value);
2997
if ((x == 0 && width == 1) || x == 1) {
2998
/* SPECIAL CASE FOR X == 0 */
2999
/* The comparator output is a clock late in the MCP, so we cannot */
3000
/* easily catch the first pixel. If the first pixel is desired, */
3001
/* we will insert a special state machine to CRC just the first */
3004
/* N2 - DISPE HIGH AND Y == 1 */
3005
/* Goto state YState = 2 */
3007
msr_value.high = 0x00000002;
3008
msr_value.low = 0x00000C00;
3009
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 2, &msr_value);
3011
/* M3 - DISPE HIGH AND Y == 0 */
3012
/* Goto YState = 1 */
3014
msr_value.high = 0x00000002;
3015
msr_value.low = 0x00000A00;
3016
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETM0CTL + 3, &msr_value);
3018
/* N3 - DISPE LOW */
3019
/* Goto YState = 0 */
3021
msr_value.high = 0x00080000;
3022
msr_value.low = 0x00000000;
3023
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 3, &msr_value);
3025
/* Y0 -> Y1 (SET M3) */
3027
msr_value.high = 0x00000000;
3028
msr_value.low = 0x0000C000;
3029
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 18, &msr_value);
3031
/* Y1 -> Y0 (SET N3) */
3033
msr_value.low = 0x0000A000;
3034
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 17, &msr_value);
3036
/* Y1 -> Y2 (SET N2) */
3038
msr_value.low = 0x00000A00;
3039
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 19, &msr_value);
3041
/* N5 (XSTATE = 10 && CMP2 <= V. COUNTER <= CMP3) &&DISPE&& Y == 0 */
3044
msr_value.high = 0x00000002;
3045
msr_value.low = 0x10800B20;
3046
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 5, &msr_value);
3048
/* N6 (XSTATE = 10 && CMP2 <= V. COUNTER <= CMP3) && DISPE&&Y == 1 */
3051
msr_value.high = 0x00000002;
3052
msr_value.low = 0x10800D20;
3053
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 6, &msr_value);
3056
/* M4 (XSTATE = 00 AND VSYNC HIGH) */
3058
/* Note: VSync = H3A */
3060
msr_value.high = 0x00000001;
3061
msr_value.low = 0x000000A0;
3062
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETM0CTL + 4, &msr_value);
3064
/* N0 (XSTATE = 01 AND VSYNC LOW) */
3066
/* Note: VSync low = H3B */
3068
msr_value.high = 0x00040000;
3069
msr_value.low = 0x000000C0;
3070
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL, &msr_value);
3072
/* M5 (XSTATE = 10 AND VSYNC HIGH) */
3075
msr_value.high = 0x00000001;
3076
msr_value.low = 0x00000120;
3077
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETM0CTL + 5, &msr_value);
3079
/* N1 (XSTATE = 10 and DISPE HIGH) */
3080
/* Increment H. Counter */
3081
/* Note: DispE = H4 */
3083
msr_value.high = 0x00000002;
3084
msr_value.low = 0x00000120;
3085
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 1, &msr_value);
3087
/* M0 (XSTATE = 10 and H. COUNTER == LIMIT) */
3088
/* Clear H. Counter and increment V. Counter */
3090
msr_value.high = 0x00000000;
3091
msr_value.low = 0x00000122;
3092
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETM0CTL, &msr_value);
3094
/* N4 (XSTATE = 10 && CMP0 <= H. COUNTER <= CMP1 && CMP2 <= V. COUNTER
3099
msr_value.high = 0x00000002;
3100
msr_value.low = 0x10C20120;
3101
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 4, &msr_value);
3103
/* COMPARATOR 0 VALUE */
3104
/* We subtract 1 to account for a pipeline delay in the GLCP. */
3105
/* When the x coordinate is 0, we must play a special game. */
3106
/* If the width is exactly 1, we will set up a state machine */
3107
/* to only CRC the first pixel. Otherwise, we will set it */
3108
/* as an OR combination of a state that CRCs the first pixel */
3109
/* and a state that CRCs 1 clock delayed width (width - 1) */
3113
msr_value.low = (x - 1) & 0xFFFF;
3116
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0, &msr_value);
3118
/* COMPARATOR 1 VALUE */
3120
if ((x == 0 || x == 1) && width > 1)
3121
msr_value.low += width - 2;
3123
msr_value.low += width - 1;
3124
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0 + 2, &msr_value);
3126
/* COMPARATOR 2 VALUE */
3128
msr_value.low = y << 16;
3129
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0 + 4, &msr_value);
3131
/* COMPARATOR 3 VALUE */
3133
msr_value.low += (height - 1) << 16;
3134
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0 + 6, &msr_value);
3136
/* COMPARATOR MASKS */
3137
/* Comparators 0 and 1 refer to lower 16 bits of RegB */
3139
msr_value.low = 0x0000FFFF;
3140
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPMASK0, &msr_value);
3141
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPMASK0 + 2, &msr_value);
3143
/* Comparators 2 and 3 refer to upper 16 bits of RegB */
3145
msr_value.low = 0xFFFF0000;
3146
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPMASK0 + 4, &msr_value);
3147
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPMASK0 + 6, &msr_value);
3150
/* We set the mask such that all all 32 bits of data are CRCed */
3152
msr_value.low = 0xFFFFFFFF;
3153
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_REGBMASK, &msr_value);
3157
/* STATE 00->01 (SET 4M) */
3159
msr_value.low = 0x000C0000;
3160
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 14, &msr_value);
3162
/* STATE 01->10 (SET 0N) */
3164
msr_value.low = 0x0000000A;
3165
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 15, &msr_value);
3167
/* STATE 10->11 (SET 5M) */
3169
msr_value.low = 0x00C00000;
3170
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 16, &msr_value);
3172
/* CLEAR REGA WHEN TRANSITIONING TO STATE 10 */
3173
/* Do not clear RegB as the initial value must be 0x00000001 */
3175
msr_value.low = 0x0000000A;
3176
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0, &msr_value);
3178
/* REGISTER ACTION 1
3179
* CRC into RegB if cmp0 <= h.counter <= cmp1 && cmp2 <= v. counter <
3180
* cmp3 && 7 xstate = 10
3181
* Increment h.counter if xstate = 10 and HSync is low.
3184
msr_value.low = 0x000A00A0;
3185
if (x == 0 && width == 1)
3186
msr_value.low = 0x00A000A0;
3187
else if (x == 1 && width == 1)
3188
msr_value.low = 0x0A0000A0;
3189
else if (x == 1 && width > 1)
3190
msr_value.low |= 0x0A000000;
3192
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 1, &msr_value);
3194
/* REGISTER ACTION 2 */
3195
/* Increment V. Counter in REGA */
3197
msr_value.low = 0x0000000C;
3198
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 2, &msr_value);
3200
/* SET REGB TO 0x00000001 */
3202
msr_value.low = 0x00000001;
3203
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_REGB, &msr_value);
3205
/* SET XSTATE TO 0 */
3207
msr_value.low = 0x00000000;
3208
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_XSTATE, &msr_value);
3210
/* SET YSTATE TO 0 */
3212
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_YSTATE, &msr_value);
3214
/* CLEAR ALL OTHER ACTIONS */
3215
/* This prevents side-effects from previous accesses to the GLCP */
3218
msr_value.low = 0x00000000;
3219
msr_value.high = 0x00000000;
3220
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 3, &msr_value);
3221
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 4, &msr_value);
3222
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 5, &msr_value);
3223
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 6, &msr_value);
3224
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 7, &msr_value);
3225
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 8, &msr_value);
3226
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 9, &msr_value);
3227
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 10, &msr_value);
3228
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 11, &msr_value);
3229
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 12, &msr_value);
3230
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 13, &msr_value);
3231
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 20, &msr_value);
3233
/* SET DIAG SETTINGS BASED ON DESIRED CRC */
3235
if (crc_source == VG_CRC_SOURCE_POSTFLICKER
3236
|| crc_source == VG_CRC_SOURCE_POSTFLICKER_EVEN) {
3239
/* ENABLE HW CLOCK GATING AND SET GLCP CLOCK TO DOT CLOCK */
3243
msr_write64(MSR_DEVICE_GEODELX_GLCP, MSR_GEODELINK_PM, &msr_value);
3245
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
3247
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
3249
/* SET REGA LIMITS */
3250
/* Lower counter uses pixels/line */
3251
/* Upper counter is 0xFFFF to prevent rollover. */
3253
msr_value.low = 0xFFFF0000 | (hactive - 1);
3254
if (READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_DCEN) {
3255
msr_value.low += hblankstart - hactive;
3256
msr_value.low += htotal - hblankend;
3258
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_REGAVAL, &msr_value);
3260
/* USE H4 FUNCTION A FOR DISPE AND H4 FUNCTION B FOR NOT DISPE */
3261
/* DISPE is bit 34 */
3263
msr_value.high = 0x00000002;
3264
msr_value.low = 0x20000FF0;
3265
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 4, &msr_value);
3267
/* USE H3 FUNCTION A FOR VSYNC AND H3 FUNCTION B FOR NOT VSYNC */
3268
/* VSYNC is bit 32. */
3270
msr_value.high = 0x00000000;
3271
msr_value.low = 0x002055AA;
3272
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 3, &msr_value);
3274
else if (crc_source == VG_CRC_SOURCE_PREFLICKER
3275
|| crc_source == VG_CRC_SOURCE_PREFLICKER_EVEN) {
3278
/* ENABLE HW CLOCK GATING AND SET GLCP CLOCK TO GEODELINK CLOCK */
3282
msr_write64(MSR_DEVICE_GEODELX_GLCP, MSR_GEODELINK_PM, &msr_value);
3284
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
3286
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
3288
/* SET REGA LIMITS */
3289
/* Lower counter uses pixels/line */
3290
/* Upper counter is 0xFFFF to prevent rollover. */
3292
msr_value.low = 0xFFFF0000 | (hactive - 1);
3293
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_REGAVAL, &msr_value);
3295
/* USE H4 FUNCTION A FOR DISPE AND H4 FUNCTION B FOR NOT DISPE */
3296
/* DISPE is bit 47 */
3298
msr_value.high = 0x00000002;
3299
msr_value.low = 0xF0000FF0;
3300
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 4, &msr_value);
3302
/* USE H3 FUNCTION A FOR VSYNC AND H3 FUNCTION B FOR NOT VSYNC */
3303
/* VSYNC is bit 45. */
3305
msr_value.high = 0x00000000;
3306
msr_value.low = 0x002D55AA;
3307
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 3, &msr_value);
3313
msr_write64(MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_DIAG, &msr_value);
3315
/* ENABLE HW CLOCK GATING AND SET GLCP CLOCK TO GEODELINK CLOCK */
3319
msr_write64(MSR_DEVICE_GEODELX_GLCP, MSR_GEODELINK_PM, &msr_value);
3321
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
3323
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
3325
/* SET REGA LIMITS */
3326
/* Lower counter uses pixels/line */
3327
/* Upper counter is 0xFFFF to prevent rollover. */
3328
/* Note that we are assuming that the number of */
3329
/* source pixels is specified in the FB_ACTIVE register */
3332
0xFFFF0000 | ((READ_REG32(DC3_FB_ACTIVE) >> 16) & 0xFFF);
3333
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_REGAVAL, &msr_value);
3335
/* USE H4 FUNCTION A FOR DISPE AND H4 FUNCTION B FOR NOT DISPE */
3336
/* DISPE is bit 55 */
3338
msr_value.high = 0x00000003;
3339
msr_value.low = 0x70000FF0;
3340
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 4, &msr_value);
3342
/* USE H3 FUNCTION A FOR VSYNC AND H3 FUNCTION B FOR NOT VSYNC */
3343
/* VSYNC is bit 53. */
3345
msr_value.high = 0x00000000;
3346
msr_value.low = 0x003555AA;
3347
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 3, &msr_value);
3350
/* WAIT FOR THE CORRECT FIELD */
3351
/* We use the VG line count and field indicator to determine when */
3352
/* to kick off a CRC. */
3354
if (crc_source & VG_CRC_SOURCE_EVEN)
3357
field = DC3_LNCNT_EVEN_FIELD;
3359
if (READ_REG32(DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN) {
3360
/* WAIT FOR THE BEGINNING OF THE FIELD (LINE 1-5) */
3361
/* Note that we wait for the field to be odd when CRCing the even */
3362
/* field and vice versa. This is because the CRC will not begin */
3363
/* until the following field. */
3366
line = READ_REG32(DC3_LINE_CNT_STATUS);
3367
} while ((line & DC3_LNCNT_EVEN_FIELD) != field ||
3368
((line & DC3_LNCNT_V_LINE_CNT) >> 16) < 1 ||
3369
((line & DC3_LNCNT_V_LINE_CNT) >> 16) > 5);
3372
/* NON-INTERLACED - EVEN FIELD CRCS ARE INVALID */
3374
if (crc_source & VG_CRC_SOURCE_EVEN)
3378
/* UPDATE VG DIAG OUTPUT */
3381
msr_value.low = diag;
3382
msr_write64(MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_DIAG, &msr_value);
3384
/* CONFIGURE DIAG CONTROL */
3385
/* Set RegA action1 to increment lower 16 bits and clear at limit. (5) */
3386
/* Set RegA action2 to increment upper 16 bits. (6) */
3387
/* Set RegB action1 to CRC32 (1) */
3388
/* Set all comparators to REGA override (0,1 lower mbus, 2,3 upper mbus) */
3389
/* Enable all actions */
3391
msr_value.low = 0x80EA20A0;
3392
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DIAGCTL, &msr_value);
3394
/* DELAY TWO FRAMES */
3396
while (READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA);
3397
while (!(READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA));
3398
while (READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA);
3399
while (!(READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA));
3400
while (READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA);
3402
/* VERIFY THAT XSTATE = 11 */
3404
msr_read64(MSR_DEVICE_GEODELX_GLCP, GLCP_XSTATE, &msr_value);
3405
if ((msr_value.low & 3) == 3) {
3406
msr_read64(MSR_DEVICE_GEODELX_GLCP, GLCP_REGB, &msr_value);
3408
crc = msr_value.low;
3411
/* DISABLE VG DIAG BUS OUTPUTS */
3413
msr_value.low = 0x00000000;
3414
msr_value.high = 0x00000000;
3415
msr_write64(MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_DIAG, &msr_value);
3417
/* DISABLE GLCP ACTIONS */
3419
msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DIAGCTL, &msr_value);
3424
/*---------------------------------------------------------------------------
3425
* vg_get_scaler_filter_coefficients
3427
* This routine gets the vertical and horizontal filter coefficients for
3428
* graphics scaling. The coefficients are sign extended to 32-bit values.
3429
*--------------------------------------------------------------------------*/
3432
vg_get_scaler_filter_coefficients(long h_taps[][5], long v_taps[][3])
3434
unsigned long irqfilt, i;
3436
long coeff0, coeff1, coeff2;
3439
/* ENABLE ACCESS TO THE HORIZONTAL COEFFICIENTS */
3441
lock = READ_REG32(DC3_UNLOCK);
3442
irqfilt = READ_REG32(DC3_IRQ_FILT_CTL);
3443
irqfilt |= DC3_IRQFILT_H_FILT_SEL;
3445
/* WRITE COEFFICIENTS */
3446
/* Coefficient indexes do not auto-increment, so we must */
3447
/* write the address for every phase */
3449
WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
3451
for (i = 0; i < 256; i++) {
3452
WRITE_REG32(DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
3454
temp = READ_REG32(DC3_FILT_COEFF1);
3455
coeff0 = (temp & 0x3FF);
3456
coeff1 = (temp >> 10) & 0x3FF;
3457
coeff2 = (temp >> 20) & 0x3FF;
3459
h_taps[i][0] = (coeff0 << 22) >> 22;
3460
h_taps[i][1] = (coeff1 << 22) >> 22;
3461
h_taps[i][2] = (coeff2 << 22) >> 22;
3463
temp = READ_REG32(DC3_FILT_COEFF2);
3464
coeff0 = (temp & 0x3FF);
3465
coeff1 = (temp >> 10) & 0x3FF;
3467
h_taps[i][3] = (coeff0 << 22) >> 22;
3468
h_taps[i][4] = (coeff1 << 22) >> 22;
3471
/* ENABLE ACCESS TO THE VERTICAL COEFFICIENTS */
3473
irqfilt &= ~DC3_IRQFILT_H_FILT_SEL;
3475
/* WRITE COEFFICIENTS */
3477
for (i = 0; i < 256; i++) {
3478
WRITE_REG32(DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
3480
temp = READ_REG32(DC3_FILT_COEFF1);
3481
coeff0 = (temp & 0x3FF);
3482
coeff1 = (temp >> 10) & 0x3FF;
3483
coeff2 = (temp >> 20) & 0x3FF;
3485
v_taps[i][0] = (coeff0 << 22) >> 22;
3486
v_taps[i][1] = (coeff1 << 22) >> 22;
3487
v_taps[i][2] = (coeff2 << 22) >> 22;
3490
WRITE_REG32(DC3_UNLOCK, lock);
3492
return CIM_STATUS_OK;
3495
/*---------------------------------------------------------------------------
3496
* vg_get_flicker_filter_configuration
3498
* This routine returns the current VG flicker filter configuration.
3499
*--------------------------------------------------------------------------*/
3502
vg_get_flicker_filter_configuration(unsigned long *strength, int *flicker_alpha)
3504
unsigned long genlk_ctl;
3506
if (!strength || !flicker_alpha)
3507
return CIM_STATUS_INVALIDPARAMS;
3509
genlk_ctl = READ_REG32(DC3_GENLK_CTL);
3510
*strength = genlk_ctl & DC3_GC_FLICKER_FILTER_MASK;
3511
if (genlk_ctl & DC3_GC_ALPHA_FLICK_ENABLE)
3516
return CIM_STATUS_OK;
3519
/*---------------------------------------------------------------------------
3520
* vg_get_display_pitch
3522
* This routine returns the current stride between successive lines of frame
3524
*--------------------------------------------------------------------------*/
3527
vg_get_display_pitch(void)
3529
return ((READ_REG32(DC3_GFX_PITCH) & 0x0000FFFF) << 3);
3532
/*---------------------------------------------------------------------------
3533
* vg_get_frame_buffer_line_size
3535
* This routine returns the current size in bytes of one line of frame buffer
3537
*--------------------------------------------------------------------------*/
3540
vg_get_frame_buffer_line_size(void)
3542
return ((READ_REG32(DC3_LINE_SIZE) & 0x3FF) << 3);
3545
/*---------------------------------------------------------------------------
3546
* vg_get_current_vline
3548
* This routine returns the number of the current line that is being displayed
3549
* by the display controller.
3550
*--------------------------------------------------------------------------*/
3553
vg_get_current_vline(void)
3555
unsigned long current_line;
3557
/* READ THE REGISTER TWICE TO ENSURE THAT THE VALUE IS NOT TRANSITIONING */
3560
current_line = READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_V_LINE_CNT;
3562
while (current_line !=
3563
(READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_V_LINE_CNT));
3565
return (current_line >> 16);
3568
/*---------------------------------------------------------------------------
3569
* vg_get_display_offset
3571
* This routine returns the offset into the frame buffer for the first pixel
3573
*--------------------------------------------------------------------------*/
3576
vg_get_display_offset(void)
3578
return (READ_REG32(DC3_FB_ST_OFFSET) & 0x0FFFFFFF);
3581
/*---------------------------------------------------------------------------
3582
* vg_get_cursor_info
3584
* This routine returns the current settings for the hardware cursor.
3585
*--------------------------------------------------------------------------*/
3588
vg_get_cursor_info(VG_CURSOR_DATA * cursor_data)
3594
cursor_data->cursor_offset = READ_REG32(DC3_CURS_ST_OFFSET) & 0x0FFFFFFF;
3596
/* CURSOR X POSITION */
3598
temp = READ_REG32(DC3_CURSOR_X);
3599
cursor_data->cursor_x = temp & 0x7FF;
3600
cursor_data->clipx = (temp >> 11) & 0x3F;
3602
/* CURSOR Y POSITION */
3604
temp = READ_REG32(DC3_CURSOR_Y);
3605
cursor_data->cursor_y = temp & 0x7FF;
3606
cursor_data->clipy = (temp >> 11) & 0x3F;
3610
WRITE_REG32(DC3_PAL_ADDRESS, 0x100);
3611
cursor_data->mono_color0 = READ_REG32(DC3_PAL_DATA);
3612
cursor_data->mono_color1 = READ_REG32(DC3_PAL_DATA);
3614
/* CURSOR ENABLES */
3616
temp = READ_REG32(DC3_GENERAL_CFG);
3617
if (temp & DC3_GCFG_CURE)
3618
cursor_data->enable = 1;
3620
cursor_data->enable = 0;
3621
if (temp & DC3_GCFG_CLR_CUR)
3622
cursor_data->color_cursor = 1;
3624
cursor_data->color_cursor = 0;
3626
return CIM_STATUS_OK;
3629
/*----------------------------------------------------------------------------
3630
* vg_get_display_palette_entry
3632
* This routine reads a single entry in the 8BPP display palette.
3633
*--------------------------------------------------------------------------*/
3636
vg_get_display_palette_entry(unsigned long index, unsigned long *entry)
3639
return CIM_STATUS_INVALIDPARAMS;
3641
WRITE_REG32(DC3_PAL_ADDRESS, index);
3642
*entry = READ_REG32(DC3_PAL_DATA);
3644
return CIM_STATUS_OK;
3647
/*----------------------------------------------------------------------------
3648
* vg_get_border_color
3650
* This routine reads the current border color for centered displays.
3651
*--------------------------------------------------------------------------*/
3654
vg_get_border_color(void)
3656
WRITE_REG32(DC3_PAL_ADDRESS, 0x104);
3657
return READ_REG32(DC3_PAL_DATA);
3660
/*----------------------------------------------------------------------------
3661
* vg_get_display_palette
3663
* This routines reads the entire contents of the display palette into a
3664
* buffer. The display palette consists of 256 X:R:G:B values.
3665
*--------------------------------------------------------------------------*/
3668
vg_get_display_palette(unsigned long *palette)
3673
WRITE_REG32(DC3_PAL_ADDRESS, 0);
3674
for (i = 0; i < 256; i++) {
3675
palette[i] = READ_REG32(DC3_PAL_DATA);
3677
return CIM_STATUS_OK;
3679
return CIM_STATUS_INVALIDPARAMS;
3682
/*----------------------------------------------------------------------------
3683
* vg_get_compression_info
3685
* This routines reads the current status of the display compression hardware.
3686
*--------------------------------------------------------------------------*/
3689
vg_get_compression_info(VG_COMPRESSION_DATA * comp_data)
3691
comp_data->compression_offset = READ_REG32(DC3_CB_ST_OFFSET) & 0x0FFFFFFF;
3692
comp_data->pitch = (READ_REG32(DC3_GFX_PITCH) >> 13) & 0x7FFF8;
3693
comp_data->size = ((READ_REG32(DC3_LINE_SIZE) >> (DC3_LINE_SIZE_CB_SHIFT -
3696
return CIM_STATUS_OK;
3699
/*----------------------------------------------------------------------------
3700
* vg_get_compression_enable
3702
* This routines reads the current enable status of the display compression
3704
*--------------------------------------------------------------------------*/
3707
vg_get_compression_enable(void)
3709
if (READ_REG32(DC3_GENERAL_CFG) & DC3_GCFG_CMPE)
3715
/*----------------------------------------------------------------------------
3717
*--------------------------------------------------------------------------*/
3720
vg_get_valid_bit(int line)
3722
unsigned long offset;
3723
unsigned long valid;
3726
lock = READ_REG32(DC3_UNLOCK);
3727
offset = READ_REG32(DC3_PHY_MEM_OFFSET) & 0xFF000000;
3730
WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
3731
WRITE_REG32(DC3_PHY_MEM_OFFSET, offset);
3732
WRITE_REG32(DC3_UNLOCK, lock);
3733
valid = READ_REG32(DC3_DV_ACC) & 2;