~gma500/+junk/emgd152-natty

« back to all changes in this revision

Viewing changes to emgd-dkms-1.5.15.3082/emgd/display/mode/cmn/match.c

  • Committer: Luca Forina
  • Date: 2011-02-06 15:11:54 UTC
  • Revision ID: luca.forina@gmail.com-20110206151154-9dzn5ugxjub9qenb
Upload Emgd 1.5.2 for Natty (override Maverick)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- pse-c -*-
 
2
 *-----------------------------------------------------------------------------
 
3
 * Filename: match.c
 
4
 * $Revision: 1.8 $
 
5
 *-----------------------------------------------------------------------------
 
6
 * Copyright © 2002-2010, Intel Corporation.
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or modify it
 
9
 * under the terms and conditions of the GNU General Public License,
 
10
 * version 2, as published by the Free Software Foundation.
 
11
 *
 
12
 * This program is distributed in the hope it will be useful, but WITHOUT
 
13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
14
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 
15
 * more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License along with
 
18
 * this program; if not, write to the Free Software Foundation, Inc.,
 
19
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 
20
 *
 
21
 *-----------------------------------------------------------------------------
 
22
 * Description:
 
23
 *  
 
24
 *-----------------------------------------------------------------------------
 
25
 */
 
26
 
 
27
#define MODULE_NAME hal.mode
 
28
 
 
29
 
 
30
#define CURSOR_DEFAULT_WIDTH    64
 
31
#define CURSOR_DEFAULT_HEIGHT   64
 
32
 
 
33
#include <context.h>
 
34
#include <igd_init.h>
 
35
#include <io.h>
 
36
#include <memory.h>
 
37
#include <edid.h>
 
38
#include <pi.h>
 
39
 
 
40
#include <igd_mode.h>
 
41
#include <igd_errno.h>
 
42
 
 
43
#include <mode.h>
 
44
#include <config.h>
 
45
 
 
46
#include "match.h"
 
47
 
 
48
/*!
 
49
 * @addtogroup display_group
 
50
 * @{
 
51
 */
 
52
 
 
53
/* Local variables */
 
54
#ifndef CONFIG_MICRO
 
55
igd_cursor_info_t default_cursor = {
 
56
        CURSOR_DEFAULT_WIDTH,
 
57
        CURSOR_DEFAULT_HEIGHT,
 
58
        CONFIG_DEFAULT_PF,
 
59
        0, 0, 0, 0, 0, 0,
 
60
        0, 0, {0, 0, 0, 0}, IGD_CURSOR_ON, 0, 0, 0, 0
 
61
};
 
62
 
 
63
/*!
 
64
 *
 
65
 * @param cursor_info
 
66
 * @param display
 
67
 *
 
68
 * @return -IGD_INVAL on failure
 
69
 * @return 0 on success
 
70
 */
 
71
int validate_cursor(igd_cursor_info_t *cursor_info,
 
72
        igd_display_context_t *display)
 
73
{
 
74
        unsigned long *list_pfs;
 
75
        igd_display_pipe_t *pipe = (igd_display_pipe_t *)(display->pipe);
 
76
 
 
77
        EMGD_TRACE_ENTER;
 
78
        if (pipe) {
 
79
                if (pipe->cursor) {
 
80
                        list_pfs = pipe->cursor->pixel_formats;
 
81
 
 
82
                        while (*list_pfs) {
 
83
                                if (cursor_info->pixel_format == *list_pfs) {
 
84
                                        return 0;
 
85
                                }
 
86
                                list_pfs++;
 
87
                        }
 
88
                }
 
89
        }
 
90
 
 
91
        EMGD_TRACE_EXIT;
 
92
        return -IGD_INVAL;
 
93
}
 
94
#endif
 
95
 
 
96
/*!
 
97
 *
 
98
 * @param timing
 
99
 * @param pt_info
 
100
 *
 
101
 * @return void
 
102
 */
 
103
static void fill_pt(
 
104
        igd_timing_info_t *timing,
 
105
        pigd_display_info_t pt_info)
 
106
{
 
107
        unsigned long flags;
 
108
 
 
109
        EMGD_DEBUG("fill_pt Entry");
 
110
 
 
111
        /* preserve existing pt_info flags */
 
112
        flags = pt_info->flags;
 
113
 
 
114
        /* Simply memcpy the structures and fix up the flags */
 
115
        OS_MEMCPY(pt_info, timing, sizeof(igd_timing_info_t));
 
116
 
 
117
        pt_info->flags |= flags;
 
118
 
 
119
        /* pt_info doesn't require a IGD_MODE_VESA flag, so clear IGD_MODE_VESA
 
120
         * Setting this flag creates issues in match mode. */
 
121
        pt_info->flags &= ~IGD_MODE_VESA;
 
122
        return;
 
123
}
 
124
 
 
125
#ifndef CONFIG_NEW_MATCH
 
126
 
 
127
 
 
128
extern igd_timing_info_t vga_timing_table[];
 
129
extern igd_timing_info_t crt_timing_table[];
 
130
 
 
131
 
 
132
#define MATCH_MOD(x)  ((x>0)?x:-x)
 
133
#define MATCH_EXACT    0x01
 
134
#define MATCH_NATIVE   0x02
 
135
#define MATCH_CENTER   0x10
 
136
#define MATCH_FOR_VGA  0x20
 
137
 
 
138
/*!
 
139
 *
 
140
 * @param display
 
141
 * @param timing_table
 
142
 * @param pt_info
 
143
 * @param type
 
144
 *
 
145
 * @return NULL on failure
 
146
 * @return timing on success
 
147
 */
 
148
static igd_timing_info_t *match_resolution(
 
149
                igd_display_context_t *display,
 
150
                igd_timing_info_t *timing_table,
 
151
                igd_display_info_t *pt_info,
 
152
                int type)
 
153
{
 
154
        igd_timing_info_t *timing;
 
155
        igd_timing_info_t *match;
 
156
        igd_timing_info_t *native_match = NULL;
 
157
        igd_display_port_t *port;
 
158
 
 
159
        EMGD_DEBUG("Enter match_resolution");
 
160
 
 
161
        EMGD_DEBUG("Width=%d, height=%d, refresh=%d mode_number=0x%x",
 
162
                pt_info->width, pt_info->height, pt_info->refresh,
 
163
                pt_info->mode_number);
 
164
 
 
165
        timing = timing_table;
 
166
        match = NULL;
 
167
        port = PORT_OWNER(display);
 
168
 
 
169
        /*
 
170
         * Note on Native matching.
 
171
         * The Ideal thing is for a fp_native_dtd to already be marked as such.
 
172
         * If there is no native timing indicated then we must choose what is
 
173
         * most likely correct.
 
174
         * If the mode is not VGA then we should choose any DTD that closely
 
175
         * matches the mode being set. Failing that we should choose any timing
 
176
         * that closely matches the mode.
 
177
         * If the mode is VGA then we should take the current mode as it is
 
178
         * more likely correct.
 
179
         */
 
180
        if(type == MATCH_NATIVE) {
 
181
                if(port->fp_native_dtd) {
 
182
                        EMGD_DEBUG("Returning quick with a native match");
 
183
 
 
184
                        EMGD_DEBUG("NATIVE Width=%d, height=%d, refresh=%d mode_num=0x%x",
 
185
                                port->fp_native_dtd->width, port->fp_native_dtd->height,
 
186
                                port->fp_native_dtd->refresh, port->fp_native_dtd->mode_number);
 
187
 
 
188
                        return port->fp_native_dtd;
 
189
                }
 
190
                if((pt_info->flags & IGD_MODE_VESA) &&
 
191
                        (pt_info->mode_number <= 0x13)) {
 
192
                        if(PIPE(display)->timing) {
 
193
                                native_match = PIPE(display)->timing;
 
194
                        }
 
195
                }
 
196
        }
 
197
 
 
198
        while (timing->width != IGD_TIMING_TABLE_END) {
 
199
                if(!(timing->mode_info_flags & IGD_MODE_SUPPORTED)) {
 
200
                        timing++;
 
201
                        continue;
 
202
                }
 
203
 
 
204
                if(type == MATCH_NATIVE) {
 
205
                        if(timing->mode_info_flags & IGD_MODE_DTD_FP_NATIVE) {
 
206
                                port->fp_native_dtd = timing;
 
207
                                return timing;
 
208
                        }
 
209
 
 
210
                        if(port->fp_info) {
 
211
                                /*
 
212
                                 * We may have only fp_width and fp_height which is really
 
213
                                 * not enough information to be useful. If we find a
 
214
                                 * matching width and height we'll keep the first one while
 
215
                                 * still hoping to find an actual native mode later.
 
216
                                 */
 
217
                                if(!match &&
 
218
                                        (port->fp_info->fp_width ==
 
219
                                                (unsigned long)timing->width) &&
 
220
                                        (port->fp_info->fp_height ==
 
221
                                                (unsigned long)timing->height)) {
 
222
                                        match = timing;
 
223
                                }
 
224
                        } else {
 
225
                                /*
 
226
                                 * Keep a match because in the event that we never find a
 
227
                                 * native DTD then we will just take the exact match.
 
228
                                 */
 
229
                                if(!match &&
 
230
                                        (timing->width == pt_info->width) &&
 
231
                                        (timing->height == pt_info->height) &&
 
232
                                        (timing->refresh == pt_info->refresh)) {
 
233
                                        match = timing;
 
234
                                }
 
235
                        }
 
236
 
 
237
                        /*
 
238
                         * If it is a DTD then keep it only if it is better than any
 
239
                         * found before.
 
240
                         */
 
241
                        if(timing->mode_info_flags & IGD_MODE_DTD_USER) {
 
242
                                if(native_match) {
 
243
                                        if(MATCH_MOD((int)(pt_info->width*pt_info->height) -
 
244
                                                        (native_match->width * native_match->height)) >
 
245
                                                MATCH_MOD((int)(pt_info->width*pt_info->height) -
 
246
                                                        (timing->width*timing->height))) {
 
247
                                                native_match = timing;
 
248
                                        }
 
249
                                } else {
 
250
                                        native_match = timing;
 
251
                                }
 
252
                        }
 
253
                } else if (type == MATCH_EXACT) {
 
254
                        /*
 
255
                         * Looking for an exact match. For VGA/VESA it must match
 
256
                         * mode number. Otherwise it must match width, height, refresh
 
257
                         * etc.
 
258
                         */
 
259
                        if(pt_info->flags & IGD_MODE_VESA) {
 
260
                                /* ((timing->mode_info_flags & IGD_MODE_VESA)) */
 
261
                                if((pt_info->mode_number == timing->mode_number) &&
 
262
                                        (!pt_info->refresh ||
 
263
                                                (pt_info->refresh == timing->refresh))) {
 
264
                                        match = timing;
 
265
                                        break;
 
266
                                }
 
267
                        } else {
 
268
                                /* If exact match found, then break the loop */
 
269
                                if((timing->width == pt_info->width) &&
 
270
                                        (timing->height == pt_info->height) &&
 
271
                                        (timing->refresh == pt_info->refresh) &&
 
272
                                        (
 
273
                                                (timing->mode_info_flags &
 
274
                                                        (IGD_SCAN_INTERLACE|IGD_PIXEL_DOUBLE|
 
275
                                                                IGD_LINE_DOUBLE)) ==
 
276
                                                (pt_info->flags &
 
277
                                                        (IGD_SCAN_INTERLACE|IGD_PIXEL_DOUBLE|
 
278
                                                                IGD_LINE_DOUBLE)))) {
 
279
                                        match = timing;
 
280
 
 
281
                                        /* If exact match found, then break the loop */
 
282
                                        if ((timing->mode_info_flags & PD_MODE_DTD_USER) ||
 
283
                                                (timing->mode_info_flags & PD_MODE_DTD)) {
 
284
                                                break;
 
285
                                        }
 
286
                                }
 
287
                        }
 
288
                }
 
289
 
 
290
 
 
291
                /* Center needs only to be bigger. Aspect ratio doesn't matter. */
 
292
                /*
 
293
                 * Note: The timings have to be big enough to fit the pt_info
 
294
                 * including any pixel double flags. VGA modes will sometimes be
 
295
                 * pixel doubled and need to be centered in a pipe that is double
 
296
                 * in size.
 
297
                 *
 
298
                 * Note2: 720x400 VGA modes can be centered in 640x480 with a
 
299
                 * special hardware config that drops every 9th pixel. Only do
 
300
                 * this when requested.
 
301
                 */
 
302
                else if(type & MATCH_CENTER) {
 
303
                        unsigned short eff_width = pt_info->width;
 
304
                        unsigned short eff_height = pt_info->height;
 
305
 
 
306
                        if(type & MATCH_FOR_VGA) {
 
307
                                /*
 
308
                                 * 720x400 is a magic mode that means all VGA modes are supported
 
309
                                 * always use that mode for centering if found.
 
310
                                 */
 
311
                                if((timing->width == 720) && (timing->height == 400)) {
 
312
                                        EMGD_DEBUG("Returning with a magic VGA mode");
 
313
                                        return timing;
 
314
                                }
 
315
                                if(pt_info->flags & IGD_PIXEL_DOUBLE) {
 
316
                                        eff_width *= 2;
 
317
                                }
 
318
                                if(pt_info->flags & IGD_LINE_DOUBLE) {
 
319
                                        eff_height *= 2;
 
320
                                }
 
321
                                if((eff_width == 720) &&
 
322
                                        (port->port_features & IGD_VGA_COMPRESS)) {
 
323
                                        eff_width = 640;
 
324
                                }
 
325
                        }
 
326
 
 
327
                        if((timing->width >= eff_width) &&
 
328
                                (timing->height >= eff_height) &&
 
329
                                (timing->mode_info_flags & IGD_SCAN_INTERLACE) ==
 
330
                                (pt_info->flags & IGD_SCAN_INTERLACE)) {
 
331
                                if(match) {
 
332
                                        /* Check for tighter fit */
 
333
                                        if((match->width > timing->width) ||
 
334
                                                (match->height > timing->height)) {
 
335
                                                match = timing;
 
336
                                        }
 
337
                                        /* Try to match refreshrate as well */
 
338
                                        if((match->width == timing->width) &&
 
339
                                           (match->height == timing->height) &&
 
340
                                           (pt_info->refresh == timing->refresh)){
 
341
                                                match = timing;
 
342
                                        }
 
343
                                } else {
 
344
                                        match = timing;
 
345
                                }
 
346
                        }
 
347
                }
 
348
                timing++;
 
349
        }
 
350
 
 
351
        if(native_match) {
 
352
                EMGD_DEBUG("Returning with a native match");
 
353
                EMGD_DEBUG("Width=%d, height=%d, refresh=%d mode_number=0x%x",
 
354
                        native_match->width, native_match->height, native_match->refresh,
 
355
                        native_match->mode_number);
 
356
                return native_match;
 
357
        }
 
358
        if (!match) {
 
359
                EMGD_DEBUG("Returning with NO match");
 
360
                return NULL;
 
361
        }
 
362
 
 
363
        EMGD_DEBUG("Returning with a match");
 
364
        EMGD_DEBUG("Width=%d, height=%d, refresh=%d mode_number=0x%x",
 
365
                match->width, match->height, match->refresh, match->mode_number);
 
366
        return match;
 
367
} /* end match_resolution */
 
368
 
 
369
static igd_timing_info_t scaled_timing[IGD_MAX_PIPES];
 
370
 
 
371
/*!
 
372
 * Match the fb and pt structures to a Mode Structure from the table.
 
373
 * When a mode is found update the input structures to reflect the
 
374
 * values found.
 
375
 *
 
376
 * Notes:
 
377
 *  Match mode has several options for what it can do. Foremost it should
 
378
 * attempt to find a mode matching the requested one from the timing table
 
379
 * provided. If the mode requested is not in the list this means one of
 
380
 * two things.
 
381
 *   1) The IAL is calling without checking modes. It is just passing down
 
382
 *  something that a user asked for. This is ok but we need to be safe so
 
383
 *  we return the next smaller mode with the same aspect ratio.
 
384
 *
 
385
 *   2) The IAL is requesting a very common "required" mode even though the
 
386
 *  port doesn't support it. In this case it should be in the static common
 
387
 *  modes table and can be centered in the next larger timings in the
 
388
 *  mode table.
 
389
 *
 
390
 * If the Frambuffer is smaller than the timings requested a fake set of
 
391
 * centered timings is returned to program the pipe.
 
392
 *
 
393
 * In the case of VGA modes. If the mode is in the mode table everything is
 
394
 * fine and we just return that. If it is not in the table we find the next
 
395
 * larger suitable mode and prepare to center in that mode. Using the static
 
396
 * timings from the VGA table as the VGA mode. We do not need to generate
 
397
 * a fake set of timings because VGA will center itself automatically in
 
398
 * hardware.
 
399
 *
 
400
 * In the case of LVDS both centering and scaling can happen. If the mode
 
401
 * is in the list it will be scaled to the Native Timings. If the mode
 
402
 * is not in the list (common or VGA) it will be centered in the next larger
 
403
 * supported mode and then scaled to the native timings.
 
404
 *
 
405
 * Centering is always indicated by returning the timings that should be
 
406
 * programmed to the pipe. The timings will then have their extension pointer
 
407
 * set to point to the centered timings. For centering with scaling the
 
408
 * first extension pointer will contain the scalable timings and the
 
409
 * second will contain the centering timings. The static "scaled_timings"
 
410
 * data structure will be used when the scaled timings need to be
 
411
 * created on the fly due to a Framebuffer that is smaller than the
 
412
 * timings.
 
413
 *
 
414
 * @param display
 
415
 * @param timing_table
 
416
 * @param fb_info
 
417
 * @param pt_info
 
418
 * @param timing
 
419
 *
 
420
 * @return -IGD_ERROR_INVAL on failure
 
421
 * @return 0 on success
 
422
 */
 
423
int match_mode (
 
424
        igd_display_context_t *display,
 
425
        igd_timing_info_t *timing_table,
 
426
        igd_framebuffer_info_t *fb_info,
 
427
        igd_display_info_t *pt_info,
 
428
        igd_timing_info_t **timing)
 
429
{
 
430
        igd_timing_info_t *exact_timing = NULL;
 
431
        igd_timing_info_t *pipe_timing = NULL;
 
432
        igd_timing_info_t *user_timing = NULL;
 
433
        igd_timing_info_t *native_timing = NULL;
 
434
        igd_timing_info_t *vga_timing = NULL;
 
435
        igd_timing_info_t *vesa_timing = NULL;
 
436
        short cntr_dff_w = 0;
 
437
        short cntr_dff_h = 0;
 
438
        unsigned long upscale = 0;
 
439
 
 
440
        EMGD_DEBUG("Enter Match Mode");
 
441
 
 
442
        if(!pt_info) {
 
443
                EMGD_ERROR("NULL Port info detected, returning");
 
444
                return -IGD_ERROR_INVAL;
 
445
        }
 
446
 
 
447
        /* Check for default case */
 
448
        if (!(pt_info->flags & IGD_MODE_VESA) &&
 
449
                (pt_info->width == 0) && (pt_info->height == 0)) {
 
450
                EMGD_DEBUG("Display Info width, height are zero, using default case");
 
451
                pt_info->width = CONFIG_DEFAULT_WIDTH;
 
452
                pt_info->height = CONFIG_DEFAULT_HEIGHT;
 
453
        }
 
454
 
 
455
        EMGD_DEBUG("Checking for exact mode match");
 
456
        exact_timing = match_resolution(display, timing_table, pt_info,
 
457
                MATCH_EXACT);
 
458
        /*
 
459
         * At this point we have one of these cases:
 
460
         *  1) Found an exact match, VGA, VESA or other.
 
461
         *    -> Go check for FB centering and finish up.
 
462
         *  2) Found nothing
 
463
         *    -> Check for VGA/VESA mode to center.
 
464
         *    -> Check common modes.
 
465
         */
 
466
        if(exact_timing) {
 
467
                pipe_timing = exact_timing;
 
468
                user_timing = exact_timing;
 
469
                pipe_timing->extn_ptr = NULL;
 
470
        } else {
 
471
                /* No match found? Is it VGA? */
 
472
                if( (pt_info->flags & IGD_MODE_VESA) &&
 
473
                        (pt_info->mode_number < 0x1D)    ){
 
474
                        EMGD_DEBUG("Checking for exact match in VGA table");
 
475
                        /* this only happens if it was a VGA mode number */
 
476
                        pt_info->refresh = 0;
 
477
                        vga_timing = match_resolution(display, vga_timing_table,
 
478
                                pt_info, MATCH_EXACT);
 
479
 
 
480
                        if(!vga_timing) {
 
481
                                return -IGD_ERROR_INVAL;
 
482
                        }
 
483
 
 
484
                        vga_timing->extn_ptr = NULL;
 
485
                        /* We got something sane that needs to be centered */
 
486
                        user_timing = vga_timing;
 
487
                        fill_pt(vga_timing,pt_info);
 
488
 
 
489
                        /* continue at the bottom where we have
 
490
                         * pipe_timing = NULL, so we will look
 
491
                         * for centered timings for pt_info and
 
492
                         * use cmn_vga_timings to tell match_resolution
 
493
                         * to take into account special VGA mode
 
494
                         * centering regulations
 
495
                         */
 
496
                }
 
497
        }
 
498
 
 
499
        /* Find UPSCALING attr value*/
 
500
        pi_pd_find_attr_and_value(PORT_OWNER(display),
 
501
                        PD_ATTR_ID_PANEL_FIT,
 
502
                        0,/*no PD_FLAG for UPSCALING */
 
503
                        NULL, /* dont need the attr ptr*/
 
504
                        &upscale);
 
505
        /* this PI func will not modify value of upscale if attr does not exist */
 
506
 
 
507
        if(!pipe_timing){
 
508
                /* At this point, one of 2 things has happenned:
 
509
                 *      - we have a mode request that we could not match exactly.
 
510
                 *        and it WASNT a VESA_MODE number request.
 
511
                 *      - we have a request based on VESA_MODE number (maybe from
 
512
                 *        VBIOS IAL) and we could not get a exact match from the
 
513
                 *        port_timing_table, but we did get a match from the vga-
 
514
                 *        timing_table.
 
515
                 * In this case, there is one thing to do - MATCH_CENTER. Match
 
516
                 * resolution will handle it this way:
 
517
                 *      - if its VESA MODE number based, we only need to get
 
518
                 *        the best (tightest) match if its VGA OR DONT match
 
519
                 *        if its one of those magic timings
 
520
                 *      - Else, we need to get the best (tightest) match, AND
 
521
                 *        we need to center requested timings in that tightest fitting
 
522
                 *        timing. But wait! This could mean if the requested pt_info
 
523
                 *        is bigger than anything in the port timing table, we have
 
524
                 *        no choice but to fail.
 
525
                 */
 
526
                unsigned char match_type = MATCH_CENTER;
 
527
 
 
528
                EMGD_DEBUG("Checking for a safe centered match");
 
529
                if(vga_timing) {
 
530
                        match_type |= MATCH_FOR_VGA;
 
531
                } else if(pt_info->flags & IGD_MODE_VESA) {
 
532
                        /* if a vesa mode number was requested...
 
533
                         * and we are centering that mode, we
 
534
                         * need to get the common mode fb size
 
535
                         * in case we need it later for VBIOS
 
536
                         * which doesnt populate the FBInfo
 
537
                         */
 
538
                        vesa_timing = match_resolution(display, crt_timing_table,
 
539
                                pt_info, MATCH_EXACT);
 
540
                }
 
541
 
 
542
                if (upscale && vga_timing) {
 
543
                        /* If port supports upscaling and match is called for VGA,
 
544
                         * then center vga mode resolution directly in the native mode
 
545
                         * instead of centering VGA in another resolution */
 
546
                        pipe_timing = vga_timing;
 
547
                } else {
 
548
                        pipe_timing = match_resolution(display, timing_table, pt_info,
 
549
                                match_type);
 
550
                        /* This can happen if there is a spurious pt_info from IAL */
 
551
                        if (!pipe_timing) {
 
552
                                return -IGD_ERROR_INVAL;
 
553
                        }
 
554
                        pipe_timing->extn_ptr = vga_timing;
 
555
                        /* for the case of non VGA mode call,
 
556
                         * at this point, vga_timing is NULL
 
557
                         */
 
558
                }
 
559
 
 
560
                if(!vga_timing) {
 
561
                        user_timing = pipe_timing;
 
562
                }
 
563
        }
 
564
 
 
565
        /*
 
566
         * At this point pipe_timing is what we are going to program the
 
567
         * pipe to roughly speaking. If there is a common timing then we
 
568
         * want it centered in the pipe_timing.
 
569
         *
 
570
         * If the framebuffer is smaller than the timings then we need to
 
571
         * generate a centered set of timings by copying the pipe timings
 
572
         * and shifting them a bit.
 
573
         *
 
574
         * If fb width and height are zero just assume that we want it to
 
575
         * match the timings and make up a pixel format. This is mostly because
 
576
         * VGA/VESA modes will just be set by number. We don't know their size
 
577
         * until we look up the number.
 
578
         */
 
579
        if(fb_info) {
 
580
                /*
 
581
                 * fb_info is sometimes NULL when just testing something.
 
582
                 */
 
583
                if(!fb_info->pixel_format) {
 
584
                        /* Ugly VGA modes, it doesn't matter */
 
585
                        fb_info->pixel_format = IGD_PF_ARGB8_INDEXED;
 
586
                }
 
587
                if(!fb_info->width) {
 
588
                        if(vga_timing) {
 
589
                                fb_info->width = vga_timing->width;
 
590
                                fb_info->height = vga_timing->height;
 
591
                        } else {
 
592
                                if(!vesa_timing){
 
593
                                        vesa_timing = pipe_timing;
 
594
                                        /* in case vesa_timing is false set it to
 
595
                                         * pipe_timing so we dont need to check for
 
596
                                         * validity later, when increasing fb size for
 
597
                                         * VBIOS in clone mode (see 18 lines below)
 
598
                                         */
 
599
                                }
 
600
                                fb_info->width = vesa_timing->width;
 
601
                                fb_info->height = vesa_timing->height;
 
602
                        }
 
603
                }
 
604
 
 
605
                /*
 
606
                 * VGA common timings are centered in pipe timings by hardware.
 
607
                 * Otherwise we need to adjust the timings when centering is
 
608
                 * needed.
 
609
                 */
 
610
                if (!vga_timing) {
 
611
                        /*
 
612
                         * For VBIOS clone modes the FB should be the biggest mode
 
613
                         * if this is the second match we may need to update the fb
 
614
                         * data structure.
 
615
                         */
 
616
                        if(fb_info->flags & IGD_VBIOS_FB) {
 
617
                                if ((fb_info->width < vesa_timing->width) ||
 
618
                                        (fb_info->height < vesa_timing->height)) {
 
619
                                        fb_info->width = vesa_timing->width;
 
620
                                        fb_info->height = vesa_timing->height;
 
621
                                }
 
622
                        }
 
623
 
 
624
 
 
625
                        /* Do centering if fb is smaller than timing except on TV */
 
626
                        if ((fb_info->width < pipe_timing->width) ||
 
627
                                (fb_info->height < pipe_timing->height)) {
 
628
                                unsigned short temp_width = pipe_timing->width;
 
629
                                unsigned short temp_height = pipe_timing->height;
 
630
                                /* Normally, we should NOT be in here. All IALs only
 
631
                                 * are supposed to request for timings that ARE surely
 
632
                                 * supported by the HAL,... i.e. query the list of
 
633
                                 * supported timings by the port first!
 
634
                                 *
 
635
                                 * The exception would be if the IAL is purposely
 
636
                                 * asking for CENTERING!!! (pt_info's that were not
 
637
                                 * part of the supported mode list). This could indicate an
 
638
                                 * error or an explicit request for VESA centering!.
 
639
                                 */
 
640
 
 
641
                                /* let's use these 2 variables as flags... and do the
 
642
                                 * actual "centering" of the timings later since we do
 
643
                                 * also need to acomodate native timings as well
 
644
                                 */
 
645
                                /* NOTE: we could never be in here in fb_info was NULL */
 
646
                                cntr_dff_w = (pipe_timing->width - fb_info->width) / 2;
 
647
                                cntr_dff_h = (pipe_timing->height - fb_info->height) / 2;
 
648
 
 
649
                                /* Dont forget to use a different storage sice we dont
 
650
                                 * want to change the original (and to be used later)
 
651
                                 * ports mode list timings
 
652
                                 */
 
653
                                OS_MEMCPY(&scaled_timing[(PIPE(display)->pipe_num)],
 
654
                                        pipe_timing,
 
655
                                        sizeof(igd_timing_info_t));
 
656
 
 
657
                                pipe_timing = &scaled_timing[(PIPE(display)->pipe_num)];
 
658
 
 
659
                                if(PORT_OWNER(display)->pd_type != PD_DISPLAY_TVOUT ) {
 
660
                                        /* TV display don't like changed pipe actives,
 
661
                                         * Updating syncs work for TV centering */
 
662
                                        if (fb_info->width < temp_width) {
 
663
                                                pipe_timing->width = (unsigned short)fb_info->width;
 
664
                                                pipe_timing->hblank_start -= cntr_dff_w;
 
665
                                                pipe_timing->hblank_end -= cntr_dff_w;
 
666
                                        }
 
667
 
 
668
                                        if (fb_info->height < temp_height) {
 
669
                                                pipe_timing->height = (unsigned short)fb_info->height;
 
670
                                                pipe_timing->vblank_start -= cntr_dff_h;
 
671
                                                pipe_timing->vblank_end -= cntr_dff_h;
 
672
                                        }
 
673
                                }
 
674
 
 
675
                                if (fb_info->width < temp_width) {
 
676
                                        pipe_timing->hsync_start -= cntr_dff_w;
 
677
                                        pipe_timing->hsync_end -= cntr_dff_w;
 
678
                                }
 
679
 
 
680
                                if (fb_info->height < temp_height) {
 
681
                                        pipe_timing->vsync_start -= cntr_dff_h;
 
682
                                        pipe_timing->vsync_end -= cntr_dff_h;
 
683
                                }
 
684
                        }
 
685
                }
 
686
        }
 
687
 
 
688
        if(upscale) {
 
689
                /* Get the native timings */
 
690
                EMGD_DEBUG("Checking for Native LVDS match for scaling");
 
691
                native_timing = match_resolution(display, timing_table, pt_info,
 
692
                        MATCH_NATIVE);
 
693
                if(native_timing && (native_timing != pipe_timing)) {
 
694
                        native_timing->extn_ptr = pipe_timing;
 
695
                        pipe_timing = native_timing;
 
696
                }
 
697
        }
 
698
 
 
699
        /*
 
700
         * Match mode returns as follows:
 
701
         * In case of VGA setmode:
 
702
         * 1) We will end up with either:
 
703
         *   magic->vga   ---   For displays supports native VGA
 
704
         *      or
 
705
         *   native->vga  ---   Upscaling displays
 
706
         *      or
 
707
         *   pipe->vga    ---   For other displays
 
708
         *
 
709
         * 2) In case of regular setmode:
 
710
         *   pipe         ---   For regular displays
 
711
         *      or
 
712
         *   native->vesa ---   Upscaling displays
 
713
         *
 
714
         *   Note: 1) Here "pipe" can be munged if centering is required.
 
715
         *         2) "vesa" is the requested mode, native is the native timing
 
716
         *            of the display.
 
717
         */
 
718
 
 
719
        /*
 
720
         * Update Input Structures with values found
 
721
         * Note: This might not be what is going to be programmed. It is what
 
722
         * the user thinks they set. Scaling or centering could have altered
 
723
         * that.
 
724
         */
 
725
        fill_pt(user_timing, pt_info);
 
726
        *timing = pipe_timing;
 
727
        EMGD_DEBUG("Return");
 
728
 
 
729
        return 0;
 
730
}
 
731
#else
 
732
 
 
733
#define MATCH_NUMBER    0x001
 
734
#define MATCH_REFRESH   0x002
 
735
#define MATCH_WIDTH     0x004
 
736
#define MATCH_HEIGHT    0x008
 
737
#define MATCH_FLAGS     0x010
 
738
#define MATCH_GE_WIDTH  0x020
 
739
#define MATCH_GE_HEIGHT 0x040
 
740
#define MATCH_FOR_VGA   0x100
 
741
 
 
742
static int modes_match(igd_display_info_t *x,
 
743
        igd_timing_info_t *y,
 
744
        unsigned int flags)
 
745
{
 
746
        if((flags & MATCH_NUMBER) &&
 
747
                (x->mode_number != y->mode_number)) {
 
748
                return 0;
 
749
        }
 
750
        if((flags & MATCH_REFRESH) &&
 
751
                (x->refresh && (x->refresh != y->refresh))) {
 
752
                return 0;
 
753
        }
 
754
        if((flags & MATCH_WIDTH) &&
 
755
                (x->width != y->width)) {
 
756
                return 0;
 
757
        }
 
758
        if((flags & MATCH_HEIGHT) &&
 
759
                (x->height != y->height)) {
 
760
                return 0;
 
761
        }
 
762
        if((flags & MATCH_GE_WIDTH) &&
 
763
                (x->width > y->width)) {
 
764
                return 0;
 
765
        }
 
766
        if((flags & MATCH_GE_HEIGHT) &&
 
767
                (x->height > y->height)) {
 
768
                return 0;
 
769
        }
 
770
        if((flags & MATCH_FLAGS) &&
 
771
                (x->flags & (IGD_SCAN_INTERLACE|IGD_PIXEL_DOUBLE|IGD_LINE_DOUBLE)) !=
 
772
                (y->mode_info_flags &
 
773
                        (IGD_SCAN_INTERLACE|IGD_PIXEL_DOUBLE|IGD_LINE_DOUBLE))) {
 
774
                return 0;
 
775
        }
 
776
 
 
777
        return 1;
 
778
}
 
779
 
 
780
typedef struct _vga_wh {
 
781
        short width;
 
782
        short height;
 
783
} vga_wh_t;
 
784
 
 
785
static vga_wh_t vga_size[] = {
 
786
        {640, 400}, {640, 400}, {640, 400}, {640, 400},
 
787
        {320, 400}, {320, 400}, {640, 400}, {720, 350},
 
788
        {640, 400}, {640, 400}, {640, 350}, {640, 350},
 
789
        {640, 350}, {640, 350}, {640, 350}, {640, 350},
 
790
        {640, 400}, {720, 400}, {720, 400}, {640, 480},
 
791
        {640, 480}, {640, 400}
 
792
};
 
793
 
 
794
/*
 
795
 * For VGA modes we do not actually have a mode table. Just use a
 
796
 * temporary slot (one per-pipe) and put the VGA mode number in it.
 
797
 */
 
798
static igd_timing_info_t vga_timing[] = {
 
799
        {
 
800
                720, 400, 70,
 
801
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
802
                0x00,
 
803
                IGD_MODE_VESA | IGD_MODE_SUPPORTED,
 
804
                0, 0, NULL, NULL
 
805
        },
 
806
        {
 
807
                720, 400, 70,
 
808
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
809
                0x00,
 
810
                IGD_MODE_VESA | IGD_MODE_SUPPORTED,
 
811
                0, 0, NULL, NULL
 
812
        }
 
813
};
 
814
 
 
815
/*
 
816
 * The magic mode, when found in a port's mode list, means that the port
 
817
 * can do native VGA output. A mode with a wxh of 720x480 and refresh of
 
818
 * 70 is the magic mode.
 
819
 */
 
820
static igd_display_info_t magic_timing = {
 
821
        720, 400, 70,
 
822
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
823
        0x00,
 
824
        IGD_MODE_VESA | PD_MODE_SUPPORTED,
 
825
        0, 0, NULL, NULL
 
826
};
 
827
 
 
828
/*!
 
829
 * Match Resolution searches the provided timing table for a mode that
 
830
 * matches the requested parameters using the provided criteria.
 
831
 *
 
832
 * @param display The display on which the mode will be displayed.
 
833
 * @param timing_table The list of modes to search through.
 
834
 * @param pt_info The timing set used as reference for the match
 
835
 * @param criteria The criteria that must match (bitfield). Options are
 
836
 *  MATCH_NUMBER: Match the VGA/VESA mode number
 
837
 *  MATCH_REFRESH: Match the refresh rate
 
838
 *  MATCH_WIDTH: Match the width
 
839
 *  MATCH_HEIGHT: Match the height
 
840
 *  MATCH_FLAGS: Match relavent interlace, pixel double, etc flags.
 
841
 *  MATCH_GE_WIDTH: Match width greater or equal to requested (used with
 
842
 *    best_match = 1)
 
843
 *  MATCH_GE_HEIGHT: Match height greater or equal to requested (used with
 
844
 *    best_match = 1)
 
845
 *  MATCH_FOR_VGA: Match is used for a VGA container which may need to take
 
846
 *    into accoutn 9th pixel dropping in the hardware.
 
847
 * @param best_match When set to 0 the first mode found matching the criteria
 
848
 *      will be returned. Null will be returned if no match is found.
 
849
 *      When set to 1 the best matching mode is found after searching all modes.
 
850
 *      if no mode is found matching the criteria, the last mode in the table
 
851
 *      is used (should be the largest mode as mode tables are sorted)
 
852
 *
 
853
 * @return igd_timing_info_t
 
854
 */
 
855
static igd_timing_info_t *match_resolution(
 
856
                igd_display_context_t *display,
 
857
                igd_timing_info_t *timing_table,
 
858
                igd_display_info_t *pt_info,
 
859
                unsigned int criteria,
 
860
                int best_match)
 
861
{
 
862
        igd_timing_info_t *timing;
 
863
        igd_timing_info_t *match;
 
864
        igd_timing_info_t *last_mode = NULL;
 
865
        igd_display_port_t *port;
 
866
        unsigned short save_width;
 
867
 
 
868
        EMGD_DEBUG("Enter match_resolution");
 
869
 
 
870
        EMGD_DEBUG("Width=%d, height=%d, refresh=%d mode_number=0x%x",
 
871
                pt_info->width, pt_info->height, pt_info->refresh,
 
872
                pt_info->mode_number);
 
873
 
 
874
        timing = timing_table;
 
875
        match = NULL;
 
876
        port = PORT_OWNER(display);
 
877
        save_width = pt_info->width;
 
878
 
 
879
        /*
 
880
         * Hardware has a mode where it can drop every 9th pixel to fit
 
881
         * a 720 width VGA mode into a 640 width container. Modify the
 
882
         * reference mode to reflect 640 width and put it back at the end.
 
883
         */
 
884
        if(criteria & MATCH_FOR_VGA) {
 
885
                if((pt_info->width == 720) &&
 
886
                        (port->port_features & IGD_VGA_COMPRESS)) {
 
887
                        pt_info->width = 640;
 
888
                }
 
889
        }
 
890
 
 
891
        while (timing->width != IGD_TIMING_TABLE_END) {
 
892
                if(!MODE_IS_SUPPORTED(timing)) {
 
893
                        timing++;
 
894
                        continue;
 
895
                }
 
896
                if(modes_match(pt_info, timing, criteria)) {
 
897
                        /*
 
898
                         * If we are looking for the first match we are done.
 
899
                         */
 
900
                        if(!best_match) {
 
901
                                match = timing;
 
902
                                break;
 
903
                        }
 
904
                        /*
 
905
                         * Looking for best match. Compare the new match to the last one
 
906
                         * to see if it is better.
 
907
                         */
 
908
                        if(match) {
 
909
                                /* Check for tighter fit */
 
910
                                if((timing->width < match->width) ||
 
911
                                        (timing->height < match->height)) {
 
912
                                        match = timing;
 
913
                                }
 
914
                        } else {
 
915
                                match = timing;
 
916
                        }
 
917
                }
 
918
                last_mode = timing;
 
919
                timing++;
 
920
        }
 
921
 
 
922
        pt_info->width = save_width;
 
923
        if(!match && best_match) {
 
924
                /*
 
925
                 * Take the last one in the table for container modes. This insures
 
926
                 * that we never fail a container mode.
 
927
                 */
 
928
                match = last_mode;
 
929
        }
 
930
 
 
931
        if (match) {
 
932
                EMGD_DEBUG("Returning with a match");
 
933
                EMGD_DEBUG("Width=%d, height=%d, refresh=%d mode_number=0x%x",
 
934
                        match->width, match->height, match->refresh, match->mode_number);
 
935
        } else {
 
936
                EMGD_DEBUG("Returning with NO match");
 
937
        }
 
938
 
 
939
        return match;
 
940
} /* end match_resolution */
 
941
 
 
942
 
 
943
void update_fb_size(igd_timing_info_t *match,
 
944
        igd_framebuffer_info_t *fb_info)
 
945
{
 
946
 
 
947
        /*
 
948
         * fb_info is sometimes NULL when just testing something.
 
949
         */
 
950
        if(fb_info) {
 
951
                /*
 
952
                 * If The FB data comes in as zero we populate it with the matched
 
953
                 * size. Also if the FB is coming from vBIOS we increase the size
 
954
                 * to fit the match.
 
955
                 */
 
956
                if((fb_info->width == 0) || (fb_info->flags & IGD_VBIOS_FB)) {
 
957
 
 
958
                        if((fb_info->width < match->width) ||
 
959
                                (fb_info->height < match->height)) {
 
960
                                fb_info->width = match->width;
 
961
                                fb_info->height = match->height;
 
962
                        }
 
963
                }
 
964
        }
 
965
}
 
966
 
 
967
/*!
 
968
 * Push a Match on to the stack which is represented by a link list.
 
969
 * Only push the mode if it is different than the head of the list.
 
970
 *
 
971
 * @param match
 
972
 * @param timing_stack
 
973
 *
 
974
 * @return void
 
975
 */
 
976
void push_match(igd_timing_info_t *match,
 
977
        igd_timing_info_t **timing_stack)
 
978
{
 
979
 
 
980
        if(match == *timing_stack) {
 
981
                return;
 
982
        }
 
983
        match->extn_ptr = *timing_stack;
 
984
        *timing_stack = match;
 
985
        return;
 
986
}
 
987
 
 
988
 
 
989
static igd_timing_info_t scaled_timing[IGD_MAX_PIPES];
 
990
 
 
991
/*!
 
992
 * This function determines if the input timings need to be modified
 
993
 * to accomodate the provided framebuffer. If so it converts the timing set
 
994
 * to a modified set that centers the provided framebuffer image.
 
995
 * The provided timings are not modified and the returned set
 
996
 * may be used until the next mode set. The returned timings do
 
997
 * not need to be freed.
 
998
 *
 
999
 * @param display A pointer to the display used for these timings.
 
1000
 *      This parameter is used to determine which pipe the timings
 
1001
 *      will be used with. There is one set of static timings for
 
1002
 *      each pipe.
 
1003
 * @param timing The input timings which are used as reference to
 
1004
 *      generate the new timings. Only the width/height and blank/syncs
 
1005
 *      will be altered. The pixel clock and total sizes will not be changed.
 
1006
 * @param fb_info The framebuffer information to center within the
 
1007
 *      provided timings. (May be NULL)
 
1008
 *
 
1009
 * @return Modified timing set
 
1010
 */
 
1011
igd_timing_info_t *get_centered_timings(igd_display_context_t *display,
 
1012
        igd_timing_info_t *timing,
 
1013
        igd_framebuffer_info_t *fb_info)
 
1014
{
 
1015
        short cntr_dff_w = 0;
 
1016
        short cntr_dff_h = 0;
 
1017
 
 
1018
        if(!fb_info) {
 
1019
                return timing;
 
1020
        }
 
1021
 
 
1022
        /*
 
1023
         * If we end up making a munged centered timings we need to use
 
1024
         * a copy and not the originals.
 
1025
         *
 
1026
         */
 
1027
        OS_MEMCPY(&scaled_timing[(PIPE(display)->pipe_num)],
 
1028
                timing, sizeof(igd_timing_info_t));
 
1029
 
 
1030
        if(PORT_OWNER(display)->pd_type != PD_DISPLAY_TVOUT) {
 
1031
                /*
 
1032
                 * TV display don't like changed pipe actives,
 
1033
                 * Updating syncs work for TV centering
 
1034
                 */
 
1035
                if (fb_info->width < timing->width) {
 
1036
                        timing = &scaled_timing[(PIPE(display)->pipe_num)];
 
1037
                        cntr_dff_w = (timing->width - fb_info->width) / 2;
 
1038
                        timing->width = (unsigned short)fb_info->width;
 
1039
                        timing->hblank_start -= cntr_dff_w;
 
1040
                        timing->hblank_end -= cntr_dff_w;
 
1041
                }
 
1042
                if (fb_info->height < timing->height) {
 
1043
                        timing = &scaled_timing[(PIPE(display)->pipe_num)];
 
1044
                        cntr_dff_h = (timing->height - fb_info->height) / 2;
 
1045
                        timing->height = (unsigned short)fb_info->height;
 
1046
                        timing->vblank_start -= cntr_dff_h;
 
1047
                        timing->vblank_end -= cntr_dff_h;
 
1048
                }
 
1049
        }
 
1050
 
 
1051
        timing->hsync_start -= cntr_dff_w;
 
1052
        timing->hsync_end -= cntr_dff_w;
 
1053
        timing->vsync_start -= cntr_dff_h;
 
1054
        timing->vsync_end -= cntr_dff_h;
 
1055
 
 
1056
        return timing;
 
1057
}
 
1058
 
 
1059
 
 
1060
/*!
 
1061
 * Match the fb and pt structures to a Mode Structure from the table.
 
1062
 * When a mode is found update the input structures to reflect the
 
1063
 * values found.
 
1064
 *
 
1065
 *  The match mode function will compile all the information needed by
 
1066
 * the HAL to put the hardware into a mode. This may be a regular
 
1067
 * full-screen mode, a centered mode, a panned mode, a scaled mode.
 
1068
 * Below is a table of the mode that will be used and the cases in which
 
1069
 * it will occurr.
 
1070
 *
 
1071
 * Native
 
1072
 *  The requested mode is matched in the mode table in terms of width
 
1073
 *  height, refresh, and interlace flags. There is no fp_native_dtd or
 
1074
 *  the matching mode IS the fp_native_dtd.
 
1075
 * Centered
 
1076
 *  1) The requested mode is matched in the mode table but the framebuffer
 
1077
 *     is a smaller size and needs to be centered.
 
1078
 *  2) The requested mode is NOT matched in the mode table and the
 
1079
 *     framebuffer matches the requested mode. A container mode is used
 
1080
 *     with the original smaller framebuffer.
 
1081
 * Scaled
 
1082
 *  The requested mode is matched in the mode table and a fp_native_dtd
 
1083
 *  is present for the port. The matched mode does not match the native
 
1084
 *  and is therefore scaled to fit.
 
1085
 * Panned/Cropped
 
1086
 *  The requested mode is matched in the mode table but the framebuffer
 
1087
 *  is larger (in at least one demension) that the mode. The mode is
 
1088
 *  set with a cropped FB that may then be panned by the IAL.
 
1089
 * Render Scaled
 
1090
 *  The requested mode may or may not be matched in the mode table. The
 
1091
 *  framebuffer data is empty. The HAL will match the mode or find a
 
1092
 *  container or find the largest mode and set the framebuffer to the
 
1093
 *  same size. The IAL will scale the actual framebuffer to the returned
 
1094
 *  framebuffer.
 
1095
 * Native VGA
 
1096
 *  A VGA mode is requested (by number) and the magic VGA mode is matched
 
1097
 *  in the mode table. FB contents are output only.
 
1098
 * Centered VGA
 
1099
 *  A VGA mode is requested (by number) and the magic VGA mode is NOT
 
1100
 *  matched. A container mode is found or the largest mode is used. The
 
1101
 *  VGA is hardware centered in the container mode. FB contents are
 
1102
 *  output only.
 
1103
 * Scaled VGA
 
1104
 *  A VGA mode is requested (by number) and the magic VGA mode is NOT
 
1105
 *  matched. A fp_native_dtd is found. The VGA image will be scaled to
 
1106
 *  the native timings.
 
1107
 *
 
1108
 *
 
1109
 * The timings returned may be part of a linked list of timings which
 
1110
 * are used by the HAL to perform centering and scaling operations. One
 
1111
 * of the following will result.
 
1112
 *
 
1113
 * Requested Mode
 
1114
 *   The requested mode matched and is returned with no linked modes.
 
1115
 * Munged Requested Mode
 
1116
 *   The requested mode was larger than the requested framebuffer. The
 
1117
 *   timings were then modified to center the framebuffer.
 
1118
 * Native Mode -> Requested Mode
 
1119
 *   The display is fixed resolution and any mode must be scaled to that
 
1120
 *   resolution by the PD. The native mode is returned and linked to the
 
1121
 *   requested mode which will be scaled to fit the native mode. The
 
1122
 *   pt_info will be populated with the requested mode giving the caller
 
1123
 *   the impression that the mode was set natively.
 
1124
 * Native Mode -> Munged Requested Mode
 
1125
 *   The display is fixed resolution and any mode must be scaled to that
 
1126
 *   resolution by the PD. In addition the requested framebuffer is smaller
 
1127
 *   then the requested mode. The native mode is returned and linked to the
 
1128
 *   requested mode which has been modifed to center the framebuffer.
 
1129
 *   The result will be the requested framebuffer scaled to fit the native
 
1130
 *   mode. The pt_info will be populated with the requested mode giving the
 
1131
 *   caller the impression that the mode was set natively.
 
1132
 * VGA Mode -> Magic VGA Mode
 
1133
 *   The requested mode was a legacy VGA mode and the display supports
 
1134
 *   native VGA output. The 720x400 "magic" mode is returned to indicate
 
1135
 *   to the HAL that native VGA should be used. The magic mode is linked
 
1136
 *   to the requested VGA mode.
 
1137
 * Container Mode -> VGA Mode
 
1138
 *   The requested mode was a legacy VGA mode but the display does not
 
1139
 *   support native VGA output. A larger container mode was found and
 
1140
 *   returned. The hardware will center the VGA mode within the container
 
1141
 *   for output. The pt_info will contain the VGA mode giving the caller
 
1142
 *   the impression that the VGA mode was set natively.
 
1143
 * Native Mode -> VGA Mode
 
1144
 *   The requested mode was a legacy VGA mode but the and the PD is
 
1145
 *   set for scaling to a fixed resolution display. The Native mode is
 
1146
 *   returned linked to the VGA mode. The result is the VGA mode scaled to
 
1147
 *   fit the native screen.
 
1148
 *
 
1149
 *   @note: There is a tradeoff to this behavior. If a VGA mode is set and
 
1150
 *   scaled to full-screen there is no guarentee that ALL VGA modes are
 
1151
 *   possible in that configuration. For instance, in DOS if a mode 3 is
 
1152
 *   set (720x400) and scaled full-screen, an application cannot directly
 
1153
 *   program the VGA registers (as many games do) to get an acceptable
 
1154
 *   output at 640x480. This tradeoff is acknoledged and accepted.
 
1155
 *
 
1156
 *
 
1157
 * Assumtions:
 
1158
 *  1) fp_native_dtd is set in all instances where the output is a fixed
 
1159
 *   resolution. (and only those instances)
 
1160
 *  2) PDs timing table contains all modes that can be output or all
 
1161
 *   modes that can be scaled to the native output.
 
1162
 *  3) Scaling PDs can accept a VGA mode to be scaled to the native.
 
1163
 *
 
1164
 * @param display
 
1165
 * @param timing_table
 
1166
 * @param fb_info
 
1167
 * @param pt_info
 
1168
 * @param timing
 
1169
 *
 
1170
 * @return 0
 
1171
 */
 
1172
int match_mode (
 
1173
        igd_display_context_t *display,
 
1174
        igd_timing_info_t *timing_table,
 
1175
        igd_framebuffer_info_t *fb_info,
 
1176
        igd_display_info_t *pt_info,
 
1177
        igd_timing_info_t **timing)
 
1178
{
 
1179
        igd_timing_info_t *match = NULL;
 
1180
        igd_timing_info_t *timing_stack = NULL;
 
1181
 
 
1182
        EMGD_DEBUG("Enter Match Mode");
 
1183
 
 
1184
        EMGD_ASSERT(pt_info, "Null PT Info", -IGD_ERROR_INVAL);
 
1185
        EMGD_ASSERT((pt_info->flags & IGD_MODE_VESA) ||
 
1186
                (pt_info->width && pt_info->height),
 
1187
                "Width and Height are Zero", -IGD_ERROR_INVAL);
 
1188
 
 
1189
        if(MODE_IS_VGA(pt_info)) {
 
1190
                /*
 
1191
                 * The requested mode is a legacy VGA mode
 
1192
                 */
 
1193
                EMGD_DEBUG("Matching a VGA mode");
 
1194
 
 
1195
                /*
 
1196
                 * All VGA modes are possible. Just use a temporary timing
 
1197
                 * block and put the VGA mode number in it. We don't actually
 
1198
                 * use any timing information for VGA modes.
 
1199
                 */
 
1200
                match = &vga_timing[(PIPE(display)->pipe_num)];
 
1201
                match->mode_number = pt_info->mode_number;
 
1202
                match->width = vga_size[pt_info->mode_number].width;
 
1203
                match->height = vga_size[pt_info->mode_number].height;
 
1204
 
 
1205
                push_match(match, &timing_stack);
 
1206
                update_fb_size(match, fb_info);
 
1207
 
 
1208
                /* The caller should think we set the VGA mode directly */
 
1209
                fill_pt(match, pt_info);
 
1210
 
 
1211
                match = match_resolution(display, timing_table, &magic_timing,
 
1212
                        MATCH_WIDTH|MATCH_HEIGHT, 0);
 
1213
                if(match) {
 
1214
                        /*
 
1215
                         * Magic VGA mode was found. This indicates the display can
 
1216
                         * do full native VGA timings. We will send the mode out
 
1217
                         * natively.
 
1218
                         */
 
1219
                        EMGD_DEBUG("Native VGA output");
 
1220
                        push_match(match, &timing_stack);
 
1221
 
 
1222
                        *timing = timing_stack;
 
1223
                        return 0;
 
1224
                }
 
1225
 
 
1226
                /*
 
1227
                 * This display cannot do native VGA. We need to center or
 
1228
                 * scale the VGA to fit.
 
1229
                 */
 
1230
                if(PORT_OWNER(display)->fp_native_dtd) {
 
1231
                        /*
 
1232
                         * Native mode in the port indicates the PD can scale.
 
1233
                         * Push the native mode on the list to get VGA scaled
 
1234
                         * to native.
 
1235
                         */
 
1236
                        EMGD_DEBUG("VGA Scaled to Native");
 
1237
                        push_match(PORT_OWNER(display)->fp_native_dtd, &timing_stack);
 
1238
                } else {
 
1239
                        /*
 
1240
                         * No native mode means the PD is not scaling. Output
 
1241
                         * VGA centered in a safe container mode.
 
1242
                         */
 
1243
                        EMGD_DEBUG("VGA centered in Container");
 
1244
                        match = match_resolution(display, timing_table, pt_info,
 
1245
                                MATCH_FOR_VGA|MATCH_GE_WIDTH|MATCH_GE_HEIGHT|MATCH_FLAGS, 1);
 
1246
                        EMGD_ASSERT(match, "Match Container Failed", -IGD_ERROR_INVAL);
 
1247
 
 
1248
                        push_match(match, &timing_stack);
 
1249
                }
 
1250
 
 
1251
                *timing = timing_stack;
 
1252
                return 0;
 
1253
 
 
1254
        }
 
1255
 
 
1256
        /*
 
1257
         * Regular NON-VGA mode
 
1258
         */
 
1259
        EMGD_DEBUG("Matching a regular NON-VGA mode");
 
1260
 
 
1261
        match = match_resolution(display, timing_table, pt_info,
 
1262
                (pt_info->flags & IGD_MODE_VESA)?
 
1263
                MATCH_NUMBER|MATCH_REFRESH:
 
1264
                MATCH_WIDTH|MATCH_HEIGHT|MATCH_REFRESH|MATCH_FLAGS, 0);
 
1265
        if(match) {
 
1266
                /*
 
1267
                 * Exact match for requested mode was found in the mode table.
 
1268
                 * This mode will be output directly.
 
1269
                 */
 
1270
                EMGD_DEBUG("Input Mode Matched exactly");
 
1271
        } else {
 
1272
                /*
 
1273
                 * Matching mode was not found. This happens for several
 
1274
                 * reasons:
 
1275
                 *
 
1276
                 * 1) We are setting the clone mode but the IAL does not
 
1277
                 *   know the clone width/height. We are just getting the
 
1278
                 *   best guess. In this case fb info is populated.
 
1279
                 * 2) IAL is doing Render Scaling but doesn't know what mode
 
1280
                 *   to scale to. We are getting the best fit. In this case
 
1281
                 *   fb info is all zeros.
 
1282
                 * 3) IAL is just setting random modes and wants something
 
1283
                 *   close. Fb info may or may not be populated.
 
1284
                 */
 
1285
                EMGD_DEBUG("Input Mode NOT matched, container used");
 
1286
                match = match_resolution(display, timing_table, pt_info,
 
1287
                        MATCH_GE_WIDTH|MATCH_GE_HEIGHT|MATCH_FLAGS, 1);
 
1288
                EMGD_ASSERT(match, "Match Container Failed", -IGD_ERROR_INVAL);
 
1289
        }
 
1290
        update_fb_size(match, fb_info);
 
1291
        match = get_centered_timings(display, match, fb_info);
 
1292
        push_match(match, &timing_stack);
 
1293
 
 
1294
        fill_pt(match, pt_info);
 
1295
 
 
1296
        if(PORT_OWNER(display)->fp_native_dtd) {
 
1297
                /*
 
1298
                 * Native DTD indicates that the PD is scaling. Hook the
 
1299
                 * match mode up to the native to get scaling.
 
1300
                 */
 
1301
                EMGD_DEBUG("Input Mode Scaled to Native");
 
1302
                push_match(PORT_OWNER(display)->fp_native_dtd, &timing_stack);
 
1303
        }
 
1304
 
 
1305
 
 
1306
        *timing = timing_stack;
 
1307
        return 0;
 
1308
}
 
1309
 
 
1310
 
 
1311
#endif
 
1312
 
 
1313
 
 
1314
/*----------------------------------------------------------------------------
 
1315
 * File Revision History
 
1316
 * $Id: match.c,v 1.8 2010/07/23 16:54:49 bpaauwe Exp $
 
1317
 * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/display/mode/cmn/match.c,v $
 
1318
 *----------------------------------------------------------------------------
 
1319
 */