~ubuntu-branches/ubuntu/precise/xserver-xorg-video-geode-lts-quantal/precise-updates

« back to all changes in this revision

Viewing changes to src/cim/cim_vg.c

  • Committer: Package Import Robot
  • Author(s): Maarten Lankhorst
  • Date: 2012-11-30 20:59:48 UTC
  • Revision ID: package-import@ubuntu.com-20121130205948-8p83molp6tff7m8o
Tags: upstream-2.11.13+git20120726
ImportĀ upstreamĀ versionĀ 2.11.13+git20120726

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2006 Advanced Micro Devices, Inc.
 
3
 *
 
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:
 
10
 *
 
11
 * The above copyright notice and this permission notice shall be included in
 
12
 * all copies or substantial portions of the Software.
 
13
 *
 
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.
 
21
 *
 
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.
 
25
 */
 
26
 
 
27
 /*
 
28
  * Cimarron display controller routines.  These routines program the display
 
29
  * mode and configure the hardware cursor and video buffers.
 
30
  */
 
31
 
 
32
/*---------------------*/
 
33
/* CIMARRON VG GLOBALS */
 
34
/*---------------------*/
 
35
 
 
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;
 
46
 
 
47
CIMARRON_STATIC unsigned long vg3_color_cursor = 0;
 
48
CIMARRON_STATIC unsigned long vg3_panel_enable = 0;
 
49
 
 
50
/*---------------------------------------------------------------------------
 
51
 * vg_delay_milliseconds
 
52
 *
 
53
 * This routine delays for a number of milliseconds based on a crude
 
54
 * delay loop.
 
55
 *--------------------------------------------------------------------------*/
 
56
 
 
57
int
 
58
vg_delay_milliseconds(unsigned long ms)
 
59
{
 
60
    /* ASSUME 500 MHZ 20 CLOCKS PER READ */
 
61
 
 
62
    unsigned long loop = ms * 25000;
 
63
 
 
64
    while (loop-- > 0) {
 
65
        READ_REG32(DC3_UNLOCK);
 
66
    }
 
67
    return CIM_STATUS_OK;
 
68
}
 
69
 
 
70
/*---------------------------------------------------------------------------
 
71
 * vg_set_display_mode
 
72
 *
 
73
 * This routine sets a CRT display mode using predefined Cimarron timings.
 
74
 * The source width and height are specified to allow scaling.
 
75
 *--------------------------------------------------------------------------*/
 
76
 
 
77
int
 
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)
 
81
{
 
82
    VG_QUERY_MODE crt_query;
 
83
    VG_DISPLAY_MODE crt_mode;
 
84
    int mode;
 
85
 
 
86
    crt_query.active_width = dst_width;
 
87
    crt_query.active_height = dst_height;
 
88
    crt_query.bpp = bpp;
 
89
    crt_query.hz = hz;
 
90
    crt_query.query_flags = VG_QUERYFLAG_ACTIVEWIDTH |
 
91
        VG_QUERYFLAG_ACTIVEHEIGHT | VG_QUERYFLAG_BPP | VG_QUERYFLAG_REFRESH;
 
92
 
 
93
    mode = vg_get_display_mode_index(&crt_query);
 
94
    if (mode >= 0) {
 
95
        crt_mode = CimarronDisplayModes[mode];
 
96
        crt_mode.src_width = src_width;
 
97
        crt_mode.src_height = src_height;
 
98
 
 
99
        /* ADD USER-REQUESTED FLAGS */
 
100
 
 
101
        crt_mode.flags |= (flags & VG_MODEFLAG_VALIDUSERFLAGS);
 
102
 
 
103
        if (flags & VG_MODEFLAG_OVERRIDE_BAND) {
 
104
            crt_mode.flags &= ~VG_MODEFLAG_BANDWIDTHMASK;
 
105
            crt_mode.flags |= (flags & VG_MODEFLAG_BANDWIDTHMASK);
 
106
        }
 
107
        if (flags & VG_MODEFLAG_INT_OVERRIDE) {
 
108
            crt_mode.flags &= ~VG_MODEFLAG_INT_MASK;
 
109
            crt_mode.flags |= (flags & VG_MODEFLAG_INT_MASK);
 
110
        }
 
111
 
 
112
        return vg_set_custom_mode(&crt_mode, bpp);
 
113
    }
 
114
    return CIM_STATUS_ERROR;
 
115
}
 
116
 
 
117
/*---------------------------------------------------------------------------
 
118
 * vg_set_panel_mode
 
119
 *
 
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
 *--------------------------------------------------------------------------*/
 
130
 
 
131
int
 
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)
 
136
{
 
137
    unsigned long sync_width;
 
138
    unsigned long sync_offset;
 
139
    VG_QUERY_MODE panel_query;
 
140
    VG_DISPLAY_MODE panel_mode;
 
141
    int mode;
 
142
 
 
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        */
 
152
    /* calculated.                                                         */
 
153
 
 
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;
 
163
 
 
164
    mode = vg_get_display_mode_index(&panel_query);
 
165
 
 
166
    /* COPY THE DATA FROM THE MODE TABLE TO A TEMPORARY STRUCTURE */
 
167
 
 
168
    if (mode >= 0) {
 
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;
 
174
 
 
175
        /* ADD USER-REQUESTED FLAGS */
 
176
 
 
177
        panel_mode.flags |= (flags & VG_MODEFLAG_VALIDUSERFLAGS);
 
178
 
 
179
        if (flags & VG_MODEFLAG_OVERRIDE_BAND) {
 
180
            panel_mode.flags &= ~VG_MODEFLAG_BANDWIDTHMASK;
 
181
            panel_mode.flags |= (flags & VG_MODEFLAG_BANDWIDTHMASK);
 
182
        }
 
183
        if (flags & VG_MODEFLAG_INT_OVERRIDE) {
 
184
            panel_mode.flags &= ~VG_MODEFLAG_INT_MASK;
 
185
            panel_mode.flags |= (flags & VG_MODEFLAG_INT_MASK);
 
186
        }
 
187
 
 
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.                                    */
 
193
 
 
194
        if (dst_width < panel_width) {
 
195
            sync_width = panel_mode.hsyncend - panel_mode.hsyncstart;
 
196
            sync_offset = panel_mode.hsyncstart - panel_mode.hblankstart;
 
197
 
 
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;
 
205
 
 
206
            panel_mode.flags |= VG_MODEFLAG_CENTERED;
 
207
        }
 
208
        if (dst_height < panel_height) {
 
209
            sync_width = panel_mode.vsyncend - panel_mode.vsyncstart;
 
210
            sync_offset = panel_mode.vsyncstart - panel_mode.vblankstart;
 
211
 
 
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;
 
219
 
 
220
            panel_mode.flags |= VG_MODEFLAG_CENTERED;
 
221
        }
 
222
        return vg_set_custom_mode(&panel_mode, bpp);
 
223
    }
 
224
    return CIM_STATUS_ERROR;
 
225
}
 
226
 
 
227
/*---------------------------------------------------------------------------
 
228
 * vg_set_tv_mode
 
229
 *
 
230
 * This routine sets a TV display mode using predefined Cimarron timings.  The
 
231
 * source width and height are specified to allow scaling.
 
232
 *--------------------------------------------------------------------------*/
 
233
 
 
234
int
 
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)
 
239
{
 
240
    unsigned long sync_width;
 
241
    unsigned long sync_offset;
 
242
    VG_QUERY_MODE tv_query;
 
243
    VG_DISPLAY_MODE tv_mode;
 
244
    int mode;
 
245
 
 
246
    if (!src_width || !src_height)
 
247
        return CIM_STATUS_INVALIDPARAMS;
 
248
 
 
249
    tv_query.bpp = bpp;
 
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;
 
254
 
 
255
    mode = vg_get_display_mode_index(&tv_query);
 
256
    if (mode >= 0) {
 
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.
 
261
         */
 
262
 
 
263
        if (!(*src_width) || !(*src_height)) {
 
264
            *src_width = CimarronDisplayModes[mode].hactive - (h_overscan << 1);
 
265
            *src_height = CimarronDisplayModes[mode].vactive;
 
266
 
 
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;
 
278
 
 
279
                    /* ONLY 1/2 THE OVERSCAN FOR LINE DOUBLED MODES */
 
280
 
 
281
                    *src_height -= v_overscan;
 
282
                }
 
283
                else {
 
284
                    *src_height += CimarronDisplayModes[mode].vactive_even;
 
285
                    *src_height -= v_overscan << 1;
 
286
                }
 
287
            }
 
288
            else {
 
289
                *src_height -= v_overscan << 1;
 
290
            }
 
291
 
 
292
            return CIM_STATUS_OK;
 
293
        }
 
294
 
 
295
        tv_mode = CimarronDisplayModes[mode];
 
296
        tv_mode.src_width = *src_width;
 
297
        tv_mode.src_height = *src_height;
 
298
 
 
299
        /* ADD USER-REQUESTED FLAGS */
 
300
 
 
301
        tv_mode.flags |= (flags & VG_MODEFLAG_VALIDUSERFLAGS);
 
302
 
 
303
        if (flags & VG_MODEFLAG_OVERRIDE_BAND) {
 
304
            tv_mode.flags &= ~VG_MODEFLAG_BANDWIDTHMASK;
 
305
            tv_mode.flags |= (flags & VG_MODEFLAG_BANDWIDTHMASK);
 
306
        }
 
307
        if (flags & VG_MODEFLAG_INT_OVERRIDE) {
 
308
            tv_mode.flags &= ~VG_MODEFLAG_INT_MASK;
 
309
            tv_mode.flags |= (flags & VG_MODEFLAG_INT_MASK);
 
310
        }
 
311
 
 
312
        /* ADJUST FOR OVERSCAN */
 
313
 
 
314
        if (h_overscan) {
 
315
            sync_width = tv_mode.hsyncend - tv_mode.hsyncstart;
 
316
            sync_offset = tv_mode.hsyncstart - tv_mode.hblankstart;
 
317
 
 
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;
 
323
 
 
324
            tv_mode.flags |= VG_MODEFLAG_CENTERED;
 
325
        }
 
326
        if (v_overscan) {
 
327
            sync_width = tv_mode.vsyncend - tv_mode.vsyncstart;
 
328
            sync_offset = tv_mode.vsyncstart - tv_mode.vblankstart;
 
329
 
 
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;
 
336
 
 
337
                sync_width = tv_mode.vsyncend_even - tv_mode.vsyncstart_even;
 
338
                sync_offset = tv_mode.vsyncstart_even -
 
339
                    tv_mode.vblankstart_even;
 
340
 
 
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;
 
349
            }
 
350
            else {
 
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;
 
356
            }
 
357
 
 
358
            tv_mode.flags |= VG_MODEFLAG_CENTERED;
 
359
        }
 
360
 
 
361
        /* TV MODES WILL NEVER ALLOW PANNING */
 
362
 
 
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;
 
367
 
 
368
        return vg_set_custom_mode(&tv_mode, bpp);
 
369
    }
 
370
    return CIM_STATUS_ERROR;
 
371
}
 
372
 
 
373
/*---------------------------------------------------------------------------
 
374
 * vg_set_custom_mode
 
375
 *
 
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
 
380
 *   - vg_set_tv_mode
 
381
 *   - directly by the user for a custom mode.
 
382
 *--------------------------------------------------------------------------*/
 
383
 
 
384
int
 
385
vg_set_custom_mode(VG_DISPLAY_MODE * mode_params, int bpp)
 
386
{
 
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;
 
395
    Q_WORD msr_value;
 
396
 
 
397
    /* DETERMINE DIMENSIONS FOR SCALING */
 
398
    /* Scaling is performed before flicker filtering and interlacing */
 
399
 
 
400
    output_height = mode_params->vactive;
 
401
 
 
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
 
405
         * fields
 
406
         */
 
407
 
 
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;
 
413
        }
 
414
 
 
415
        /* LINE DOUBLING
 
416
         * The composite image height is the greater of the two field
 
417
         * heights.
 
418
         */
 
419
 
 
420
        else if (mode_params->vactive_even > output_height)
 
421
            output_height = mode_params->vactive_even;
 
422
    }
 
423
 
 
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.
 
429
     */
 
430
 
 
431
    irq_ctl = 0;
 
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);
 
439
        }
 
440
        else {
 
441
            starting_width = mode_params->hactive;
 
442
            hscale = 0x4000;
 
443
        }
 
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);
 
450
        }
 
451
        else {
 
452
            starting_height = output_height;
 
453
            vscale = 0x4000;
 
454
        }
 
455
    }
 
456
    else {
 
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);
 
463
        }
 
464
        else {
 
465
            hscale = 0x4000;
 
466
        }
 
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);
 
470
        }
 
471
        else {
 
472
            vscale = 0x4000;
 
473
        }
 
474
    }
 
475
 
 
476
    starting_width = (starting_width + 7) & 0xFFFF8;
 
477
 
 
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;
 
482
    }
 
483
 
 
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.               */
 
488
 
 
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;
 
495
        }
 
496
    }
 
497
 
 
498
    /* CHECK FOR VALID BPP */
 
499
 
 
500
    switch (bpp) {
 
501
    case 8:
 
502
        bpp_mask = DC3_DCFG_DISP_MODE_8BPP;
 
503
        break;
 
504
    case 24:
 
505
        bpp_mask = DC3_DCFG_DISP_MODE_24BPP;
 
506
        break;
 
507
    case 32:
 
508
        bpp_mask = DC3_DCFG_DISP_MODE_32BPP;
 
509
        break;
 
510
    case 12:
 
511
        bpp_mask = DC3_DCFG_DISP_MODE_16BPP | DC3_DCFG_12BPP;
 
512
        break;
 
513
    case 15:
 
514
        bpp_mask = DC3_DCFG_DISP_MODE_16BPP | DC3_DCFG_15BPP;
 
515
        break;
 
516
    case 16:
 
517
        bpp_mask = DC3_DCFG_DISP_MODE_16BPP | DC3_DCFG_16BPP;
 
518
        break;
 
519
    default:
 
520
        return CIM_STATUS_INVALIDPARAMS;
 
521
    }
 
522
 
 
523
    vg3_bpp = bpp;
 
524
 
 
525
    /* CLEAR PANNING OFFSETS */
 
526
 
 
527
    vg3_delta_x = 0;
 
528
    vg3_delta_y = 0;
 
529
 
 
530
    /* SAVE PANEL PARAMETERS */
 
531
 
 
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;
 
538
 
 
539
        /* INVERT THE SHIFT CLOCK IF REQUESTED */
 
540
        /* Note that we avoid writing the power management register if */
 
541
        /* we can help it.                                             */
 
542
 
 
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));
 
547
        }
 
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));
 
551
        }
 
552
 
 
553
        /* SET PANEL TIMING VALUES */
 
554
 
 
555
        if (!(mode_params->flags & VG_MODEFLAG_NOPANELTIMINGS)) {
 
556
            unsigned long pmtim1, pmtim2, dith_ctl;
 
557
 
 
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;
 
564
            }
 
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;
 
571
            }
 
572
            else {
 
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;
 
578
 
 
579
            }
 
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);
 
584
        }
 
585
 
 
586
        /* SET APPROPRIATE PANEL OUTPUT MODE */
 
587
 
 
588
        msr_read64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
 
589
 
 
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;
 
594
        else
 
595
            msr_value.low &= ~DF_SIMULTANEOUS_CRT_FP;
 
596
 
 
597
        msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
 
598
 
 
599
    }
 
600
    else if (mode_params->flags & VG_MODEFLAG_TVOUT) {
 
601
        vg3_panel_enable = 0;
 
602
 
 
603
        /* SET APPROPRIATE TV OUTPUT MODE */
 
604
 
 
605
        msr_read64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
 
606
 
 
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;
 
611
        else
 
612
            msr_value.low &= ~DF_SIMULTANEOUS_CRT_FP;
 
613
 
 
614
        msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
 
615
 
 
616
        /* CONFIGURE PADS FOR VOP OUTPUT */
 
617
        /* Note that the VOP clock is currently always inverted. */
 
618
 
 
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);
 
622
    }
 
623
    else {
 
624
        vg3_panel_enable = 0;
 
625
 
 
626
        /* SET OUTPUT TO CRT ONLY */
 
627
 
 
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);
 
632
    }
 
633
 
 
634
    /* SET UNLOCK VALUE */
 
635
 
 
636
    unlock = READ_REG32(DC3_UNLOCK);
 
637
    WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
 
638
 
 
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
    /*-------------------------------------------------------------------*/
 
646
 
 
647
    /* DISABLE VGA
 
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.
 
651
     */
 
652
 
 
653
    temp = READ_REG32(DC3_GENERAL_CFG) & ~DC3_GCFG_VGAE;
 
654
 
 
655
    /* DISABLE VIDEO (INCLUDING ALPHA WINDOWS) */
 
656
 
 
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);
 
660
 
 
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));
 
664
 
 
665
    /* DISABLE VG INTERRUPTS */
 
666
 
 
667
    WRITE_REG32(DC3_IRQ, DC3_IRQ_MASK | DC3_VSYNC_IRQ_MASK |
 
668
                DC3_IRQ_STATUS | DC3_VSYNC_IRQ_STATUS);
 
669
 
 
670
    /* DISABLE GENLOCK */
 
671
 
 
672
    genlk_ctl = READ_REG32(DC3_GENLK_CTL);
 
673
    WRITE_REG32(DC3_GENLK_CTL, (genlk_ctl & ~DC3_GC_GENLOCK_ENABLE));
 
674
 
 
675
    /* DISABLE VIP CAPTURE AND VIP INTERRUPTS */
 
676
 
 
677
    WRITE_VIP32(VIP_CONTROL1, 0);
 
678
    WRITE_VIP32(VIP_CONTROL2, 0);
 
679
    WRITE_VIP32(VIP_INTERRUPT, VIP_ALL_INTERRUPTS | (VIP_ALL_INTERRUPTS >> 16));
 
680
 
 
681
    /* DISABLE COLOR KEYING
 
682
     * The color key mechanism should be disabled whenever a mode switch
 
683
     * occurs.
 
684
     */
 
685
 
 
686
    temp = READ_REG32(DC3_COLOR_KEY);
 
687
    WRITE_REG32(DC3_COLOR_KEY, (temp & ~DC3_CLR_KEY_ENABLE));
 
688
 
 
689
    /* BLANK THE DISPLAY
 
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.
 
694
     */
 
695
 
 
696
    misc = READ_VID32(DF_VID_MISC);
 
697
    config = READ_VID32(DF_DISPLAY_CONFIG);
 
698
 
 
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)));
 
703
 
 
704
    /* DISABLE COMPRESSION  */
 
705
 
 
706
    gcfg = READ_REG32(DC3_GENERAL_CFG);
 
707
    gcfg &= ~(DC3_GCFG_CMPE | DC3_GCFG_DECE);
 
708
    WRITE_REG32(DC3_GENERAL_CFG, gcfg);
 
709
 
 
710
    /* DISABLE THE TIMING GENERATOR */
 
711
 
 
712
    dcfg = READ_REG32(DC3_DISPLAY_CFG);
 
713
    dcfg &= ~DC3_DCFG_TGEN;
 
714
    WRITE_REG32(DC3_DISPLAY_CFG, dcfg);
 
715
 
 
716
    /* WAIT FOR PENDING MEMORY REQUESTS */
 
717
 
 
718
    vg_delay_milliseconds(1);
 
719
 
 
720
    /* DISABLE DISPLAY FIFO LOAD */
 
721
 
 
722
    gcfg &= ~DC3_GCFG_DFLE;
 
723
    WRITE_REG32(DC3_GENERAL_CFG, gcfg);
 
724
    gcfg = 0;
 
725
    dcfg = 0;
 
726
 
 
727
    /* WAIT FOR THE GP TO BE IDLE (JUST IN CASE) */
 
728
 
 
729
    while (((temp = READ_GP32(GP3_BLT_STATUS)) & GP3_BS_BLT_BUSY) ||
 
730
           !(temp & GP3_BS_CB_EMPTY)) {
 
731
        ;
 
732
    }
 
733
 
 
734
    /* SET THE DOT CLOCK FREQUENCY */
 
735
 
 
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;
 
741
        else
 
742
            flags = 0;
 
743
 
 
744
        /* ALLOW DOTREF TO BE USED AS THE PLL            */
 
745
        /* This is useful for some external TV encoders. */
 
746
 
 
747
        if (mode_params->flags & VG_MODEFLAG_PLL_BYPASS)
 
748
            flags |= VG_PLL_BYPASS;
 
749
 
 
750
        /* ALLOW THE USER TO MANUALLY ENTER THE MSR VALUE */
 
751
 
 
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;
 
756
 
 
757
        vg_set_clock_frequency(mode_params->frequency, flags);
 
758
    }
 
759
 
 
760
    /* CLEAR ALL BUFFER OFFSETS */
 
761
 
 
762
    WRITE_REG32(DC3_FB_ST_OFFSET, 0);
 
763
    WRITE_REG32(DC3_CB_ST_OFFSET, 0);
 
764
    WRITE_REG32(DC3_CURS_ST_OFFSET, 0);
 
765
 
 
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);
 
769
 
 
770
    /* ENABLE INTERLACING */
 
771
 
 
772
    if (mode_params->flags & VG_MODEFLAG_INTERLACED) {
 
773
        irq_ctl |= DC3_IRQFILT_INTL_EN;
 
774
 
 
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;
 
782
        }
 
783
    }
 
784
 
 
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);
 
788
 
 
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.
 
794
     */
 
795
 
 
796
    switch (bpp) {
 
797
    case 8:
 
798
        size = mode_params->src_width;
 
799
        line_size = starting_width;
 
800
        break;
 
801
 
 
802
    case 12:
 
803
    case 15:
 
804
    case 16:
 
805
 
 
806
        size = mode_params->src_width << 1;
 
807
        line_size = starting_width << 1;
 
808
        break;
 
809
 
 
810
    case 24:
 
811
    case 32:
 
812
    default:
 
813
 
 
814
        size = mode_params->src_width << 2;
 
815
        line_size = starting_width << 2;
 
816
        break;
 
817
    }
 
818
 
 
819
    /* CALCULATE DV RAM SETTINGS AND POWER OF 2 PITCH */
 
820
 
 
821
    pitch = 1024;
 
822
    dv_size = DC3_DV_LINE_SIZE_1024;
 
823
 
 
824
    if (size > 1024) {
 
825
        pitch = 2048;
 
826
        dv_size = DC3_DV_LINE_SIZE_2048;
 
827
    }
 
828
    if (size > 2048) {
 
829
        pitch = 4096;
 
830
        dv_size = DC3_DV_LINE_SIZE_4096;
 
831
    }
 
832
    if (size > 4096) {
 
833
        pitch = 8192;
 
834
        dv_size = DC3_DV_LINE_SIZE_8192;
 
835
    }
 
836
 
 
837
    /* OVERRIDE SETTINGS FOR LINEAR PITCH */
 
838
 
 
839
    if (mode_params->flags & VG_MODEFLAG_LINEARPITCH) {
 
840
        unsigned long max;
 
841
 
 
842
        if (pitch != size) {
 
843
            /* CALCULATE MAXIMUM ADDRESS (1K ALIGNED) */
 
844
 
 
845
            max = size * output_height;
 
846
            max = (max + 0x3FF) & 0xFFFFFC00;
 
847
            WRITE_REG32(DC3_DV_TOP, max | DC3_DVTOP_ENABLE);
 
848
 
 
849
            gcfg |= DC3_GCFG_FDTY;
 
850
            pitch = size;
 
851
        }
 
852
        else {
 
853
            WRITE_REG32(DC3_DV_TOP, 0);
 
854
        }
 
855
    }
 
856
 
 
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...                                    */
 
861
 
 
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);
 
865
 
 
866
    /* SET THE LINE SIZE */
 
867
 
 
868
    WRITE_REG32(DC3_LINE_SIZE, (line_size + 7) >> 3);
 
869
 
 
870
    /* ALWAYS ENABLE VIDEO AND GRAPHICS DATA            */
 
871
    /* These bits are relics from a previous design and */
 
872
    /* should always be enabled.                        */
 
873
 
 
874
    dcfg |= (DC3_DCFG_VDEN | DC3_DCFG_GDEN);
 
875
 
 
876
    /* SET PIXEL FORMAT */
 
877
 
 
878
    dcfg |= bpp_mask;
 
879
 
 
880
    /* ENABLE TIMING GENERATOR, TIM. REG. UPDATES, PALETTE BYPASS */
 
881
    /* AND VERT. INT. SELECT                                      */
 
882
 
 
883
    dcfg |= (unsigned long) (DC3_DCFG_TGEN | DC3_DCFG_TRUP | DC3_DCFG_PALB |
 
884
                             DC3_DCFG_VISL);
 
885
 
 
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.
 
889
     */
 
890
 
 
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);
 
897
 
 
898
    if ((mode_params->flags & VG_MODEFLAG_BANDWIDTHMASK) ==
 
899
        VG_MODEFLAG_HIGH_BAND || ((mode_params->flags & VG_MODEFLAG_INTERLACED)
 
900
                                  && (mode_params->
 
901
                                      flags & VG_MODEFLAG_INT_MASK) ==
 
902
                                  VG_MODEFLAG_INT_FLICKER) ||
 
903
        (irq_ctl & DC3_IRQFILT_GFX_FILT_EN)) {
 
904
        /* HIGH BANDWIDTH */
 
905
        /* Set agressive watermarks and disallow forced low priority */
 
906
 
 
907
        gcfg |= 0x0000BA01;
 
908
        dcfg |= 0x000EA000;
 
909
        acfg = 0x001A0201;
 
910
 
 
911
        msr_value.low |= DC3_SPARE_DISABLE_CFIFO_HGO |
 
912
            DC3_SPARE_VFIFO_ARB_SELECT | DC3_SPARE_WM_LPEN_OVRD;
 
913
    }
 
914
    else if ((mode_params->flags & VG_MODEFLAG_BANDWIDTHMASK) ==
 
915
             VG_MODEFLAG_AVG_BAND) {
 
916
        /* AVERAGE BANDWIDTH
 
917
         * Set average watermarks and allow small regions of forced low
 
918
         * priority.
 
919
         */
 
920
 
 
921
        gcfg |= 0x0000B601;
 
922
        dcfg |= 0x00009000;
 
923
        acfg = 0x00160001;
 
924
 
 
925
        msr_value.low |= DC3_SPARE_DISABLE_CFIFO_HGO |
 
926
            DC3_SPARE_VFIFO_ARB_SELECT | DC3_SPARE_WM_LPEN_OVRD;
 
927
 
 
928
        /* SET THE NUMBER OF LOW PRIORITY LINES TO 1/2 THE TOTAL AVAILABLE */
 
929
 
 
930
        temp = ((READ_REG32(DC3_V_ACTIVE_TIMING) >> 16) & 0x7FF) + 1;
 
931
        temp -= (READ_REG32(DC3_V_SYNC_TIMING) & 0x7FF) + 1;
 
932
        temp >>= 1;
 
933
        if (temp > 127)
 
934
            temp = 127;
 
935
 
 
936
        acfg |= temp << 9;
 
937
    }
 
938
    else if ((mode_params->flags & VG_MODEFLAG_BANDWIDTHMASK) ==
 
939
             VG_MODEFLAG_LOW_BAND) {
 
940
        /* LOW BANDWIDTH
 
941
         * Set low watermarks and allow larger regions of forced low priority
 
942
         */
 
943
 
 
944
        gcfg |= 0x00009501;
 
945
        dcfg |= 0x00008000;
 
946
        acfg = 0x00150001;
 
947
 
 
948
        msr_value.low |= DC3_SPARE_DISABLE_CFIFO_HGO |
 
949
            DC3_SPARE_VFIFO_ARB_SELECT | DC3_SPARE_WM_LPEN_OVRD;
 
950
 
 
951
        /* SET THE NUMBER OF LOW PRIORITY LINES TO 3/4 THE TOTAL AVAILABLE */
 
952
 
 
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;
 
956
        if (temp > 127)
 
957
            temp = 127;
 
958
 
 
959
        acfg |= temp << 9;
 
960
    }
 
961
    else {
 
962
        /* LEGACY CHARACTERISTICS */
 
963
        /* Arbitration from a single set of watermarks. */
 
964
 
 
965
        gcfg |= 0x0000B601;
 
966
        msr_value.low |= DC3_SPARE_DISABLE_VFIFO_WM |
 
967
            DC3_SPARE_DISABLE_INIT_VID_PRI;
 
968
        acfg = 0;
 
969
    }
 
970
 
 
971
    msr_write64(MSR_DEVICE_GEODELX_VG, DC3_SPARE_MSR, &msr_value);
 
972
 
 
973
    /* ENABLE FLAT PANEL CENTERING                          */
 
974
    /* For panel modes having a resolution smaller than the */
 
975
    /* panel resolution, turn on data centering.            */
 
976
 
 
977
    if (mode_params->flags & VG_MODEFLAG_CENTERED)
 
978
        dcfg |= DC3_DCFG_DCEN;
 
979
 
 
980
    /* COMBINE AND SET TIMING VALUES */
 
981
 
 
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 -
 
997
                                               1) << 16);
 
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);
 
1005
 
 
1006
    /* SET THE VIDEO REQUEST REGISTER */
 
1007
 
 
1008
    WRITE_VID32(DF_VIDEO_REQUEST, 0);
 
1009
 
 
1010
    /* SET SOURCE DIMENSIONS */
 
1011
 
 
1012
    WRITE_REG32(DC3_FB_ACTIVE, ((starting_width - 1) << 16) |
 
1013
                (starting_height - 1));
 
1014
 
 
1015
    /* SET SYNC POLARITIES */
 
1016
 
 
1017
    temp = READ_VID32(DF_DISPLAY_CONFIG);
 
1018
 
 
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);
 
1021
 
 
1022
    temp |= DF_DCFG_CRT_SYNC_SKW_INIT | DF_DCFG_PWR_SEQ_DLY_INIT;
 
1023
 
 
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;
 
1028
 
 
1029
    WRITE_VID32(DF_DISPLAY_CONFIG, temp);
 
1030
 
 
1031
    WRITE_REG32(DC3_DISPLAY_CFG, dcfg);
 
1032
    WRITE_REG32(DC3_ARB_CFG, acfg);
 
1033
    WRITE_REG32(DC3_GENERAL_CFG, gcfg);
 
1034
 
 
1035
    /* RESTORE VALUE OF DC3_UNLOCK */
 
1036
 
 
1037
    WRITE_REG32(DC3_UNLOCK, unlock);
 
1038
 
 
1039
    return CIM_STATUS_OK;
 
1040
}
 
1041
 
 
1042
/*---------------------------------------------------------------------------
 
1043
 * vg_set_bpp
 
1044
 *
 
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
 *--------------------------------------------------------------------------*/
 
1049
 
 
1050
int
 
1051
vg_set_display_bpp(int bpp)
 
1052
{
 
1053
    unsigned long unlock, dcfg, bpp_mask;
 
1054
 
 
1055
    switch (bpp) {
 
1056
    case 8:
 
1057
        bpp_mask = DC3_DCFG_DISP_MODE_8BPP;
 
1058
        break;
 
1059
    case 24:
 
1060
        bpp_mask = DC3_DCFG_DISP_MODE_24BPP;
 
1061
        break;
 
1062
    case 32:
 
1063
        bpp_mask = DC3_DCFG_DISP_MODE_32BPP;
 
1064
        break;
 
1065
    case 12:
 
1066
        bpp_mask = DC3_DCFG_DISP_MODE_16BPP | DC3_DCFG_12BPP;
 
1067
        break;
 
1068
    case 15:
 
1069
        bpp_mask = DC3_DCFG_DISP_MODE_16BPP | DC3_DCFG_15BPP;
 
1070
        break;
 
1071
    case 16:
 
1072
        bpp_mask = DC3_DCFG_DISP_MODE_16BPP | DC3_DCFG_16BPP;
 
1073
        break;
 
1074
    default:
 
1075
        return CIM_STATUS_INVALIDPARAMS;
 
1076
    }
 
1077
 
 
1078
    unlock = READ_REG32(DC3_UNLOCK);
 
1079
    dcfg = READ_REG32(DC3_DISPLAY_CFG) & ~(DC3_DCFG_DISP_MODE_MASK |
 
1080
                                           DC3_DCFG_16BPP_MODE_MASK);
 
1081
    dcfg |= bpp_mask;
 
1082
 
 
1083
    WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
 
1084
    WRITE_REG32(DC3_DISPLAY_CFG, dcfg);
 
1085
    WRITE_REG32(DC3_UNLOCK, unlock);
 
1086
 
 
1087
    return CIM_STATUS_OK;
 
1088
}
 
1089
 
 
1090
/*---------------------------------------------------------------------------
 
1091
 * vg_get_display_mode_index
 
1092
 *
 
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
 *--------------------------------------------------------------------------*/
 
1097
 
 
1098
int
 
1099
vg_get_display_mode_index(VG_QUERY_MODE * query)
 
1100
{
 
1101
    unsigned int mode;
 
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;
 
1109
    long diff;
 
1110
    int match = -1;
 
1111
 
 
1112
    if (!query || !query->query_flags)
 
1113
        return -1;
 
1114
 
 
1115
    if (query->query_flags & VG_QUERYFLAG_REFRESH) {
 
1116
        /* SET FLAGS TO MATCH REFRESH RATE */
 
1117
 
 
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;
 
1134
        else
 
1135
            hz_flag = 0;
 
1136
    }
 
1137
 
 
1138
    if (query->query_flags & VG_QUERYFLAG_BPP) {
 
1139
        /* SET BPP FLAGS TO LIMIT MODE SELECTION */
 
1140
 
 
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;
 
1153
        else
 
1154
            bpp_flag = 0;
 
1155
    }
 
1156
 
 
1157
    if (query->query_flags & VG_QUERYFLAG_ENCODER) {
 
1158
        /* SET ENCODER FLAGS TO LIMIT MODE SELECTION */
 
1159
 
 
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;
 
1168
        else
 
1169
            enc_flag = 0;
 
1170
    }
 
1171
 
 
1172
    if (query->query_flags & VG_QUERYFLAG_TVMODE) {
 
1173
        /* SET ENCODER FLAGS TO LIMIT MODE SELECTION */
 
1174
 
 
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;
 
1197
        else
 
1198
            tv_flag = 0xFFFFFFFF;
 
1199
    }
 
1200
 
 
1201
    /* SET APPROPRIATE TV AND VOP FLAGS */
 
1202
 
 
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;
 
1207
 
 
1208
    /* CHECK FOR INVALID REQUEST */
 
1209
 
 
1210
    if (!hz_flag || !bpp_flag || !enc_flag || tv_flag == 0xFFFFFFFF)
 
1211
        return -1;
 
1212
 
 
1213
    /* LOOP THROUGH THE AVAILABLE MODES TO FIND A MATCH */
 
1214
 
 
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)
 
1223
                == interlaced)
 
1224
            && (!(query->query_flags & VG_QUERYFLAG_HALFCLOCK)
 
1225
                || (CimarronDisplayModes[mode].flags & VG_MODEFLAG_HALFCLOCK) ==
 
1226
                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)
 
1248
                ||
 
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 */
 
1254
 
 
1255
            if (query->query_flags & VG_QUERYFLAG_PIXELCLOCK_APPROX) {
 
1256
                diff = query->frequency - CimarronDisplayModes[mode].frequency;
 
1257
                if (diff < 0)
 
1258
                    diff = -diff;
 
1259
 
 
1260
                if (diff < minimum) {
 
1261
                    minimum = diff;
 
1262
                    match = mode;
 
1263
                }
 
1264
            }
 
1265
            else {
 
1266
                match = mode;
 
1267
                break;
 
1268
            }
 
1269
        }
 
1270
    }
 
1271
 
 
1272
    /* RETURN DISPLAY MODE INDEX */
 
1273
 
 
1274
    return match;
 
1275
}
 
1276
 
 
1277
/*---------------------------------------------------------------------------
 
1278
 * vg_get_display_mode_information
 
1279
 *
 
1280
 * This routine retrieves all information for a display mode contained
 
1281
 * within Cimarron's mode tables.
 
1282
 *--------------------------------------------------------------------------*/
 
1283
 
 
1284
int
 
1285
vg_get_display_mode_information(unsigned int index, VG_DISPLAY_MODE * vg_mode)
 
1286
{
 
1287
    if (index > NUM_CIMARRON_DISPLAY_MODES)
 
1288
        return CIM_STATUS_INVALIDPARAMS;
 
1289
 
 
1290
    *vg_mode = CimarronDisplayModes[index];
 
1291
    return CIM_STATUS_OK;
 
1292
}
 
1293
 
 
1294
/*---------------------------------------------------------------------------
 
1295
 * vg_get_display_mode_count
 
1296
 *
 
1297
 * This routine retrieves the count of all predefined Cimarron modes.
 
1298
 *--------------------------------------------------------------------------*/
 
1299
 
 
1300
int
 
1301
vg_get_display_mode_count(void)
 
1302
{
 
1303
    return NUM_CIMARRON_DISPLAY_MODES;
 
1304
}
 
1305
 
 
1306
/*---------------------------------------------------------------------------
 
1307
 * vg_get_current_display_mode
 
1308
 *
 
1309
 * This routine retrieves the settings for the current display.  This includes
 
1310
 * any panel settings.
 
1311
 *--------------------------------------------------------------------------*/
 
1312
 
 
1313
int
 
1314
vg_get_current_display_mode(VG_DISPLAY_MODE * current_display, int *bpp)
 
1315
{
 
1316
    Q_WORD msr_value;
 
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;
 
1322
 
 
1323
    /* READ THE CURRENT HORIZONTAL DISPLAY TIMINGS */
 
1324
 
 
1325
    active = READ_REG32(DC3_H_ACTIVE_TIMING);
 
1326
    blank = READ_REG32(DC3_H_BLANK_TIMING);
 
1327
    sync = READ_REG32(DC3_H_SYNC_TIMING);
 
1328
 
 
1329
    current_display->hactive = (active & 0xFFF) + 1;
 
1330
    current_display->hblankstart = (blank & 0xFFF) + 1;
 
1331
    current_display->hsyncstart = (sync & 0xFFF) + 1;
 
1332
 
 
1333
    current_display->htotal = ((active >> 16) & 0xFFF) + 1;
 
1334
    current_display->hblankend = ((blank >> 16) & 0xFFF) + 1;
 
1335
    current_display->hsyncend = ((sync >> 16) & 0xFFF) + 1;
 
1336
 
 
1337
    /* READ THE CURRENT VERTICAL DISPLAY TIMINGS */
 
1338
 
 
1339
    active = READ_REG32(DC3_V_ACTIVE_TIMING);
 
1340
    blank = READ_REG32(DC3_V_BLANK_TIMING);
 
1341
    sync = READ_REG32(DC3_V_SYNC_TIMING);
 
1342
 
 
1343
    current_display->vactive = (active & 0x7FF) + 1;
 
1344
    current_display->vblankstart = (blank & 0x7FF) + 1;
 
1345
    current_display->vsyncstart = (sync & 0x7FF) + 1;
 
1346
 
 
1347
    current_display->vtotal = ((active >> 16) & 0x7FF) + 1;
 
1348
    current_display->vblankend = ((blank >> 16) & 0x7FF) + 1;
 
1349
    current_display->vsyncend = ((sync >> 16) & 0x7FF) + 1;
 
1350
 
 
1351
    /* READ THE CURRENT EVEN FIELD VERTICAL DISPLAY TIMINGS */
 
1352
 
 
1353
    active = READ_REG32(DC3_V_ACTIVE_EVEN);
 
1354
    blank = READ_REG32(DC3_V_BLANK_EVEN);
 
1355
    sync = READ_REG32(DC3_V_SYNC_EVEN);
 
1356
 
 
1357
    current_display->vactive_even = (active & 0x7FF) + 1;
 
1358
    current_display->vblankstart_even = (blank & 0x7FF) + 1;
 
1359
    current_display->vsyncstart_even = (sync & 0x7FF) + 1;
 
1360
 
 
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;
 
1364
 
 
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.                     */
 
1370
 
 
1371
    genlk = READ_REG32(DC3_GENLK_CTL);
 
1372
    irq = READ_REG32(DC3_IRQ_FILT_CTL);
 
1373
    temp = READ_REG32(DC3_FB_ACTIVE);
 
1374
 
 
1375
    current_display->src_height = (temp & 0xFFFF) + 1;
 
1376
    current_display->src_width = ((temp >> 16) & 0xFFF8) + 8;
 
1377
 
 
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.          */
 
1383
 
 
1384
    if (vg3_panel_enable) {
 
1385
        Q_WORD msr_value;
 
1386
 
 
1387
        flags |= VG_MODEFLAG_PANELOUT;
 
1388
 
 
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;
 
1393
 
 
1394
        if (READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_DCEN)
 
1395
            flags |= VG_MODEFLAG_CENTERED;
 
1396
 
 
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;
 
1403
    }
 
1404
 
 
1405
    /* SET MISCELLANEOUS MODE FLAGS */
 
1406
 
 
1407
    /* INTERLACED */
 
1408
 
 
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;
 
1415
        else
 
1416
            flags |= VG_MODEFLAG_INT_LINEDOUBLE;
 
1417
    }
 
1418
 
 
1419
    /* POLARITIES */
 
1420
 
 
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;
 
1426
 
 
1427
    /* BPP */
 
1428
 
 
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;
 
1432
        *bpp = 8;
 
1433
    }
 
1434
    else if (temp == DC3_DCFG_DISP_MODE_24BPP) {
 
1435
        iflags |= VG_SUPPORTFLAG_24BPP;
 
1436
        *bpp = 24;
 
1437
    }
 
1438
    else if (temp == DC3_DCFG_DISP_MODE_32BPP) {
 
1439
        iflags |= VG_SUPPORTFLAG_32BPP;
 
1440
        *bpp = 32;
 
1441
    }
 
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;
 
1446
            *bpp = 16;
 
1447
        }
 
1448
        else if (temp == DC3_DCFG_15BPP) {
 
1449
            iflags |= VG_SUPPORTFLAG_15BPP;
 
1450
            *bpp = 15;
 
1451
        }
 
1452
        else if (temp == DC3_DCFG_12BPP) {
 
1453
            iflags |= VG_SUPPORTFLAG_12BPP;
 
1454
            *bpp = 12;
 
1455
        }
 
1456
    }
 
1457
 
 
1458
    /* TV RELATED FLAGS */
 
1459
 
 
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;
 
1463
 
 
1464
    /* LINEAR PITCH */
 
1465
 
 
1466
    temp = (READ_REG32(DC3_GFX_PITCH) & 0x0000FFFF) << 3;
 
1467
    if (temp != 1024 && temp != 2048 && temp != 4096 && temp != 8192)
 
1468
        flags |= VG_MODEFLAG_LINEARPITCH;
 
1469
 
 
1470
    /* SIMULTANEOUS CRT/FP */
 
1471
 
 
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;
 
1475
 
 
1476
    /* SET PLL-RELATED FLAGS */
 
1477
 
 
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;
 
1483
 
 
1484
    /* SAVE THE FLAGS IN THE MODE STRUCTURE */
 
1485
 
 
1486
    current_display->internal_flags = iflags;
 
1487
    current_display->flags = flags;
 
1488
 
 
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. */
 
1492
 
 
1493
    for (i = 0; i < NUM_CIMARRON_PLL_FREQUENCIES; i++) {
 
1494
        if (CimarronPLLFrequencies[i].pll_value == msr_value.high)
 
1495
            break;
 
1496
    }
 
1497
 
 
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:       */
 
1502
        /*                             n + 1                               */
 
1503
        /*   Fout =  48.000   *    --------------                          */
 
1504
        /*                         m + 1   *  p + 1                        */
 
1505
 
 
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));
 
1510
 
 
1511
        return CIM_STATUS_INEXACTMATCH;
 
1512
    }
 
1513
 
 
1514
    current_display->frequency = CimarronPLLFrequencies[i].frequency;
 
1515
 
 
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.                    */
 
1520
 
 
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) {
 
1545
            break;
 
1546
        }
 
1547
    }
 
1548
 
 
1549
    if (i == NUM_CIMARRON_DISPLAY_MODES)
 
1550
        return CIM_STATUS_INEXACTMATCH;
 
1551
 
 
1552
    current_display->internal_flags |=
 
1553
        (CimarronDisplayModes[i].internal_flags & VG_SUPPORTFLAG_HZMASK);
 
1554
    return CIM_STATUS_OK;
 
1555
}
 
1556
 
 
1557
/*---------------------------------------------------------------------------
 
1558
 * vg_set_scaler_filter_coefficients
 
1559
 *
 
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
 *--------------------------------------------------------------------------*/
 
1564
 
 
1565
int
 
1566
vg_set_scaler_filter_coefficients(long h_taps[][5], long v_taps[][3])
 
1567
{
 
1568
    unsigned long irqfilt, i;
 
1569
    unsigned long temp0, temp1;
 
1570
    unsigned long lock;
 
1571
 
 
1572
    /* ENABLE ACCESS TO THE HORIZONTAL COEFFICIENTS */
 
1573
 
 
1574
    irqfilt = READ_REG32(DC3_IRQ_FILT_CTL);
 
1575
    irqfilt |= DC3_IRQFILT_H_FILT_SEL;
 
1576
 
 
1577
    /* UNLOCK THE COEFFICIENT REGISTERS */
 
1578
 
 
1579
    lock = READ_REG32(DC3_UNLOCK);
 
1580
    WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
 
1581
 
 
1582
    /* WRITE COEFFICIENTS */
 
1583
    /* Coefficient indexes do not auto-increment, so we must */
 
1584
    /* write the address for every phase                     */
 
1585
 
 
1586
    for (i = 0; i < 256; i++) {
 
1587
        WRITE_REG32(DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
 
1588
 
 
1589
        if (!h_taps) {
 
1590
            temp0 = CimarronHorizontalGraphicsFilter[i][0];
 
1591
            temp1 = CimarronHorizontalGraphicsFilter[i][1];
 
1592
        }
 
1593
        else {
 
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);
 
1597
 
 
1598
            temp1 = ((unsigned long) h_taps[i][3] & 0x3FF) |
 
1599
                (((unsigned long) h_taps[i][4] & 0x3FF) << 10);
 
1600
        }
 
1601
        WRITE_REG32(DC3_FILT_COEFF1, temp0);
 
1602
        WRITE_REG32(DC3_FILT_COEFF2, temp1);
 
1603
    }
 
1604
 
 
1605
    /* ENABLE ACCESS TO THE VERTICAL COEFFICIENTS */
 
1606
 
 
1607
    irqfilt &= ~DC3_IRQFILT_H_FILT_SEL;
 
1608
 
 
1609
    /* WRITE COEFFICIENTS */
 
1610
 
 
1611
    for (i = 0; i < 256; i++) {
 
1612
        WRITE_REG32(DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
 
1613
 
 
1614
        if (!v_taps) {
 
1615
            temp0 = CimarronVerticalGraphicsFilter[i];
 
1616
        }
 
1617
        else {
 
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);
 
1621
        }
 
1622
 
 
1623
        WRITE_REG32(DC3_FILT_COEFF1, temp0);
 
1624
    }
 
1625
 
 
1626
    WRITE_REG32(DC3_UNLOCK, lock);
 
1627
 
 
1628
    return CIM_STATUS_OK;
 
1629
}
 
1630
 
 
1631
/*---------------------------------------------------------------------------
 
1632
 * vg_configure_flicker_filter
 
1633
 *
 
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
 
1637
 * 1/4, 1/2, 1/4.
 
1638
 *--------------------------------------------------------------------------*/
 
1639
 
 
1640
int
 
1641
vg_configure_flicker_filter(unsigned long flicker_strength, int flicker_alpha)
 
1642
{
 
1643
    unsigned long unlock;
 
1644
    unsigned long genlk_ctl;
 
1645
 
 
1646
    /* CHECK FOR VALID FLICKER SETTING */
 
1647
 
 
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;
 
1654
    }
 
1655
 
 
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;
 
1660
    if (flicker_alpha)
 
1661
        genlk_ctl |= DC3_GC_ALPHA_FLICK_ENABLE;
 
1662
 
 
1663
    WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
 
1664
    WRITE_REG32(DC3_GENLK_CTL, genlk_ctl);
 
1665
    WRITE_REG32(DC3_UNLOCK, unlock);
 
1666
 
 
1667
    return CIM_STATUS_OK;
 
1668
}
 
1669
 
 
1670
/*---------------------------------------------------------------------------
 
1671
 * vg_set_clock_frequency
 
1672
 *
 
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
 *--------------------------------------------------------------------------*/
 
1678
 
 
1679
int
 
1680
vg_set_clock_frequency(unsigned long frequency, unsigned long pll_flags)
 
1681
{
 
1682
    Q_WORD msr_value;
 
1683
    unsigned long timeout;
 
1684
    unsigned long index = 0;
 
1685
    unsigned long unlock, i;
 
1686
    unsigned long pll_high, pll_low;
 
1687
    long diff, min = 0;
 
1688
 
 
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.                                             */
 
1693
 
 
1694
    pll_low = 0;
 
1695
    if (!(pll_flags & VG_PLL_MANUAL)) {
 
1696
        min = (long) CimarronPLLFrequencies[0].frequency - (long) frequency;
 
1697
        if (min < 0L)
 
1698
            min = -min;
 
1699
 
 
1700
        for (i = 1; i < NUM_CIMARRON_PLL_FREQUENCIES; i++) {
 
1701
            diff = (long) CimarronPLLFrequencies[i].frequency -
 
1702
                (long) frequency;
 
1703
            if (diff < 0L)
 
1704
                diff = -diff;
 
1705
 
 
1706
            if (diff < min) {
 
1707
                min = diff;
 
1708
                index = i;
 
1709
            }
 
1710
        }
 
1711
 
 
1712
        pll_high = CimarronPLLFrequencies[index].pll_value & 0x00007FFF;
 
1713
    }
 
1714
    else {
 
1715
        pll_high = frequency;
 
1716
    }
 
1717
 
 
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;
 
1726
 
 
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.                                        */
 
1731
 
 
1732
    msr_read64(MSR_DEVICE_GEODELX_GLCP, GLCP_DOTPLL, &msr_value);
 
1733
 
 
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;
 
1738
    }
 
1739
 
 
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.                  */
 
1743
 
 
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);
 
1748
 
 
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.      */
 
1754
 
 
1755
    unlock = READ_REG32(DC3_UNLOCK);
 
1756
    for (timeout = 0; timeout < 1280; timeout++)
 
1757
        WRITE_REG32(DC3_UNLOCK, unlock);
 
1758
 
 
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)
 
1762
            break;
 
1763
    }
 
1764
 
 
1765
    /* CLEAR THE RESET BIT */
 
1766
 
 
1767
    msr_value.low &= 0xFFFFFFFE;
 
1768
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DOTPLL, &msr_value);
 
1769
 
 
1770
    /* DID THE PLL SUCCESSFULLY LOCK? */
 
1771
 
 
1772
    if (!(msr_value.low & GLCP_DOTPLL_LOCK))
 
1773
        return CIM_STATUS_NOLOCK;
 
1774
 
 
1775
    /* RETURN THE APPROPRIATE CODE */
 
1776
 
 
1777
    if (min == 0)
 
1778
        return CIM_STATUS_OK;
 
1779
    else
 
1780
        return CIM_STATUS_INEXACTMATCH;
 
1781
}
 
1782
 
 
1783
/*---------------------------------------------------------------------------
 
1784
 * vg_set_border_color
 
1785
 *
 
1786
 * This routine sets the color used as the border in centered panel modes.
 
1787
 *--------------------------------------------------------------------------*/
 
1788
 
 
1789
int
 
1790
vg_set_border_color(unsigned long border_color)
 
1791
{
 
1792
    unsigned long lock = READ_REG32(DC3_UNLOCK);
 
1793
 
 
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);
 
1798
 
 
1799
    return CIM_STATUS_OK;
 
1800
}
 
1801
 
 
1802
/*---------------------------------------------------------------------------
 
1803
 * vg_set_cursor_enable
 
1804
 *
 
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
 *--------------------------------------------------------------------------*/
 
1808
 
 
1809
int
 
1810
vg_set_cursor_enable(int enable)
 
1811
{
 
1812
    unsigned long unlock, gcfg;
 
1813
 
 
1814
    /* SET OR CLEAR CURSOR ENABLE BIT */
 
1815
 
 
1816
    unlock = READ_REG32(DC3_UNLOCK);
 
1817
    gcfg = READ_REG32(DC3_GENERAL_CFG);
 
1818
    if (enable)
 
1819
        gcfg |= DC3_GCFG_CURE;
 
1820
    else
 
1821
        gcfg &= ~(DC3_GCFG_CURE);
 
1822
 
 
1823
    /* WRITE NEW REGISTER VALUE */
 
1824
 
 
1825
    WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
 
1826
    WRITE_REG32(DC3_GENERAL_CFG, gcfg);
 
1827
    WRITE_REG32(DC3_UNLOCK, unlock);
 
1828
 
 
1829
    return CIM_STATUS_OK;
 
1830
}
 
1831
 
 
1832
/*---------------------------------------------------------------------------
 
1833
 * vg_set_mono_cursor_colors
 
1834
 *
 
1835
 * This routine sets the colors of the hardware monochrome cursor.
 
1836
 *--------------------------------------------------------------------------*/
 
1837
 
 
1838
int
 
1839
vg_set_mono_cursor_colors(unsigned long bkcolor, unsigned long fgcolor)
 
1840
{
 
1841
    unsigned long lock = READ_REG32(DC3_UNLOCK);
 
1842
 
 
1843
    /* SET CURSOR COLORS */
 
1844
 
 
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);
 
1850
 
 
1851
    return CIM_STATUS_OK;
 
1852
}
 
1853
 
 
1854
/*---------------------------------------------------------------------------
 
1855
 * vg_set_cursor_position
 
1856
 *
 
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
 *--------------------------------------------------------------------------*/
 
1864
 
 
1865
int
 
1866
vg_set_cursor_position(long xpos, long ypos, VG_PANNING_COORDINATES * panning)
 
1867
{
 
1868
    unsigned long unlock, memoffset;
 
1869
    unsigned long gcfg;
 
1870
    long x, xoffset;
 
1871
    long y, yoffset;
 
1872
 
 
1873
    memoffset = vg3_cursor_offset;
 
1874
    x = xpos - (long) vg3_x_hotspot;
 
1875
    y = ypos - (long) vg3_y_hotspot;
 
1876
 
 
1877
    /* HANDLE NEGATIVE COORDINATES                                      */
 
1878
    /* This routine supports operating systems that use negative        */
 
1879
    /* coordinates, instead of positive coordinates with an appropriate */
 
1880
    /* hotspot.                                                         */
 
1881
 
 
1882
    if (xpos < 0)
 
1883
        xpos = 0;
 
1884
    if (ypos < 0)
 
1885
        ypos = 0;
 
1886
 
 
1887
    if (x < -63)
 
1888
        return CIM_STATUS_INVALIDPARAMS;
 
1889
    if (y < -63)
 
1890
        return CIM_STATUS_INVALIDPARAMS;
 
1891
 
 
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;
 
1898
        }
 
1899
        else {
 
1900
            panning->start_x = 0;
 
1901
            panning->start_y = 0;
 
1902
            panning->start_updated = 0;
 
1903
        }
 
1904
    }
 
1905
 
 
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.                                                 */
 
1911
 
 
1912
    if (x < 0) {
 
1913
        xoffset = -x;
 
1914
        x = 0;
 
1915
    }
 
1916
    else {
 
1917
        xoffset = 0;
 
1918
    }
 
1919
    if (y < 0) {
 
1920
        yoffset = -y;
 
1921
        y = 0;
 
1922
    }
 
1923
    else {
 
1924
        yoffset = 0;
 
1925
    }
 
1926
 
 
1927
    if (vg3_color_cursor)
 
1928
        memoffset += (unsigned long) yoffset *192;
 
1929
 
 
1930
    else
 
1931
        memoffset += (unsigned long) yoffset << 4;
 
1932
 
 
1933
    /* SET COLOR CURSOR BIT */
 
1934
 
 
1935
    gcfg = READ_REG32(DC3_GENERAL_CFG);
 
1936
    if (vg3_color_cursor)
 
1937
        gcfg |= DC3_GCFG_CLR_CUR;
 
1938
    else
 
1939
        gcfg &= ~DC3_GCFG_CLR_CUR;
 
1940
 
 
1941
    /* SET CURSOR POSITION */
 
1942
 
 
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);
 
1952
 
 
1953
    return CIM_STATUS_OK;
 
1954
}
 
1955
 
 
1956
/*---------------------------------------------------------------------------
 
1957
 * vg_set_mono_cursor_shape32
 
1958
 *
 
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
 
1961
 * transparency.
 
1962
 *--------------------------------------------------------------------------*/
 
1963
 
 
1964
int
 
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)
 
1968
{
 
1969
    int i;
 
1970
 
 
1971
    /* SAVE THE CURSOR OFFSET AND HOTSPOTS                               */
 
1972
    /* These are reused later when updating the cursor position, panning */
 
1973
    /* and clipping the cursor pointer.                                  */
 
1974
 
 
1975
    vg3_x_hotspot = x_hotspot;
 
1976
    vg3_y_hotspot = y_hotspot;
 
1977
    vg3_cursor_offset = memoffset;
 
1978
    vg3_color_cursor = 0;
 
1979
 
 
1980
    for (i = 0; i < 32; i++) {
 
1981
        /* EVEN QWORDS CONTAIN THE AND MASK */
 
1982
 
 
1983
        WRITE_FB32(memoffset, 0xFFFFFFFF);
 
1984
        WRITE_FB32(memoffset + 4, andmask[i]);
 
1985
 
 
1986
        /* ODD QWORDS CONTAIN THE XOR MASK  */
 
1987
 
 
1988
        WRITE_FB32(memoffset + 8, 0x00000000);
 
1989
        WRITE_FB32(memoffset + 12, xormask[i]);
 
1990
 
 
1991
        memoffset += 16;
 
1992
    }
 
1993
 
 
1994
    /* FILL THE LOWER HALF OF THE BUFFER WITH TRANSPARENT PIXELS */
 
1995
 
 
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);
 
2001
 
 
2002
        memoffset += 16;
 
2003
    }
 
2004
 
 
2005
    return CIM_STATUS_OK;
 
2006
}
 
2007
 
 
2008
/*---------------------------------------------------------------------------
 
2009
 * vg_set_mono_cursor_shape64
 
2010
 *
 
2011
 * This routine loads 64x64 cursor data into the cursor buffer in graphics
 
2012
 * memory.
 
2013
 *--------------------------------------------------------------------------*/
 
2014
 
 
2015
int
 
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)
 
2019
{
 
2020
    int i;
 
2021
 
 
2022
    /* SAVE THE CURSOR OFFSET AND HOTSPOTS                               */
 
2023
    /* These are reused later when updating the cursor position, panning */
 
2024
    /* and clipping the cursor pointer.                                  */
 
2025
 
 
2026
    vg3_x_hotspot = x_hotspot;
 
2027
    vg3_y_hotspot = y_hotspot;
 
2028
    vg3_cursor_offset = memoffset;
 
2029
    vg3_color_cursor = 0;
 
2030
 
 
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.  */
 
2037
 
 
2038
        WRITE_FB32(memoffset, andmask[i + 1]);
 
2039
        WRITE_FB32(memoffset + 4, andmask[i]);
 
2040
 
 
2041
        /* ODD QWORDS CONTAIN THE XOR MASK  */
 
2042
 
 
2043
        WRITE_FB32(memoffset + 8, xormask[i + 1]);
 
2044
        WRITE_FB32(memoffset + 12, xormask[i]);
 
2045
 
 
2046
        memoffset += 16;
 
2047
    }
 
2048
 
 
2049
    return CIM_STATUS_OK;
 
2050
}
 
2051
 
 
2052
/*---------------------------------------------------------------------------
 
2053
 * vg_set_color_cursor_shape
 
2054
 *
 
2055
 * This routine loads 8:8:8:8 cursor data into the color cursor buffer.
 
2056
 *--------------------------------------------------------------------------*/
 
2057
 
 
2058
int
 
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)
 
2062
{
 
2063
    unsigned long y;
 
2064
 
 
2065
    /* SAVE THE CURSOR OFFSET AND HOTSPOTS                               */
 
2066
    /* These are reused later when updating the cursor position, panning */
 
2067
    /* and clipping the cursor pointer.                                  */
 
2068
 
 
2069
    vg3_x_hotspot = x_hotspot;
 
2070
    vg3_y_hotspot = y_hotspot;
 
2071
    vg3_cursor_offset = memoffset;
 
2072
    vg3_color_cursor = 1;
 
2073
 
 
2074
    /* WRITE THE CURSOR DATA */
 
2075
    /* The outside edges of the color cursor are filled with transparency */
 
2076
    /* The cursor buffer dimensions are 48x64.                            */
 
2077
 
 
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...               */
 
2082
 
 
2083
        WRITE_FB_STRING32(memoffset, data, width);
 
2084
        WRITE_FB_CONSTANT((memoffset + (width << 2)), 0, (48 - width));
 
2085
 
 
2086
        /* INCREMENT PAST THE LINE */
 
2087
 
 
2088
        memoffset += 192;
 
2089
        data += pitch;
 
2090
    }
 
2091
 
 
2092
    /* WRITE THE EXTRA TRANSPARENT LINES */
 
2093
    /* Write the lines in one big bulk setting. */
 
2094
 
 
2095
    WRITE_FB_CONSTANT(memoffset, 0, ((64 - height) * 48));
 
2096
 
 
2097
    return CIM_STATUS_OK;
 
2098
}
 
2099
 
 
2100
/*---------------------------------------------------------------------------
 
2101
 * vg_pan_desktop
 
2102
 *
 
2103
 * This routine sets the correct display offset based on the current cursor
 
2104
 * position.
 
2105
 *--------------------------------------------------------------------------*/
 
2106
 
 
2107
int
 
2108
vg_pan_desktop(unsigned long x, unsigned long y,
 
2109
               VG_PANNING_COORDINATES * panning)
 
2110
{
 
2111
    unsigned long modeShiftPerPixel;
 
2112
    unsigned long modeBytesPerScanline;
 
2113
    unsigned long startAddress;
 
2114
 
 
2115
    /* TEST FOR NO-WORK */
 
2116
 
 
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;
 
2123
    }
 
2124
 
 
2125
    if (vg3_bpp == 24)
 
2126
        modeShiftPerPixel = 2;
 
2127
    else
 
2128
        modeShiftPerPixel = (vg3_bpp + 7) >> 4;
 
2129
 
 
2130
    modeBytesPerScanline = (READ_REG32(DC3_GFX_PITCH) & 0x0000FFFF) << 3;
 
2131
 
 
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.          */
 
2135
 
 
2136
    if (x < vg3_delta_x)
 
2137
        vg3_delta_x = x;
 
2138
    else if (x >= (vg3_delta_x + vg3_panel_width))
 
2139
        vg3_delta_x = x - vg3_panel_width + 1;
 
2140
 
 
2141
    if (y < vg3_delta_y)
 
2142
        vg3_delta_y = y;
 
2143
    else if (y >= (vg3_delta_y + vg3_panel_height))
 
2144
        vg3_delta_y = y - vg3_panel_height + 1;
 
2145
 
 
2146
    /* CALCULATE THE START OFFSET */
 
2147
 
 
2148
    startAddress = (vg3_delta_x << modeShiftPerPixel) +
 
2149
        (vg3_delta_y * modeBytesPerScanline);
 
2150
 
 
2151
    vg_set_display_offset(startAddress);
 
2152
 
 
2153
    panning->start_updated = 1;
 
2154
    panning->start_x = vg3_delta_x;
 
2155
    panning->start_y = vg3_delta_y;
 
2156
    return CIM_STATUS_OK;
 
2157
}
 
2158
 
 
2159
/*---------------------------------------------------------------------------
 
2160
 * vg_set_display_offset
 
2161
 *
 
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
 *--------------------------------------------------------------------------*/
 
2166
 
 
2167
int
 
2168
vg_set_display_offset(unsigned long address)
 
2169
{
 
2170
    unsigned long lock, gcfg;
 
2171
 
 
2172
    lock = READ_REG32(DC3_UNLOCK);
 
2173
    WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
 
2174
 
 
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.                       */
 
2185
 
 
2186
    if (address != 0) {
 
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)));
 
2191
        }
 
2192
    }
 
2193
 
 
2194
    WRITE_REG32(DC3_FB_ST_OFFSET, address);
 
2195
    WRITE_REG32(DC3_UNLOCK, lock);
 
2196
 
 
2197
    return CIM_STATUS_OK;
 
2198
}
 
2199
 
 
2200
/*---------------------------------------------------------------------------
 
2201
 * vg_set_display_pitch
 
2202
 *
 
2203
 * This routine sets the stride between successive lines of data in the frame
 
2204
 * buffer.
 
2205
 *--------------------------------------------------------------------------*/
 
2206
 
 
2207
int
 
2208
vg_set_display_pitch(unsigned long pitch)
 
2209
{
 
2210
    unsigned long temp, dvsize, dvtop, value;
 
2211
    unsigned long lock = READ_REG32(DC3_UNLOCK);
 
2212
 
 
2213
    value = READ_REG32(DC3_GFX_PITCH) & 0xFFFF0000;
 
2214
    value |= (pitch >> 3);
 
2215
 
 
2216
    /* PROGRAM THE DISPLAY PITCH */
 
2217
 
 
2218
    WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
 
2219
    WRITE_REG32(DC3_GFX_PITCH, value);
 
2220
 
 
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.                */
 
2228
 
 
2229
    if (pitch > 4096) {
 
2230
        dvsize = DC3_DV_LINE_SIZE_8192;
 
2231
    }
 
2232
    else if (pitch > 2048) {
 
2233
        dvsize = DC3_DV_LINE_SIZE_4096;
 
2234
    }
 
2235
    else if (pitch > 1024) {
 
2236
        dvsize = DC3_DV_LINE_SIZE_2048;
 
2237
    }
 
2238
    else {
 
2239
        dvsize = DC3_DV_LINE_SIZE_1024;
 
2240
    }
 
2241
 
 
2242
    temp = READ_REG32(DC3_DV_CTL);
 
2243
    WRITE_REG32(DC3_DV_CTL,
 
2244
                (temp & ~DC3_DV_LINE_SIZE_MASK) | dvsize | 0x00000001);
 
2245
 
 
2246
    value = READ_REG32(DC3_GENERAL_CFG);
 
2247
 
 
2248
    if (pitch == 1024 || pitch == 2048 || pitch == 4096 || pitch == 8192) {
 
2249
        value &= ~DC3_GCFG_FDTY;
 
2250
        dvtop = 0;
 
2251
    }
 
2252
    else {
 
2253
        value |= DC3_GCFG_FDTY;
 
2254
 
 
2255
        dvtop = (READ_REG32(DC3_FB_ACTIVE) & 0xFFF) + 1;
 
2256
        dvtop = ((dvtop * pitch) + 0x3FF) & 0xFFFFFC00;
 
2257
        dvtop |= DC3_DVTOP_ENABLE;
 
2258
    }
 
2259
 
 
2260
    WRITE_REG32(DC3_GENERAL_CFG, value);
 
2261
    WRITE_REG32(DC3_DV_TOP, dvtop);
 
2262
    WRITE_REG32(DC3_UNLOCK, lock);
 
2263
 
 
2264
    return CIM_STATUS_OK;
 
2265
}
 
2266
 
 
2267
/*---------------------------------------------------------------------------
 
2268
 * vg_set_display_palette_entry
 
2269
 *
 
2270
 * This routine sets a single 8BPP palette entry in the display controller.
 
2271
 *--------------------------------------------------------------------------*/
 
2272
 
 
2273
int
 
2274
vg_set_display_palette_entry(unsigned long index, unsigned long palette)
 
2275
{
 
2276
    unsigned long dcfg, unlock;
 
2277
 
 
2278
    if (index > 0xFF)
 
2279
        return CIM_STATUS_INVALIDPARAMS;
 
2280
 
 
2281
    unlock = READ_REG32(DC3_UNLOCK);
 
2282
    dcfg = READ_REG32(DC3_DISPLAY_CFG);
 
2283
 
 
2284
    WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
 
2285
    WRITE_REG32(DC3_DISPLAY_CFG, dcfg & ~DC3_DCFG_PALB);
 
2286
    WRITE_REG32(DC3_UNLOCK, unlock);
 
2287
 
 
2288
    WRITE_REG32(DC3_PAL_ADDRESS, index);
 
2289
    WRITE_REG32(DC3_PAL_DATA, palette);
 
2290
 
 
2291
    return CIM_STATUS_OK;
 
2292
}
 
2293
 
 
2294
/*---------------------------------------------------------------------------
 
2295
 * vg_set_display_palette
 
2296
 *
 
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
 *--------------------------------------------------------------------------*/
 
2300
 
 
2301
int
 
2302
vg_set_display_palette(unsigned long *palette)
 
2303
{
 
2304
    unsigned long unlock, dcfg, i;
 
2305
 
 
2306
    WRITE_REG32(DC3_PAL_ADDRESS, 0);
 
2307
 
 
2308
    if (palette) {
 
2309
        unlock = READ_REG32(DC3_UNLOCK);
 
2310
        dcfg = READ_REG32(DC3_DISPLAY_CFG);
 
2311
 
 
2312
        WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
 
2313
        WRITE_REG32(DC3_DISPLAY_CFG, dcfg & ~DC3_DCFG_PALB);
 
2314
        WRITE_REG32(DC3_UNLOCK, unlock);
 
2315
 
 
2316
        for (i = 0; i < 256; i++)
 
2317
            WRITE_REG32(DC3_PAL_DATA, palette[i]);
 
2318
 
 
2319
        return CIM_STATUS_OK;
 
2320
    }
 
2321
    return CIM_STATUS_INVALIDPARAMS;
 
2322
}
 
2323
 
 
2324
/*---------------------------------------------------------------------------
 
2325
 * vg_set_compression_enable
 
2326
 *
 
2327
 * This routine enables or disables display compression.
 
2328
 *--------------------------------------------------------------------------*/
 
2329
 
 
2330
int
 
2331
vg_set_compression_enable(int enable)
 
2332
{
 
2333
    Q_WORD msr_value;
 
2334
    unsigned long unlock, gcfg;
 
2335
    unsigned long temp;
 
2336
 
 
2337
    unlock = READ_REG32(DC3_UNLOCK);
 
2338
    gcfg = READ_REG32(DC3_GENERAL_CFG);
 
2339
    WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
 
2340
 
 
2341
    if (enable) {
 
2342
        /* DO NOT ENABLE IF THE DISPLAY OFFSET IS NOT ZERO */
 
2343
 
 
2344
        if (READ_REG32(DC3_FB_ST_OFFSET) & 0x0FFFFFFF)
 
2345
            return CIM_STATUS_ERROR;
 
2346
 
 
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.
 
2352
         */
 
2353
 
 
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);
 
2358
 
 
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.
 
2363
         */
 
2364
 
 
2365
        temp = READ_REG32(DC3_DV_CTL);
 
2366
        WRITE_REG32(DC3_DV_CTL, temp | 0x00000001);
 
2367
 
 
2368
        /* ENABLE COMPRESSION BITS */
 
2369
 
 
2370
        gcfg |= DC3_GCFG_CMPE | DC3_GCFG_DECE;
 
2371
    }
 
2372
    else {
 
2373
        gcfg &= ~(DC3_GCFG_CMPE | DC3_GCFG_DECE);
 
2374
    }
 
2375
 
 
2376
    WRITE_REG32(DC3_GENERAL_CFG, gcfg);
 
2377
    WRITE_REG32(DC3_UNLOCK, unlock);
 
2378
 
 
2379
    return CIM_STATUS_OK;
 
2380
}
 
2381
 
 
2382
/*---------------------------------------------------------------------------
 
2383
 * vg_configure_compression
 
2384
 *
 
2385
 * This routine configures all aspects of display compression, including
 
2386
 * pitch, size and the offset of the compression buffer.
 
2387
 *--------------------------------------------------------------------------*/
 
2388
 
 
2389
int
 
2390
vg_configure_compression(VG_COMPRESSION_DATA * comp_data)
 
2391
{
 
2392
    unsigned long delta, size;
 
2393
    unsigned long comp_size, unlock;
 
2394
 
 
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.        */
 
2399
 
 
2400
    if (comp_data->size > 544 || comp_data->pitch < comp_data->size ||
 
2401
        comp_data->compression_offset & 0x0F) {
 
2402
        return CIM_STATUS_INVALIDPARAMS;
 
2403
    }
 
2404
 
 
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.                                              */
 
2409
 
 
2410
    comp_size = comp_data->size - 32;
 
2411
 
 
2412
    /* CALCULATE REGISTER VALUES */
 
2413
 
 
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;
 
2417
 
 
2418
    size |= ((comp_size >> 3) + 1) << DC3_LINE_SIZE_CB_SHIFT;
 
2419
    delta |= ((comp_data->pitch >> 3) << 16);
 
2420
 
 
2421
    /* WRITE COMPRESSION PARAMETERS */
 
2422
 
 
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);
 
2428
 
 
2429
    return CIM_STATUS_OK;
 
2430
}
 
2431
 
 
2432
/*---------------------------------------------------------------------------
 
2433
 * vg_test_timing_active
 
2434
 *
 
2435
 * This routine checks the status of the display timing generator.
 
2436
 *--------------------------------------------------------------------------*/
 
2437
 
 
2438
int
 
2439
vg_test_timing_active(void)
 
2440
{
 
2441
    if (READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_TGEN)
 
2442
        return 1;
 
2443
 
 
2444
    return 0;
 
2445
}
 
2446
 
 
2447
/*---------------------------------------------------------------------------
 
2448
 * vg_test_vertical_active
 
2449
 *
 
2450
 * This routine checks if the display is currently in the middle of a frame
 
2451
 * (not in the VBlank interval)
 
2452
 *--------------------------------------------------------------------------*/
 
2453
 
 
2454
int
 
2455
vg_test_vertical_active(void)
 
2456
{
 
2457
    if (READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA)
 
2458
        return 0;
 
2459
 
 
2460
    return 1;
 
2461
}
 
2462
 
 
2463
/*---------------------------------------------------------------------------
 
2464
 * vg_wait_vertical_blank
 
2465
 *
 
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
 *--------------------------------------------------------------------------*/
 
2470
 
 
2471
int
 
2472
vg_wait_vertical_blank(void)
 
2473
{
 
2474
    if (vg_test_timing_active()) {
 
2475
        while (!vg_test_vertical_active());
 
2476
        while (vg_test_vertical_active());
 
2477
    }
 
2478
    return CIM_STATUS_OK;
 
2479
}
 
2480
 
 
2481
/*---------------------------------------------------------------------------
 
2482
 * vg_test_even_field
 
2483
 *
 
2484
 * This routine tests the odd/even status of the current VG output field.
 
2485
 *--------------------------------------------------------------------------*/
 
2486
 
 
2487
int
 
2488
vg_test_even_field(void)
 
2489
{
 
2490
    if (READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_EVEN_FIELD)
 
2491
        return 1;
 
2492
 
 
2493
    return 0;
 
2494
}
 
2495
 
 
2496
/*---------------------------------------------------------------------------
 
2497
 * vg_configure_line_interrupt
 
2498
 *
 
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
 *--------------------------------------------------------------------------*/
 
2503
 
 
2504
int
 
2505
vg_configure_line_interrupt(VG_INTERRUPT_PARAMS * interrupt_info)
 
2506
{
 
2507
    unsigned long irq_line, irq_enable;
 
2508
    unsigned long lock;
 
2509
 
 
2510
    irq_line = READ_REG32(DC3_IRQ_FILT_CTL);
 
2511
    irq_enable = READ_REG32(DC3_IRQ);
 
2512
    lock = READ_REG32(DC3_UNLOCK);
 
2513
 
 
2514
    irq_line = (irq_line & ~DC3_IRQFILT_LINE_MASK) |
 
2515
        ((interrupt_info->line << 16) & DC3_IRQFILT_LINE_MASK);
 
2516
 
 
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  */
 
2521
    /* applications.                                                 */
 
2522
 
 
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));
 
2527
    }
 
2528
    else {
 
2529
        WRITE_REG32(DC3_IRQ, (irq_enable | DC3_IRQ_MASK));
 
2530
        WRITE_REG32(DC3_IRQ_FILT_CTL, irq_line);
 
2531
    }
 
2532
    WRITE_REG32(DC3_UNLOCK, lock);
 
2533
    return CIM_STATUS_OK;
 
2534
}
 
2535
 
 
2536
/*---------------------------------------------------------------------------
 
2537
 * vg_test_and_clear_interrupt
 
2538
 *
 
2539
 * This routine resets any pending interrupt in the video generator.  The
 
2540
 * return value indicates the interrupt status prior to the reset.
 
2541
 *--------------------------------------------------------------------------*/
 
2542
 
 
2543
unsigned long
 
2544
vg_test_and_clear_interrupt(void)
 
2545
{
 
2546
    unsigned long irq_enable;
 
2547
    unsigned long lock;
 
2548
 
 
2549
    irq_enable = READ_REG32(DC3_IRQ);
 
2550
    lock = READ_REG32(DC3_UNLOCK);
 
2551
 
 
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.                       */
 
2555
 
 
2556
    if ((irq_enable & (DC3_IRQ_MASK | DC3_VSYNC_IRQ_MASK)) ==
 
2557
        (DC3_IRQ_MASK | DC3_VSYNC_IRQ_MASK))
 
2558
        return 0;
 
2559
 
 
2560
    WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
 
2561
    WRITE_REG32(DC3_IRQ, irq_enable);
 
2562
    WRITE_REG32(DC3_UNLOCK, lock);
 
2563
 
 
2564
    return (irq_enable & (DC3_IRQ_STATUS | DC3_VSYNC_IRQ_STATUS));
 
2565
}
 
2566
 
 
2567
/*---------------------------------------------------------------------------
 
2568
 * vg_test_flip_status
 
2569
 *
 
2570
 * This routine tests if a new display offset has been latched.
 
2571
 *--------------------------------------------------------------------------*/
 
2572
 
 
2573
unsigned long
 
2574
vg_test_flip_status(void)
 
2575
{
 
2576
    return (READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_FLIP);
 
2577
}
 
2578
 
 
2579
/*---------------------------------------------------------------------------
 
2580
 * vg_save_state
 
2581
 *
 
2582
 * This routine saves all persistent VG state information.
 
2583
 *--------------------------------------------------------------------------*/
 
2584
 
 
2585
int
 
2586
vg_save_state(VG_SAVE_RESTORE * vg_state)
 
2587
{
 
2588
    Q_WORD msr_value;
 
2589
    unsigned long irqfilt;
 
2590
    unsigned long offset, i;
 
2591
    unsigned long lock;
 
2592
 
 
2593
    /* READ ALL CURRENT REGISTER SETTINGS */
 
2594
 
 
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);
 
2641
 
 
2642
    /* READ THE CURRENT PALETTE */
 
2643
 
 
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);
 
2649
 
 
2650
    /* READ THE CURRENT FILTER COEFFICIENTS */
 
2651
 
 
2652
    /* ENABLE ACCESS TO THE HORIZONTAL COEFFICIENTS */
 
2653
 
 
2654
    irqfilt = READ_REG32(DC3_IRQ_FILT_CTL);
 
2655
    irqfilt |= DC3_IRQFILT_H_FILT_SEL;
 
2656
 
 
2657
    /* READ HORIZONTAL COEFFICIENTS */
 
2658
 
 
2659
    for (i = 0; i < 256; i++) {
 
2660
        WRITE_REG32(DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
 
2661
 
 
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);
 
2664
    }
 
2665
 
 
2666
    /* ENABLE ACCESS TO THE VERTICAL COEFFICIENTS */
 
2667
 
 
2668
    irqfilt &= ~DC3_IRQFILT_H_FILT_SEL;
 
2669
 
 
2670
    /* READ COEFFICIENTS */
 
2671
 
 
2672
    for (i = 0; i < 256; i++) {
 
2673
        WRITE_REG32(DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
 
2674
 
 
2675
        vg_state->v_coeff[i] = READ_REG32(DC3_FILT_COEFF1);
 
2676
    }
 
2677
 
 
2678
    /* READ THE CURSOR DATA */
 
2679
 
 
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));
 
2683
 
 
2684
    /* READ THE CURRENT PLL */
 
2685
 
 
2686
    msr_read64(MSR_DEVICE_GEODELX_GLCP, GLCP_DOTPLL, &msr_value);
 
2687
 
 
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;
 
2692
            break;
 
2693
        }
 
2694
    }
 
2695
 
 
2696
    if (i == NUM_CIMARRON_PLL_FREQUENCIES) {
 
2697
        /* NO MATCH */
 
2698
        /* Enter the frequency as a manual frequency. */
 
2699
 
 
2700
        vg_state->dot_pll = msr_value.high;
 
2701
        vg_state->pll_flags |= VG_PLL_MANUAL;
 
2702
    }
 
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;
 
2711
 
 
2712
    /* READ ALL VG MSRS */
 
2713
 
 
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));
 
2725
 
 
2726
    WRITE_REG32(DC3_UNLOCK, lock);
 
2727
 
 
2728
    return CIM_STATUS_OK;
 
2729
}
 
2730
 
 
2731
/*---------------------------------------------------------------------------
 
2732
 * vg_restore_state
 
2733
 *
 
2734
 * This routine restores all persistent VG state information.
 
2735
 *--------------------------------------------------------------------------*/
 
2736
 
 
2737
int
 
2738
vg_restore_state(VG_SAVE_RESTORE * vg_state)
 
2739
{
 
2740
    unsigned long irqfilt, i;
 
2741
    unsigned long memoffset;
 
2742
 
 
2743
    /* TEMPORARILY UNLOCK ALL REGISTERS */
 
2744
 
 
2745
    WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
 
2746
 
 
2747
    /* RESTORE THE FRAME BUFFER OFFSET */
 
2748
 
 
2749
    WRITE_REG32(DC3_PHY_MEM_OFFSET, vg_state->fb_base);
 
2750
 
 
2751
    /* BLANK GCFG AND DCFG */
 
2752
 
 
2753
    WRITE_REG32(DC3_GENERAL_CFG, 0);
 
2754
    WRITE_REG32(DC3_DISPLAY_CFG, 0);
 
2755
 
 
2756
    /* RESTORE ALL REGISTERS */
 
2757
 
 
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);
 
2801
 
 
2802
    /* RESTORE THE PALETTE */
 
2803
 
 
2804
    WRITE_REG32(DC3_PAL_ADDRESS, 0);
 
2805
    for (i = 0; i < 261; i++)
 
2806
        WRITE_REG32(DC3_PAL_DATA, vg_state->palette[i]);
 
2807
 
 
2808
    /* RESTORE THE HORIZONTAL FILTER COEFFICIENTS */
 
2809
 
 
2810
    irqfilt = READ_REG32(DC3_IRQ_FILT_CTL);
 
2811
    irqfilt |= DC3_IRQFILT_H_FILT_SEL;
 
2812
 
 
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]);
 
2817
    }
 
2818
 
 
2819
    /* RESTORE VERTICAL COEFFICIENTS */
 
2820
 
 
2821
    irqfilt &= ~DC3_IRQFILT_H_FILT_SEL;
 
2822
 
 
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]);
 
2826
    }
 
2827
 
 
2828
    /* RESTORE THE CURSOR DATA */
 
2829
 
 
2830
    memoffset = READ_REG32(DC3_CURS_ST_OFFSET) & 0x0FFFFFFF;
 
2831
    WRITE_FB_STRING32(memoffset, (unsigned char *) &(vg_state->cursor_data[0]),
 
2832
                      3072);
 
2833
 
 
2834
    /* RESTORE THE PLL */
 
2835
    /* Use a common routine to use common code to poll for lock bit */
 
2836
 
 
2837
    vg_set_clock_frequency(vg_state->dot_pll, vg_state->pll_flags);
 
2838
 
 
2839
    /* RESTORE ALL VG MSRS */
 
2840
 
 
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));
 
2852
 
 
2853
    /* NOW RESTORE GCFG AND DCFG */
 
2854
 
 
2855
    WRITE_REG32(DC3_DISPLAY_CFG, vg_state->dcfg);
 
2856
    WRITE_REG32(DC3_GENERAL_CFG, vg_state->gcfg);
 
2857
 
 
2858
    /* FINALLY RESTORE UNLOCK */
 
2859
 
 
2860
    WRITE_REG32(DC3_UNLOCK, vg_state->unlock);
 
2861
 
 
2862
    return CIM_STATUS_OK;
 
2863
}
 
2864
 
 
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
 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
 
2870
 
 
2871
#if CIMARRON_INCLUDE_VG_READ_ROUTINES
 
2872
 
 
2873
/*---------------------------------------------------------------------------
 
2874
 * vg_read_graphics_crc
 
2875
 *
 
2876
 * This routine reads the Cyclic Redundancy Check (CRC) value for the graphics
 
2877
 * frame.
 
2878
 *--------------------------------------------------------------------------*/
 
2879
 
 
2880
unsigned long
 
2881
vg_read_graphics_crc(int crc_source)
 
2882
{
 
2883
    unsigned long gcfg, unlock;
 
2884
    unsigned long crc, vbi_even;
 
2885
    unsigned long interlaced;
 
2886
    unsigned long line, field;
 
2887
 
 
2888
    if (!(READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_TGEN))
 
2889
        return 0xFFFFFFFF;
 
2890
 
 
2891
    unlock = READ_REG32(DC3_UNLOCK);
 
2892
    gcfg = READ_REG32(DC3_GENERAL_CFG);
 
2893
    vbi_even = READ_REG32(DC3_VBI_EVEN_CTL);
 
2894
 
 
2895
    vbi_even &= ~DC3_VBI_EVEN_ENABLE_CRC;
 
2896
 
 
2897
    gcfg |= DC3_GCFG_SGRE | DC3_GCFG_CRC_MODE;
 
2898
    gcfg &= ~(DC3_GCFG_SGFR | DC3_GCFG_SIG_SEL | DC3_GCFG_FILT_SIG_SEL);
 
2899
 
 
2900
    switch (crc_source) {
 
2901
    case VG_CRC_SOURCE_PREFILTER_EVEN:
 
2902
    case VG_CRC_SOURCE_PREFILTER:
 
2903
        gcfg |= DC3_GCFG_SIG_SEL;
 
2904
        break;
 
2905
    case VG_CRC_SOURCE_PREFLICKER:
 
2906
    case VG_CRC_SOURCE_PREFLICKER_EVEN:
 
2907
        gcfg |= DC3_GCFG_FILT_SIG_SEL;
 
2908
        break;
 
2909
    case VG_CRC_SOURCE_POSTFLICKER:
 
2910
    case VG_CRC_SOURCE_POSTFLICKER_EVEN:       /* NO WORK */
 
2911
        break;
 
2912
 
 
2913
    default:
 
2914
        return 0xFFFFFFFF;
 
2915
    }
 
2916
 
 
2917
    if (crc_source & VG_CRC_SOURCE_EVEN)
 
2918
        field = 0;
 
2919
    else
 
2920
        field = DC3_LNCNT_EVEN_FIELD;
 
2921
 
 
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.                                     */
 
2927
 
 
2928
        do {
 
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);
 
2933
    }
 
2934
    else {
 
2935
        /* NON-INTERLACED - EVEN FIELD CRCS ARE INVALID */
 
2936
 
 
2937
        if (crc_source & VG_CRC_SOURCE_EVEN)
 
2938
            return 0xFFFFFFFF;
 
2939
    }
 
2940
 
 
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);
 
2945
 
 
2946
    /* WAIT FOR THE CRC TO BE COMPLETED */
 
2947
 
 
2948
    while (!(READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_SIGC));
 
2949
 
 
2950
    /* READ THE COMPLETED CRC */
 
2951
 
 
2952
    crc = READ_REG32(DC3_PAL_DATA);
 
2953
 
 
2954
    /* RESTORE THE PALETTE SETTINGS */
 
2955
 
 
2956
    gcfg &= ~DC3_GCFG_SGRE;
 
2957
    WRITE_REG32(DC3_GENERAL_CFG, gcfg);
 
2958
    WRITE_REG32(DC3_UNLOCK, unlock);
 
2959
 
 
2960
    return crc;
 
2961
}
 
2962
 
 
2963
/*---------------------------------------------------------------------------
 
2964
 * vg_read_window_crc
 
2965
 *
 
2966
 * This routine reads the Cyclic Redundancy Check (CRC) value for a sub-
 
2967
 * section of the frame.
 
2968
 *--------------------------------------------------------------------------*/
 
2969
 
 
2970
unsigned long
 
2971
vg_read_window_crc(int crc_source, unsigned long x, unsigned long y,
 
2972
                   unsigned long width, unsigned long height)
 
2973
{
 
2974
    Q_WORD msr_value;
 
2975
    unsigned long crc = 0;
 
2976
    unsigned long hactive, hblankstart;
 
2977
    unsigned long htotal, hblankend;
 
2978
    unsigned long line, field;
 
2979
    unsigned long diag;
 
2980
 
 
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;
 
2985
 
 
2986
    /* TIMINGS MUST BE ACTIVE */
 
2987
 
 
2988
    if (!(READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_TGEN))
 
2989
        return 0xFFFFFFFF;
 
2990
 
 
2991
    /* DISABLE GLCP ACTIONS */
 
2992
 
 
2993
    msr_value.low = 0;
 
2994
    msr_value.high = 0;
 
2995
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DIAGCTL, &msr_value);
 
2996
 
 
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   */
 
3002
        /* pixel.                                                         */
 
3003
 
 
3004
        /* N2 - DISPE HIGH AND Y == 1 */
 
3005
        /* Goto state YState = 2      */
 
3006
 
 
3007
        msr_value.high = 0x00000002;
 
3008
        msr_value.low = 0x00000C00;
 
3009
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 2, &msr_value);
 
3010
 
 
3011
        /* M3 - DISPE HIGH AND Y == 0 */
 
3012
        /* Goto YState = 1            */
 
3013
 
 
3014
        msr_value.high = 0x00000002;
 
3015
        msr_value.low = 0x00000A00;
 
3016
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETM0CTL + 3, &msr_value);
 
3017
 
 
3018
        /* N3 - DISPE LOW  */
 
3019
        /* Goto YState = 0 */
 
3020
 
 
3021
        msr_value.high = 0x00080000;
 
3022
        msr_value.low = 0x00000000;
 
3023
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 3, &msr_value);
 
3024
 
 
3025
        /* Y0 -> Y1 (SET M3) */
 
3026
 
 
3027
        msr_value.high = 0x00000000;
 
3028
        msr_value.low = 0x0000C000;
 
3029
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 18, &msr_value);
 
3030
 
 
3031
        /* Y1 -> Y0 (SET N3) */
 
3032
 
 
3033
        msr_value.low = 0x0000A000;
 
3034
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 17, &msr_value);
 
3035
 
 
3036
        /* Y1 -> Y2 (SET N2) */
 
3037
 
 
3038
        msr_value.low = 0x00000A00;
 
3039
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 19, &msr_value);
 
3040
 
 
3041
        /* N5 (XSTATE = 10 && CMP2 <= V. COUNTER <= CMP3) &&DISPE&& Y == 0 */
 
3042
        /* CRC into REGB                                                   */
 
3043
 
 
3044
        msr_value.high = 0x00000002;
 
3045
        msr_value.low = 0x10800B20;
 
3046
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 5, &msr_value);
 
3047
 
 
3048
        /* N6 (XSTATE = 10 && CMP2 <= V. COUNTER <= CMP3) && DISPE&&Y == 1 */
 
3049
        /* CRC into REGB                                                   */
 
3050
 
 
3051
        msr_value.high = 0x00000002;
 
3052
        msr_value.low = 0x10800D20;
 
3053
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 6, &msr_value);
 
3054
    }
 
3055
 
 
3056
    /* M4 (XSTATE = 00 AND VSYNC HIGH) */
 
3057
    /* Goto state 01                   */
 
3058
    /* Note: VSync = H3A               */
 
3059
 
 
3060
    msr_value.high = 0x00000001;
 
3061
    msr_value.low = 0x000000A0;
 
3062
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETM0CTL + 4, &msr_value);
 
3063
 
 
3064
    /* N0 (XSTATE = 01 AND VSYNC LOW) */
 
3065
    /* Goto state 02                  */
 
3066
    /* Note: VSync low = H3B          */
 
3067
 
 
3068
    msr_value.high = 0x00040000;
 
3069
    msr_value.low = 0x000000C0;
 
3070
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL, &msr_value);
 
3071
 
 
3072
    /* M5 (XSTATE = 10 AND VSYNC HIGH) */
 
3073
    /* Goto state 11                   */
 
3074
 
 
3075
    msr_value.high = 0x00000001;
 
3076
    msr_value.low = 0x00000120;
 
3077
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETM0CTL + 5, &msr_value);
 
3078
 
 
3079
    /* N1 (XSTATE = 10 and DISPE HIGH) */
 
3080
    /* Increment H. Counter           */
 
3081
    /* Note: DispE = H4               */
 
3082
 
 
3083
    msr_value.high = 0x00000002;
 
3084
    msr_value.low = 0x00000120;
 
3085
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 1, &msr_value);
 
3086
 
 
3087
    /* M0 (XSTATE = 10 and H. COUNTER == LIMIT)  */
 
3088
    /* Clear H. Counter and increment V. Counter */
 
3089
 
 
3090
    msr_value.high = 0x00000000;
 
3091
    msr_value.low = 0x00000122;
 
3092
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETM0CTL, &msr_value);
 
3093
 
 
3094
    /* N4 (XSTATE = 10 && CMP0 <= H. COUNTER <= CMP1 && CMP2 <= V. COUNTER
 
3095
     * <= CMP3) && DISPE
 
3096
     * CRC into REGB
 
3097
     */
 
3098
 
 
3099
    msr_value.high = 0x00000002;
 
3100
    msr_value.low = 0x10C20120;
 
3101
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 4, &msr_value);
 
3102
 
 
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)    */
 
3110
 
 
3111
    msr_value.high = 0;
 
3112
    if (x > 1)
 
3113
        msr_value.low = (x - 1) & 0xFFFF;
 
3114
    else
 
3115
        msr_value.low = x;
 
3116
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0, &msr_value);
 
3117
 
 
3118
    /* COMPARATOR 1 VALUE */
 
3119
 
 
3120
    if ((x == 0 || x == 1) && width > 1)
 
3121
        msr_value.low += width - 2;
 
3122
    else
 
3123
        msr_value.low += width - 1;
 
3124
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0 + 2, &msr_value);
 
3125
 
 
3126
    /* COMPARATOR 2 VALUE */
 
3127
 
 
3128
    msr_value.low = y << 16;
 
3129
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0 + 4, &msr_value);
 
3130
 
 
3131
    /* COMPARATOR 3 VALUE */
 
3132
 
 
3133
    msr_value.low += (height - 1) << 16;
 
3134
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0 + 6, &msr_value);
 
3135
 
 
3136
    /* COMPARATOR MASKS */
 
3137
    /* Comparators 0 and 1 refer to lower 16 bits of RegB */
 
3138
 
 
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);
 
3142
 
 
3143
    /* Comparators 2 and 3 refer to upper 16 bits of RegB */
 
3144
 
 
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);
 
3148
 
 
3149
    /* SET REGB MASK                                               */
 
3150
    /* We set the mask such that all all 32 bits of data are CRCed */
 
3151
 
 
3152
    msr_value.low = 0xFFFFFFFF;
 
3153
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_REGBMASK, &msr_value);
 
3154
 
 
3155
    /* ACTIONS */
 
3156
 
 
3157
    /* STATE 00->01 (SET 4M) */
 
3158
 
 
3159
    msr_value.low = 0x000C0000;
 
3160
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 14, &msr_value);
 
3161
 
 
3162
    /* STATE 01->10 (SET 0N) */
 
3163
 
 
3164
    msr_value.low = 0x0000000A;
 
3165
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 15, &msr_value);
 
3166
 
 
3167
    /* STATE 10->11 (SET 5M) */
 
3168
 
 
3169
    msr_value.low = 0x00C00000;
 
3170
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 16, &msr_value);
 
3171
 
 
3172
    /* CLEAR REGA WHEN TRANSITIONING TO STATE 10                 */
 
3173
    /* Do not clear RegB as the initial value must be 0x00000001 */
 
3174
 
 
3175
    msr_value.low = 0x0000000A;
 
3176
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0, &msr_value);
 
3177
 
 
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.
 
3182
     */
 
3183
 
 
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;
 
3191
 
 
3192
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 1, &msr_value);
 
3193
 
 
3194
    /* REGISTER ACTION 2            */
 
3195
    /* Increment V. Counter in REGA */
 
3196
 
 
3197
    msr_value.low = 0x0000000C;
 
3198
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 2, &msr_value);
 
3199
 
 
3200
    /* SET REGB TO 0x00000001 */
 
3201
 
 
3202
    msr_value.low = 0x00000001;
 
3203
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_REGB, &msr_value);
 
3204
 
 
3205
    /* SET XSTATE TO 0 */
 
3206
 
 
3207
    msr_value.low = 0x00000000;
 
3208
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_XSTATE, &msr_value);
 
3209
 
 
3210
    /* SET YSTATE TO 0 */
 
3211
 
 
3212
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_YSTATE, &msr_value);
 
3213
 
 
3214
    /* CLEAR ALL OTHER ACTIONS */
 
3215
    /* This prevents side-effects from previous accesses to the GLCP */
 
3216
    /* debug logic.                                                  */
 
3217
 
 
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);
 
3232
 
 
3233
    /* SET DIAG SETTINGS BASED ON DESIRED CRC */
 
3234
 
 
3235
    if (crc_source == VG_CRC_SOURCE_POSTFLICKER
 
3236
        || crc_source == VG_CRC_SOURCE_POSTFLICKER_EVEN) {
 
3237
        diag = 0x80808086;
 
3238
 
 
3239
        /* ENABLE HW CLOCK GATING AND SET GLCP CLOCK TO DOT CLOCK */
 
3240
 
 
3241
        msr_value.high = 0;
 
3242
        msr_value.low = 5;
 
3243
        msr_write64(MSR_DEVICE_GEODELX_GLCP, MSR_GEODELINK_PM, &msr_value);
 
3244
        msr_value.low = 0;
 
3245
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
 
3246
        msr_value.low = 3;
 
3247
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
 
3248
 
 
3249
        /* SET REGA LIMITS                              */
 
3250
        /* Lower counter uses pixels/line               */
 
3251
        /* Upper counter is 0xFFFF to prevent rollover. */
 
3252
 
 
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;
 
3257
        }
 
3258
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_REGAVAL, &msr_value);
 
3259
 
 
3260
        /* USE H4 FUNCTION A FOR DISPE AND H4 FUNCTION B FOR NOT DISPE */
 
3261
        /* DISPE is bit 34                                             */
 
3262
 
 
3263
        msr_value.high = 0x00000002;
 
3264
        msr_value.low = 0x20000FF0;
 
3265
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 4, &msr_value);
 
3266
 
 
3267
        /* USE H3 FUNCTION A FOR VSYNC AND H3 FUNCTION B FOR NOT VSYNC */
 
3268
        /* VSYNC is bit 32.                                            */
 
3269
 
 
3270
        msr_value.high = 0x00000000;
 
3271
        msr_value.low = 0x002055AA;
 
3272
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 3, &msr_value);
 
3273
    }
 
3274
    else if (crc_source == VG_CRC_SOURCE_PREFLICKER
 
3275
             || crc_source == VG_CRC_SOURCE_PREFLICKER_EVEN) {
 
3276
        diag = 0x801F8032;
 
3277
 
 
3278
        /* ENABLE HW CLOCK GATING AND SET GLCP CLOCK TO GEODELINK CLOCK */
 
3279
 
 
3280
        msr_value.high = 0;
 
3281
        msr_value.low = 5;
 
3282
        msr_write64(MSR_DEVICE_GEODELX_GLCP, MSR_GEODELINK_PM, &msr_value);
 
3283
        msr_value.low = 0;
 
3284
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
 
3285
        msr_value.low = 2;
 
3286
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
 
3287
 
 
3288
        /* SET REGA LIMITS                              */
 
3289
        /* Lower counter uses pixels/line               */
 
3290
        /* Upper counter is 0xFFFF to prevent rollover. */
 
3291
 
 
3292
        msr_value.low = 0xFFFF0000 | (hactive - 1);
 
3293
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_REGAVAL, &msr_value);
 
3294
 
 
3295
        /* USE H4 FUNCTION A FOR DISPE AND H4 FUNCTION B FOR NOT DISPE */
 
3296
        /* DISPE is bit 47                                             */
 
3297
 
 
3298
        msr_value.high = 0x00000002;
 
3299
        msr_value.low = 0xF0000FF0;
 
3300
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 4, &msr_value);
 
3301
 
 
3302
        /* USE H3 FUNCTION A FOR VSYNC AND H3 FUNCTION B FOR NOT VSYNC */
 
3303
        /* VSYNC is bit 45.                                            */
 
3304
 
 
3305
        msr_value.high = 0x00000000;
 
3306
        msr_value.low = 0x002D55AA;
 
3307
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 3, &msr_value);
 
3308
    }
 
3309
    else {
 
3310
        /* PREFILTER CRC */
 
3311
 
 
3312
        diag = 0x80138048;
 
3313
        msr_write64(MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_DIAG, &msr_value);
 
3314
 
 
3315
        /* ENABLE HW CLOCK GATING AND SET GLCP CLOCK TO GEODELINK CLOCK */
 
3316
 
 
3317
        msr_value.high = 0;
 
3318
        msr_value.low = 5;
 
3319
        msr_write64(MSR_DEVICE_GEODELX_GLCP, MSR_GEODELINK_PM, &msr_value);
 
3320
        msr_value.low = 0;
 
3321
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
 
3322
        msr_value.low = 2;
 
3323
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
 
3324
 
 
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 */
 
3330
 
 
3331
        msr_value.low =
 
3332
            0xFFFF0000 | ((READ_REG32(DC3_FB_ACTIVE) >> 16) & 0xFFF);
 
3333
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_REGAVAL, &msr_value);
 
3334
 
 
3335
        /* USE H4 FUNCTION A FOR DISPE AND H4 FUNCTION B FOR NOT DISPE */
 
3336
        /* DISPE is bit 55                                             */
 
3337
 
 
3338
        msr_value.high = 0x00000003;
 
3339
        msr_value.low = 0x70000FF0;
 
3340
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 4, &msr_value);
 
3341
 
 
3342
        /* USE H3 FUNCTION A FOR VSYNC AND H3 FUNCTION B FOR NOT VSYNC */
 
3343
        /* VSYNC is bit 53.                                            */
 
3344
 
 
3345
        msr_value.high = 0x00000000;
 
3346
        msr_value.low = 0x003555AA;
 
3347
        msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 3, &msr_value);
 
3348
    }
 
3349
 
 
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.                                             */
 
3353
 
 
3354
    if (crc_source & VG_CRC_SOURCE_EVEN)
 
3355
        field = 0;
 
3356
    else
 
3357
        field = DC3_LNCNT_EVEN_FIELD;
 
3358
 
 
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.                                     */
 
3364
 
 
3365
        do {
 
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);
 
3370
    }
 
3371
    else {
 
3372
        /* NON-INTERLACED - EVEN FIELD CRCS ARE INVALID */
 
3373
 
 
3374
        if (crc_source & VG_CRC_SOURCE_EVEN)
 
3375
            return 0xFFFFFFFF;
 
3376
    }
 
3377
 
 
3378
    /* UPDATE VG DIAG OUTPUT */
 
3379
 
 
3380
    msr_value.high = 0;
 
3381
    msr_value.low = diag;
 
3382
    msr_write64(MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_DIAG, &msr_value);
 
3383
 
 
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                                                   */
 
3390
 
 
3391
    msr_value.low = 0x80EA20A0;
 
3392
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DIAGCTL, &msr_value);
 
3393
 
 
3394
    /* DELAY TWO FRAMES */
 
3395
 
 
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);
 
3401
 
 
3402
    /* VERIFY THAT XSTATE = 11 */
 
3403
 
 
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);
 
3407
 
 
3408
        crc = msr_value.low;
 
3409
    }
 
3410
 
 
3411
    /* DISABLE VG DIAG BUS OUTPUTS */
 
3412
 
 
3413
    msr_value.low = 0x00000000;
 
3414
    msr_value.high = 0x00000000;
 
3415
    msr_write64(MSR_DEVICE_GEODELX_VG, MSR_GEODELINK_DIAG, &msr_value);
 
3416
 
 
3417
    /* DISABLE GLCP ACTIONS */
 
3418
 
 
3419
    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DIAGCTL, &msr_value);
 
3420
 
 
3421
    return crc;
 
3422
}
 
3423
 
 
3424
/*---------------------------------------------------------------------------
 
3425
 * vg_get_scaler_filter_coefficients
 
3426
 *
 
3427
 * This routine gets the vertical and horizontal filter coefficients for
 
3428
 * graphics scaling.  The coefficients are sign extended to 32-bit values.
 
3429
 *--------------------------------------------------------------------------*/
 
3430
 
 
3431
int
 
3432
vg_get_scaler_filter_coefficients(long h_taps[][5], long v_taps[][3])
 
3433
{
 
3434
    unsigned long irqfilt, i;
 
3435
    unsigned long temp;
 
3436
    long coeff0, coeff1, coeff2;
 
3437
    unsigned long lock;
 
3438
 
 
3439
    /* ENABLE ACCESS TO THE HORIZONTAL COEFFICIENTS */
 
3440
 
 
3441
    lock = READ_REG32(DC3_UNLOCK);
 
3442
    irqfilt = READ_REG32(DC3_IRQ_FILT_CTL);
 
3443
    irqfilt |= DC3_IRQFILT_H_FILT_SEL;
 
3444
 
 
3445
    /* WRITE COEFFICIENTS */
 
3446
    /* Coefficient indexes do not auto-increment, so we must */
 
3447
    /* write the address for every phase                     */
 
3448
 
 
3449
    WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
 
3450
 
 
3451
    for (i = 0; i < 256; i++) {
 
3452
        WRITE_REG32(DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
 
3453
 
 
3454
        temp = READ_REG32(DC3_FILT_COEFF1);
 
3455
        coeff0 = (temp & 0x3FF);
 
3456
        coeff1 = (temp >> 10) & 0x3FF;
 
3457
        coeff2 = (temp >> 20) & 0x3FF;
 
3458
 
 
3459
        h_taps[i][0] = (coeff0 << 22) >> 22;
 
3460
        h_taps[i][1] = (coeff1 << 22) >> 22;
 
3461
        h_taps[i][2] = (coeff2 << 22) >> 22;
 
3462
 
 
3463
        temp = READ_REG32(DC3_FILT_COEFF2);
 
3464
        coeff0 = (temp & 0x3FF);
 
3465
        coeff1 = (temp >> 10) & 0x3FF;
 
3466
 
 
3467
        h_taps[i][3] = (coeff0 << 22) >> 22;
 
3468
        h_taps[i][4] = (coeff1 << 22) >> 22;
 
3469
    }
 
3470
 
 
3471
    /* ENABLE ACCESS TO THE VERTICAL COEFFICIENTS */
 
3472
 
 
3473
    irqfilt &= ~DC3_IRQFILT_H_FILT_SEL;
 
3474
 
 
3475
    /* WRITE COEFFICIENTS */
 
3476
 
 
3477
    for (i = 0; i < 256; i++) {
 
3478
        WRITE_REG32(DC3_IRQ_FILT_CTL, ((irqfilt & 0xFFFFFF00L) | i));
 
3479
 
 
3480
        temp = READ_REG32(DC3_FILT_COEFF1);
 
3481
        coeff0 = (temp & 0x3FF);
 
3482
        coeff1 = (temp >> 10) & 0x3FF;
 
3483
        coeff2 = (temp >> 20) & 0x3FF;
 
3484
 
 
3485
        v_taps[i][0] = (coeff0 << 22) >> 22;
 
3486
        v_taps[i][1] = (coeff1 << 22) >> 22;
 
3487
        v_taps[i][2] = (coeff2 << 22) >> 22;
 
3488
    }
 
3489
 
 
3490
    WRITE_REG32(DC3_UNLOCK, lock);
 
3491
 
 
3492
    return CIM_STATUS_OK;
 
3493
}
 
3494
 
 
3495
/*---------------------------------------------------------------------------
 
3496
 * vg_get_flicker_filter_configuration
 
3497
 *
 
3498
 * This routine returns the current VG flicker filter configuration.
 
3499
 *--------------------------------------------------------------------------*/
 
3500
 
 
3501
int
 
3502
vg_get_flicker_filter_configuration(unsigned long *strength, int *flicker_alpha)
 
3503
{
 
3504
    unsigned long genlk_ctl;
 
3505
 
 
3506
    if (!strength || !flicker_alpha)
 
3507
        return CIM_STATUS_INVALIDPARAMS;
 
3508
 
 
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)
 
3512
        *flicker_alpha = 1;
 
3513
    else
 
3514
        *flicker_alpha = 0;
 
3515
 
 
3516
    return CIM_STATUS_OK;
 
3517
}
 
3518
 
 
3519
/*---------------------------------------------------------------------------
 
3520
 * vg_get_display_pitch
 
3521
 *
 
3522
 * This routine returns the current stride between successive lines of frame
 
3523
 * buffer data.
 
3524
 *--------------------------------------------------------------------------*/
 
3525
 
 
3526
unsigned long
 
3527
vg_get_display_pitch(void)
 
3528
{
 
3529
    return ((READ_REG32(DC3_GFX_PITCH) & 0x0000FFFF) << 3);
 
3530
}
 
3531
 
 
3532
/*---------------------------------------------------------------------------
 
3533
 * vg_get_frame_buffer_line_size
 
3534
 *
 
3535
 * This routine returns the current size in bytes of one line of frame buffer
 
3536
 * data.
 
3537
 *--------------------------------------------------------------------------*/
 
3538
 
 
3539
unsigned long
 
3540
vg_get_frame_buffer_line_size(void)
 
3541
{
 
3542
    return ((READ_REG32(DC3_LINE_SIZE) & 0x3FF) << 3);
 
3543
}
 
3544
 
 
3545
/*---------------------------------------------------------------------------
 
3546
 * vg_get_current_vline
 
3547
 *
 
3548
 * This routine returns the number of the current line that is being displayed
 
3549
 * by the display controller.
 
3550
 *--------------------------------------------------------------------------*/
 
3551
 
 
3552
unsigned long
 
3553
vg_get_current_vline(void)
 
3554
{
 
3555
    unsigned long current_line;
 
3556
 
 
3557
    /* READ THE REGISTER TWICE TO ENSURE THAT THE VALUE IS NOT TRANSITIONING */
 
3558
 
 
3559
    do {
 
3560
        current_line = READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_V_LINE_CNT;
 
3561
    }
 
3562
    while (current_line !=
 
3563
           (READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_V_LINE_CNT));
 
3564
 
 
3565
    return (current_line >> 16);
 
3566
}
 
3567
 
 
3568
/*---------------------------------------------------------------------------
 
3569
 * vg_get_display_offset
 
3570
 *
 
3571
 * This routine returns the offset into the frame buffer for the first pixel
 
3572
 * of the display.
 
3573
 *--------------------------------------------------------------------------*/
 
3574
 
 
3575
unsigned long
 
3576
vg_get_display_offset(void)
 
3577
{
 
3578
    return (READ_REG32(DC3_FB_ST_OFFSET) & 0x0FFFFFFF);
 
3579
}
 
3580
 
 
3581
/*---------------------------------------------------------------------------
 
3582
 * vg_get_cursor_info
 
3583
 *
 
3584
 * This routine returns the current settings for the hardware cursor.
 
3585
 *--------------------------------------------------------------------------*/
 
3586
 
 
3587
int
 
3588
vg_get_cursor_info(VG_CURSOR_DATA * cursor_data)
 
3589
{
 
3590
    unsigned long temp;
 
3591
 
 
3592
    /* CURSOR OFFSET */
 
3593
 
 
3594
    cursor_data->cursor_offset = READ_REG32(DC3_CURS_ST_OFFSET) & 0x0FFFFFFF;
 
3595
 
 
3596
    /* CURSOR X POSITION */
 
3597
 
 
3598
    temp = READ_REG32(DC3_CURSOR_X);
 
3599
    cursor_data->cursor_x = temp & 0x7FF;
 
3600
    cursor_data->clipx = (temp >> 11) & 0x3F;
 
3601
 
 
3602
    /* CURSOR Y POSITION */
 
3603
 
 
3604
    temp = READ_REG32(DC3_CURSOR_Y);
 
3605
    cursor_data->cursor_y = temp & 0x7FF;
 
3606
    cursor_data->clipy = (temp >> 11) & 0x3F;
 
3607
 
 
3608
    /* CURSOR COLORS */
 
3609
 
 
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);
 
3613
 
 
3614
    /* CURSOR ENABLES */
 
3615
 
 
3616
    temp = READ_REG32(DC3_GENERAL_CFG);
 
3617
    if (temp & DC3_GCFG_CURE)
 
3618
        cursor_data->enable = 1;
 
3619
    else
 
3620
        cursor_data->enable = 0;
 
3621
    if (temp & DC3_GCFG_CLR_CUR)
 
3622
        cursor_data->color_cursor = 1;
 
3623
    else
 
3624
        cursor_data->color_cursor = 0;
 
3625
 
 
3626
    return CIM_STATUS_OK;
 
3627
}
 
3628
 
 
3629
/*----------------------------------------------------------------------------
 
3630
 * vg_get_display_palette_entry
 
3631
 *
 
3632
 * This routine reads a single entry in the 8BPP display palette.
 
3633
 *--------------------------------------------------------------------------*/
 
3634
 
 
3635
int
 
3636
vg_get_display_palette_entry(unsigned long index, unsigned long *entry)
 
3637
{
 
3638
    if (index > 0xFF)
 
3639
        return CIM_STATUS_INVALIDPARAMS;
 
3640
 
 
3641
    WRITE_REG32(DC3_PAL_ADDRESS, index);
 
3642
    *entry = READ_REG32(DC3_PAL_DATA);
 
3643
 
 
3644
    return CIM_STATUS_OK;
 
3645
}
 
3646
 
 
3647
/*----------------------------------------------------------------------------
 
3648
 * vg_get_border_color
 
3649
 *
 
3650
 * This routine reads the current border color for centered displays.
 
3651
 *--------------------------------------------------------------------------*/
 
3652
 
 
3653
unsigned long
 
3654
vg_get_border_color(void)
 
3655
{
 
3656
    WRITE_REG32(DC3_PAL_ADDRESS, 0x104);
 
3657
    return READ_REG32(DC3_PAL_DATA);
 
3658
}
 
3659
 
 
3660
/*----------------------------------------------------------------------------
 
3661
 * vg_get_display_palette
 
3662
 *
 
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
 *--------------------------------------------------------------------------*/
 
3666
 
 
3667
int
 
3668
vg_get_display_palette(unsigned long *palette)
 
3669
{
 
3670
    unsigned long i;
 
3671
 
 
3672
    if (palette) {
 
3673
        WRITE_REG32(DC3_PAL_ADDRESS, 0);
 
3674
        for (i = 0; i < 256; i++) {
 
3675
            palette[i] = READ_REG32(DC3_PAL_DATA);
 
3676
        }
 
3677
        return CIM_STATUS_OK;
 
3678
    }
 
3679
    return CIM_STATUS_INVALIDPARAMS;
 
3680
}
 
3681
 
 
3682
/*----------------------------------------------------------------------------
 
3683
 * vg_get_compression_info
 
3684
 *
 
3685
 * This routines reads the current status of the display compression hardware.
 
3686
 *--------------------------------------------------------------------------*/
 
3687
 
 
3688
int
 
3689
vg_get_compression_info(VG_COMPRESSION_DATA * comp_data)
 
3690
{
 
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 -
 
3694
                                                      3)) & 0x3F8) + 24;
 
3695
 
 
3696
    return CIM_STATUS_OK;
 
3697
}
 
3698
 
 
3699
/*----------------------------------------------------------------------------
 
3700
 * vg_get_compression_enable
 
3701
 *
 
3702
 * This routines reads the current enable status of the display compression
 
3703
 * hardware.
 
3704
 *--------------------------------------------------------------------------*/
 
3705
 
 
3706
int
 
3707
vg_get_compression_enable(void)
 
3708
{
 
3709
    if (READ_REG32(DC3_GENERAL_CFG) & DC3_GCFG_CMPE)
 
3710
        return 1;
 
3711
 
 
3712
    return 0;
 
3713
}
 
3714
 
 
3715
/*----------------------------------------------------------------------------
 
3716
 * vg_get_valid_bit
 
3717
 *--------------------------------------------------------------------------*/
 
3718
 
 
3719
int
 
3720
vg_get_valid_bit(int line)
 
3721
{
 
3722
    unsigned long offset;
 
3723
    unsigned long valid;
 
3724
    unsigned long lock;
 
3725
 
 
3726
    lock = READ_REG32(DC3_UNLOCK);
 
3727
    offset = READ_REG32(DC3_PHY_MEM_OFFSET) & 0xFF000000;
 
3728
    offset |= line;
 
3729
 
 
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;
 
3734
 
 
3735
    if (valid)
 
3736
        return 1;
 
3737
    return 0;
 
3738
}
 
3739
 
 
3740
#endif