~gma500/+junk/emgd152-natty

« back to all changes in this revision

Viewing changes to emgd-dkms-1.5.15.3082/emgd/display/pi/cmn/pi.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: pi.c
 
4
 * $Revision: 1.14 $
 
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
 *  This file contains all the necessary functions for port interface
 
24
 *  module. This module abstracts all hardware port interfaces and
 
25
 *  manages them.
 
26
 *-----------------------------------------------------------------------------
 
27
 */
 
28
 
 
29
#define MODULE_NAME hal.dpd
 
30
 
 
31
#include <config.h>
 
32
#include <igd.h>
 
33
#include <igd_errno.h>
 
34
#include <igd_init.h>
 
35
#include <igd_pwr.h>
 
36
 
 
37
#include <io.h>
 
38
#include <pci.h>
 
39
#include <sched.h>
 
40
#include <memory.h>
 
41
 
 
42
#include <context.h>
 
43
#include <mode.h>
 
44
#include <utils.h>
 
45
#include <dsp.h>
 
46
#include <debug.h>
 
47
#include <pi.h>
 
48
#include <pd.h>
 
49
#include <pd_init.h>
 
50
#include <intelpci.h>
 
51
#include <dispatch.h>
 
52
#include <mode_access.h>
 
53
#include <edid.h>
 
54
#include <displayid.h>
 
55
 
 
56
#include "i2c_dispatch.h"
 
57
#include <igd_vga.h>
 
58
#include <context.h>
 
59
 
 
60
/*!
 
61
 * @addtogroup display_group
 
62
 * @{
 
63
 */
 
64
 
 
65
typedef struct _pi_context {
 
66
        igd_context_t *igd_context;
 
67
        i2c_dispatch_t *i2c_dispatch;
 
68
        unsigned long num_pi_drivers;
 
69
} pi_context_t;
 
70
 
 
71
/* Function to filter the modes using EDID or DisplayID*/
 
72
int get_firmware_timings(igd_display_port_t *port,
 
73
        unsigned char  *firmware_data, pd_timing_t *timing_table);
 
74
 
 
75
int pi_pd_init(igd_display_port_t *port, unsigned long port_feature,
 
76
        unsigned long second_port_feature, int drm_load_time);
 
77
#ifndef CONFIG_MICRO
 
78
unsigned long get_magic_cookie(pd_driver_t *pd_driver);
 
79
#endif
 
80
void assign_dynamic_numbers(igd_timing_info_t *timing_table);
 
81
int update_attrs(igd_display_port_t *port);
 
82
pd_timing_t *get_user_timings(igd_param_dtd_list_t *in_list);
 
83
 
 
84
 
 
85
extern int pi_init_all(void *handle);
 
86
 
 
87
 
 
88
extern i2c_dispatch_t i2c_dispatch_plb;
 
89
extern i2c_dispatch_t i2c_dispatch_tnc;
 
90
 
 
91
int null_func( void )
 
92
{
 
93
        return -IGD_ERROR_NODEV;
 
94
}
 
95
/* Not currently used
 
96
static i2c_dispatch_t i2c_dispatch_null = {
 
97
        (void *)null_func,
 
98
        (void *)null_func,
 
99
        (void *)null_func,
 
100
        (void *)null_func
 
101
}; */
 
102
 
 
103
 
 
104
static dispatch_table_t i2c_dispatch_list[] = {
 
105
 
 
106
#ifdef CONFIG_PLB
 
107
        {PCI_DEVICE_ID_VGA_PLB, &i2c_dispatch_plb},
 
108
#endif
 
109
#ifdef CONFIG_TNC
 
110
        {PCI_DEVICE_ID_VGA_TNC, &i2c_dispatch_tnc},
 
111
#endif
 
112
 
 
113
        {0, NULL}
 
114
};
 
115
 
 
116
static unsigned char firmware_data[256];
 
117
 
 
118
static pi_context_t pi_context[1];
 
119
 
 
120
/*----------------------------------------------------------------------
 
121
 *                        FUNCTION DEFINITIONS
 
122
 *----------------------------------------------------------------------*/
 
123
#ifndef CONFIG_MICRO
 
124
/*!
 
125
 *
 
126
 * @param context
 
127
 *
 
128
 * @return void
 
129
 */
 
130
static void pi_shutdown(igd_context_t *context)
 
131
{
 
132
        igd_display_port_t *port;
 
133
 
 
134
        EMGD_TRACE_ENTER;
 
135
 
 
136
        if (pi_context->igd_context == NULL) {
 
137
                return;
 
138
        }
 
139
 
 
140
        /* Close the port drivers */
 
141
        port = NULL;
 
142
        while ((port = context->mod_dispatch.dsp_get_next_port(context, port, 0)) != NULL) {
 
143
                if (port->pd_driver) {
 
144
                        port->pd_driver->pd_close(port->pd_context);
 
145
                        port->pd_driver = NULL;
 
146
                        /* pd_context is freed by port driver */
 
147
                        port->pd_context = NULL;
 
148
                        port->timing_table = NULL;
 
149
                        port->num_timing = 0;
 
150
                        if (port->fp_info) {
 
151
                                OS_FREE(port->fp_info);
 
152
                                port->fp_info = NULL;
 
153
                        }
 
154
                        if (port->callback) {
 
155
                                OS_FREE(port->callback);
 
156
                                port->callback = NULL;
 
157
                        }
 
158
                }
 
159
        }
 
160
 
 
161
        EMGD_TRACE_EXIT;
 
162
        return;
 
163
}
 
164
 
 
165
/*!
 
166
 *
 
167
 * @param context
 
168
 *
 
169
 * @return 0
 
170
 */
 
171
int pi_full_init(igd_context_t *context)
 
172
{
 
173
        /* Optional Inter-module interfaces */
 
174
        context->mod_dispatch.pi_shutdown = pi_shutdown;
 
175
        return 0;
 
176
}
 
177
 
 
178
#endif
 
179
 
 
180
/*!
 
181
 *
 
182
 * @param context
 
183
 * @param config_info
 
184
 *
 
185
 * @return 0
 
186
 */
 
187
static int pi_get_config_info(igd_context_t *context,
 
188
        igd_config_info_t *config_info)
 
189
{
 
190
        EMGD_TRACE_ENTER;
 
191
 
 
192
        EMGD_ASSERT(context, "Null context", -IGD_ERROR_INVAL);
 
193
        EMGD_ASSERT(config_info, "Null config_info", -IGD_ERROR_INVAL);
 
194
 
 
195
        config_info->num_act_dsp_ports = pi_context->num_pi_drivers;
 
196
 
 
197
        EMGD_TRACE_EXIT;
 
198
        return 0;
 
199
}
 
200
 
 
201
/*!
 
202
 *
 
203
 * @param context
 
204
 *
 
205
 * @return 0
 
206
 */
 
207
int pi_init(igd_context_t *context)
 
208
{
 
209
        i2c_dispatch_t *i2c_dispatch;
 
210
 
 
211
        EMGD_TRACE_ENTER;
 
212
 
 
213
        OS_MEMSET(pi_context, 0, sizeof(pi_context_t));
 
214
 
 
215
        /* Save igd_context in local_igd_context. */
 
216
        pi_context->igd_context = context;
 
217
 
 
218
        /* Get I2C dispatch table */
 
219
        i2c_dispatch = (i2c_dispatch_t *)dispatch_acquire(context,
 
220
                i2c_dispatch_list);
 
221
        if(!i2c_dispatch) {
 
222
                EMGD_DEBUG("No i2c Dispatch available for PI module");
 
223
        }
 
224
        pi_context->i2c_dispatch = i2c_dispatch;
 
225
 
 
226
        /*
 
227
         * If Dynamic Port drivers are not used then init the static drivers
 
228
         * now.
 
229
         */
 
230
#ifndef IGD_DPD_ENABLED
 
231
        {
 
232
                void *handle = NULL;
 
233
                int ret;
 
234
                ret = pi_init_all(handle);
 
235
        }
 
236
#endif
 
237
 
 
238
        /* Inter-module dispatch functions */
 
239
        context->mod_dispatch.i2c_read_regs = i2c_dispatch->i2c_read_regs;
 
240
        context->mod_dispatch.i2c_write_reg_list =
 
241
                i2c_dispatch->i2c_write_reg_list;
 
242
        context->mod_dispatch.pi_get_config_info = pi_get_config_info;
 
243
 
 
244
        OPT_MICRO_CALL(pi_full_init(context));
 
245
 
 
246
        EMGD_TRACE_EXIT;
 
247
        return 0;
 
248
}
 
249
 
 
250
/*!
 
251
 * Get a port with the requested feature set from the list. Don't allocate
 
252
 * it just return it.  Only consider ports that aren't already in use.
 
253
 *
 
254
 * @param feature
 
255
 * @param last
 
256
 *
 
257
 * @return port on success
 
258
 * @return NULL on failure
 
259
 */
 
260
igd_display_port_t *pi_get_feature_port(unsigned long feature,
 
261
        igd_display_port_t *last)
 
262
{
 
263
        igd_display_port_t *port;
 
264
        inter_module_dispatch_t *md = &pi_context->igd_context->mod_dispatch;
 
265
 
 
266
        while ((port = md->dsp_get_next_port(pi_context->igd_context, last, 0))) {
 
267
                if (!port->inuse) {
 
268
                        if (feature) {
 
269
                                if (port->port_features & feature) {
 
270
                                        return port;
 
271
                                }
 
272
                        } else {
 
273
                                return port;
 
274
                        }
 
275
                }
 
276
                last = port;
 
277
        }
 
278
 
 
279
        return NULL;
 
280
}
 
281
 
 
282
/*!
 
283
 * Function to register port driver with display driver
 
284
 *
 
285
 * @param pd_driver
 
286
 *
 
287
 * @return PD_SUCCESS on success
 
288
 * @return PD_ERR_NULL_PTR, PD_ERR_VER_MISMATCH, PD_ERR_DISPLAY_TYPE,
 
289
 *      PD_ERR_NOMEM on failure
 
290
 */
 
291
int pi_pd_register(pd_driver_t *pd_driver)
 
292
{
 
293
        igd_display_port_t *port;
 
294
        igd_param_t *init_params;
 
295
        unsigned long      prev_dab = 0, prev_i2c_speed = 0;
 
296
        unsigned long      port_type, port_feature, second_port_feature = 0;
 
297
        unsigned long      cookie_sent, cookie_rcvd;
 
298
        unsigned long      num_instances = 0;
 
299
        unsigned long      prev_instance_dab = 0, prev_instance_i2c_reg = 0;
 
300
        unsigned long      dab_index = 0;
 
301
        int                ret = PD_SUCCESS;
 
302
 
 
303
        EMGD_TRACE_ENTER;
 
304
 
 
305
        if (!pd_driver) {
 
306
                EMGD_ERROR_EXIT("Null pd_driver received.");
 
307
                return PD_ERR_NULL_PTR;
 
308
        }
 
309
 
 
310
        /* Check the PD SDK version (interface version between main and
 
311
         * port drivers Rightnow this check is useful only for XFree86.
 
312
         * XP and CE already done this checking. */
 
313
        if (pd_driver->pd_sdk_version != PD_SDK_VERSION) {
 
314
                EMGD_ERROR("PD SDK version mismatch between main driver"
 
315
                        "and %s. %u.%u != %u.%u", pd_driver->name,
 
316
                        (unsigned short) PD_SDK_VERSION>>8,
 
317
                        (unsigned short) PD_SDK_VERSION & 0xFF,
 
318
                        (unsigned short) pd_driver->pd_sdk_version>>8,
 
319
                        (unsigned short) pd_driver->pd_sdk_version & 0xFF);
 
320
                return PD_ERR_VER_MISMATCH;
 
321
        }
 
322
 
 
323
        /* Do magic cookie hand shaking */
 
324
#ifndef CONFIG_MICRO
 
325
        cookie_sent = get_magic_cookie(pd_driver);
 
326
#else
 
327
        cookie_sent = 0;
 
328
#endif
 
329
        cookie_rcvd = pd_driver->validate(cookie_sent);
 
330
        if (cookie_sent != cookie_rcvd) {
 
331
                /* TODO: Do this check once we comeup with handshake algorithm. */
 
332
                /*
 
333
                EMGD_ERROR("Error, magic cookie handshaking failed.");
 
334
                return PD_ERR_HAND_SHAKE;
 
335
                */
 
336
        }
 
337
 
 
338
        init_params = pi_context->igd_context->mod_dispatch.init_params;
 
339
 
 
340
        port_feature = 0;
 
341
        /* Get the port features based on the display types */
 
342
        if (pd_driver->type == PD_DISPLAY_CRT) {
 
343
                /* Allocate GMCH onboard CRT port */
 
344
                port_type = IGD_PORT_ANALOG;
 
345
        } else if (pd_driver->type == PD_DISPLAY_LVDS_INT) {
 
346
                /* Allocate GMCH onboard LVDS port */
 
347
                port_type = IGD_PORT_LVDS;
 
348
        } else if (pd_driver->type == PD_DISPLAY_TVOUT_INT) {
 
349
                /* Allocate GMCH onboard TV port */
 
350
                port_type = IGD_PORT_TV;
 
351
        } else if (pd_driver->type &
 
352
                        (PD_DISPLAY_TVOUT |    PD_DISPLAY_FP |      PD_DISPLAY_CRT_EXT |
 
353
                         PD_DISPLAY_LVDS_EXT | PD_DISPLAY_HDMI_EXT| PD_DISPLAY_HDMI_INT|
 
354
                         PD_DISPLAY_DRGB)) {
 
355
 
 
356
                /* Allocate DVO port which is the only kind of port exported to
 
357
                 * 3rd party encoders */
 
358
                port_type = IGD_PORT_DIGITAL;
 
359
 
 
360
                if (pd_driver->flags & PD_FLAG_GANG_MODE) {
 
361
                        igd_display_port_t *portb;
 
362
                        unsigned long user_gang = 0;
 
363
                        /* Get DVO Port B */
 
364
                        pi_context->igd_context->mod_dispatch.dsp_get_display(2,
 
365
                                NULL, &portb, 0);
 
366
                        if(portb) {
 
367
                                if (portb->attr_list && portb->attr_list->num_attrs != 0) {
 
368
                                        unsigned long i;
 
369
                                        for (i = 0; i < portb->attr_list->num_attrs; i++) {
 
370
                                                if (portb->attr_list->attr[i].id==PD_ATTR_ID_GANG_MODE){
 
371
                                                        user_gang = portb->attr_list->attr[i].value;
 
372
                                                }
 
373
                                        }
 
374
                                }
 
375
                        }
 
376
                        /* If both user attribute and port driver flag are set to GANG MODE,
 
377
                         * then allocate a gang display port */
 
378
                        if (user_gang) {
 
379
                                port_feature = IGD_PORT_GANG;
 
380
                                second_port_feature = IGD_PORT_GANG;
 
381
                        }
 
382
                }
 
383
        } else if (pd_driver->type == PD_DISPLAY_RGBA) {
 
384
                port_type = IGD_PORT_DIGITAL;
 
385
                port_feature = IGD_RGBA_COLOR;
 
386
                second_port_feature = IGD_RGBA_ALPHA;
 
387
        } else {
 
388
                EMGD_ERROR_EXIT("Invalid display type.");
 
389
                return PD_ERR_DISPLAY_TYPE;
 
390
        }
 
391
 
 
392
        /* Get the port entry */
 
393
        port = NULL;
 
394
        while((port = pi_get_feature_port(port_feature, port))) {
 
395
                dab_index = 0;
 
396
 
 
397
 
 
398
                /* This port already has a port driver,
 
399
                 * don't search device on this port. */
 
400
                if (port->pd_driver || (port->port_type != port_type)) {
 
401
                        continue;
 
402
                }
 
403
 
 
404
                /* allocate memory for callback */
 
405
                port->callback = (pd_callback_t *)OS_ALLOC(sizeof(pd_callback_t));
 
406
                if (port->callback == NULL) {
 
407
                        EMGD_ERROR_EXIT("Unable to alloc memory for callback context.");
 
408
                        return PD_ERR_NOMEM;
 
409
                }
 
410
                /* Fill entries in pd_callback_t */
 
411
                port->callback->callback_context = port;
 
412
                port->callback->read_regs = pi_read_regs;
 
413
                port->callback->write_regs = pi_write_regs;
 
414
                port->callback->eld = NULL; /* Insert when edid is initialize */
 
415
 
 
416
                /*      SDVO port driver needs the port number */
 
417
                port->callback->port_num = port->port_number;
 
418
 
 
419
                /* now save the pd_driver in port entry */
 
420
                port->pd_driver = pd_driver;
 
421
 
 
422
                /* preference is to user specified i2c_speed */
 
423
                prev_dab = port->dab;
 
424
                prev_i2c_speed = port->i2c_speed;
 
425
                if (!port->i2c_speed) {
 
426
                        port->i2c_speed = pd_driver->i2c_speed?pd_driver->i2c_speed:
 
427
                                I2C_DEFAULT_SPEED;
 
428
                }
 
429
 
 
430
                /* Try detecting the encoder by calling port driver open() */
 
431
                if (port->dab ||
 
432
                        ((port->dab == 0) && (pd_driver->dab_list[0] == PD_DAB_LIST_END))) {
 
433
 
 
434
                        /* Workaround for not to detect 2 encoders if only 1 encoder
 
435
                         * is present and both DVOB and DVOC are using same I2C bus */
 
436
                        if ((init_params->display_flags & IGD_DISPLAY_MULTI_DVO) &&
 
437
                                (num_instances > 0) &&
 
438
                                (prev_instance_dab == port->dab) &&
 
439
                                (prev_instance_i2c_reg == port->i2c_reg)) {
 
440
                                /* Print this msg, because user explicitly mentioned DAB/I2C
 
441
                                 * bus details which are same as previous encoder's DAB/I2C bus
 
442
                                 * details. */
 
443
                                EMGD_DEBUG("1+ encoders have same I2C bus and DAB");
 
444
                                ret = -1;
 
445
                        } else {
 
446
                                /* Call open() only once if either user provides a DAB
 
447
                                 *                      or
 
448
                                 * no required to open an encoder. ex: analog, rgba, lvds etc.
 
449
                                 */
 
450
                                EMGD_DEBUG("Looking for \"%s\" on port 0x%lx with DAB 0x%lx",
 
451
                                        pd_driver->name, port->port_reg, port->dab);
 
452
                                ret = pd_driver->open(port->callback, &(port->pd_context));
 
453
                        }
 
454
                } else {
 
455
 
 
456
                        /* Call open() for each DAB */
 
457
                        while (pd_driver->dab_list[dab_index] != PD_DAB_LIST_END) {
 
458
                                port->dab = pd_driver->dab_list[dab_index];
 
459
 
 
460
                                /* Workaround for not to detect 2 encoders if only 1 encoder
 
461
                                 * is present and both DVOB and DVOC are using same I2C bus */
 
462
                                if ((init_params->display_flags & IGD_DISPLAY_MULTI_DVO) &&
 
463
                                        (num_instances > 0) &&
 
464
                                        (prev_instance_dab == port->dab) &&
 
465
                                        (prev_instance_i2c_reg == port->i2c_reg)) {
 
466
                                        /* Don't print the debug msg, because this is a valid case.
 
467
                                         * Example,
 
468
                                         *    Algorithm is detecting for multiple encoders with
 
469
                                         *    same DAB and same I2C bus on different ports.
 
470
                                         * If this case arises, simply continue
 
471
                                         */
 
472
                                        /* EMGD_DEBUG("1+ encoders have same I2C bus and DAB"); */
 
473
                                        if (pd_driver->flags & PD_FLAG_DUAL_DVO) {
 
474
                                                /* If this flag is set, that means port driver is
 
475
                                                 * explicityly requesting to be loaded on
 
476
                                                 * both DVO B & DVO C with same DAB. Example: CH7017.
 
477
                                                 *
 
478
                                                 * In this case open the port driver again. */
 
479
                                        } else {
 
480
                                                ret = -1;
 
481
                                                port->pd_context = NULL;
 
482
                                                dab_index++;
 
483
                                                continue;
 
484
                                        }
 
485
                                }
 
486
 
 
487
                                EMGD_DEBUG("Looking for \"%s\" on port 0x%lx with DAB 0x%lx",
 
488
                                        pd_driver->name, port->port_reg, port->dab);
 
489
                                ret = pd_driver->open(port->callback, &(port->pd_context));
 
490
                                if (ret == 0) {
 
491
                                        break;
 
492
                                } else {
 
493
 
 
494
                                        dab_index++;
 
495
                                }
 
496
                        }
 
497
                }
 
498
#ifndef CONFIG_MICRO
 
499
                if(pi_context->igd_context->mod_dispatch.check_port_supported && ret == 0){
 
500
                        ret = pi_context->igd_context->mod_dispatch.check_port_supported(port);
 
501
                }
 
502
#endif
 
503
                if (ret == 0) {
 
504
 
 
505
                        /* Initialize our port entry */
 
506
                        ret = pi_pd_init(port, port_feature, second_port_feature, TRUE);
 
507
                        if (ret) {
 
508
                                port->pd_driver = NULL;
 
509
                                port->pd_context = NULL;
 
510
                                port->dab = prev_dab;
 
511
                                port->i2c_speed = prev_i2c_speed;
 
512
                                port->mult_port = NULL;
 
513
                                port->timing_table = NULL;
 
514
                                port->num_timing = 0;
 
515
                                if (port->callback) {
 
516
                                        OS_FREE(port->callback);
 
517
                                        port->callback = NULL;
 
518
                                }
 
519
                        } else {
 
520
                                EMGD_DEBUG("Device found on %s port for \"%s\"", port->port_name,
 
521
                                        pd_driver->name);
 
522
                                num_instances++;
 
523
                                prev_instance_dab = port->dab;
 
524
                                prev_instance_i2c_reg = port->i2c_reg;
 
525
                        }
 
526
 
 
527
                        /* If Multi-DVO support is enabled then detect next encoder of
 
528
                         * same kind */
 
529
                        if (init_params->display_flags & IGD_DISPLAY_MULTI_DVO){
 
530
                                /* Continue to find next encoder */
 
531
                                continue;
 
532
                        } else {
 
533
                                /* Found one encoder and return to port driver */
 
534
                                break;
 
535
                        }
 
536
                } else {
 
537
                        port->pd_driver = NULL;
 
538
                        port->pd_context = NULL;
 
539
                        port->dab = prev_dab;
 
540
                        port->i2c_speed = prev_i2c_speed;;
 
541
                        if (port->callback) {
 
542
                                OS_FREE(port->callback);
 
543
                                port->callback = NULL;
 
544
                        }
 
545
                }
 
546
        } /* end while(port == feature_port()) */
 
547
 
 
548
        if (num_instances == 0) {
 
549
                EMGD_DEBUG("No device found for \"%s\"", pd_driver->name);
 
550
                return PD_ERR_NOPORT_AVAIL;
 
551
        }
 
552
 
 
553
        EMGD_TRACE_EXIT;
 
554
        return PD_SUCCESS;
 
555
} /* end pi_pd_register() */
 
556
 
 
557
/* Function to replace common timings in 1st list with 2nd list, 2nd list
 
558
 * is unchanged. */
 
559
void replace_common_dtds(igd_timing_info_t *dtds1,
 
560
        igd_timing_info_t *dtds2)
 
561
{
 
562
        igd_timing_info_t *temp;
 
563
        int index;
 
564
 
 
565
        if (!dtds2 || !dtds1) {
 
566
                return;
 
567
        }
 
568
 
 
569
        while (dtds1->width != IGD_TIMING_TABLE_END) {
 
570
                temp = dtds2;
 
571
                index = 0;
 
572
 
 
573
                while (temp->width != IGD_TIMING_TABLE_END && index < NUM_TIMINGS) {
 
574
                        /* Replace modes that have common width, height and
 
575
                           refresh rate. Removed Dot clock comparison since
 
576
                           EDID(CEA modes) may differ in dot clock value.
 
577
                           causing duplicate mode.
 
578
                           All ial would do a match  mode by height, width
 
579
                           and refresh rate.
 
580
                        */
 
581
                        if ((temp->width   == dtds1->width) &&
 
582
                                (temp->height  == dtds1->height) &&
 
583
                                (temp->refresh == dtds1->refresh) &&
 
584
                                ((temp->mode_info_flags & PD_SCAN_INTERLACE) ==
 
585
                                 (dtds1->mode_info_flags & PD_SCAN_INTERLACE))) {
 
586
                                dtds1->mode_info_flags &= ~PD_MODE_SUPPORTED;
 
587
                        }
 
588
                        temp++;
 
589
                        index++;
 
590
                }
 
591
                dtds1++;
 
592
        }
 
593
}
 
594
 
 
595
/*!
 
596
 *
 
597
 * @param port
 
598
 *
 
599
 * @return 0
 
600
 */
 
601
int check_port_attrs(igd_display_port_t *port)
 
602
{
 
603
        int          ret;
 
604
        unsigned long         attr_value = 0;
 
605
#ifndef CONFIG_MICRO
 
606
        pd_attr_t             out_list,*temp_list;
 
607
        temp_list = &out_list;
 
608
#endif
 
609
        /* Attempt to see if the port driver has this attibutes so it can update
 
610
          the port driver value. For now this is required for internal HDMI which
 
611
          has a different i2c bus and port name from the standard SDVO port driver.
 
612
          DP would most likely use this attribute assuming it uese the same port
 
613
          number as well*/
 
614
        ret = pi_pd_find_attr_and_value(port, PD_ATTR_ID_PORT_DDC_REG,
 
615
                PD_ATTR_FLAG_GENERAL, NULL, &attr_value);
 
616
        if(!ret){
 
617
                EMGD_DEBUG("ddr_reg value unique = %ld.", attr_value);
 
618
                port->ddc_reg = attr_value;
 
619
        }
 
620
#ifndef CONFIG_MICRO
 
621
        ret = pi_pd_find_attr_and_value(port, PD_ATTR_ID_PORT_NAME,
 
622
                PD_ATTR_FLAG_GENERAL, &(temp_list), &attr_value);
 
623
        if(!ret){
 
624
                EMGD_DEBUG("ddr_reg value unique = %ld.", attr_value);
 
625
                pd_strcpy(port->port_name, temp_list->name);
 
626
        }
 
627
#endif
 
628
        return 0;
 
629
 
 
630
}
 
631
 
 
632
/*!
 
633
 * Function to initialize port driver related members in port table entry
 
634
 *
 
635
 * @param port
 
636
 * @param port_feature
 
637
 * @param second_port_feature
 
638
 * @param drm_load_time
 
639
 *
 
640
 * @return PD_SUCCESS on success
 
641
 * @return 1 on failure
 
642
 */
 
643
int pi_pd_init(igd_display_port_t *port,
 
644
        unsigned long port_feature,
 
645
        unsigned long second_port_feature,
 
646
        int drm_load_time)
 
647
{
 
648
        igd_display_port_t *second_port;
 
649
        pd_timing_t        *user_timings = NULL;
 
650
        pd_timing_t        *std_timings = NULL;
 
651
        pd_timing_t        *firmware_timings = NULL;
 
652
        pd_timing_t        *final_timings = NULL;
 
653
        pd_timing_t        *pd_timing_table = NULL;
 
654
        mode_state_t       *mstate;
 
655
        int                i, ret = PD_SUCCESS;
 
656
        unsigned long      edid_flags;
 
657
        unsigned char      num_firmware_timings = 0;
 
658
        igd_display_params_t *display_params = NULL;
 
659
        igd_param_t *init_params;
 
660
 
 
661
        EMGD_TRACE_ENTER;
 
662
 
 
663
        mstate = NULL;
 
664
 
 
665
        /* If the display device is a ganged mode device or RGBA mode, then hook
 
666
         * up second port pointer in first port */
 
667
        if (second_port_feature) {
 
668
                second_port = pi_get_feature_port(second_port_feature, port);
 
669
 
 
670
                /* If second_port is N/A, or second port was already taken by
 
671
                 * other port driver, then release main port and return error */
 
672
                if (second_port == NULL || second_port->pd_driver) {
 
673
                        EMGD_ERROR_EXIT("Second ganged/RGBA port N/A or already allocated.");
 
674
                        return PD_ERR_NOPORT_AVAIL;
 
675
                }
 
676
                /* now link second port to first one */
 
677
                port->mult_port = second_port;
 
678
        }
 
679
 
 
680
        /* Check port attributes to overwrite port value is any available */
 
681
        check_port_attrs(port);
 
682
        /* Implementation notes to get the timing list:
 
683
         *   Any port timing table consists of
 
684
         *          EDID DTDS
 
685
         *          USER DTDS
 
686
         *          STD TIMINGS
 
687
         *   based on edid_flags.
 
688
         *
 
689
         * If there are no flags, then it defaults to use STD TIMINGS + EDID DTDs
 
690
         */
 
691
 
 
692
        /* Get the display params for this port */
 
693
        init_params = pi_context->igd_context->mod_dispatch.init_params;
 
694
 
 
695
        for (i = 0; i < 5; i++) {
 
696
                if (port->port_number == init_params->display_params[i].port_number) {
 
697
                        display_params = &init_params->display_params[i];
 
698
                        break;
 
699
                }
 
700
        }
 
701
 
 
702
        /* Start with STD TIMINGS */
 
703
        edid_flags = IGD_DISPLAY_USE_STD_TIMINGS;
 
704
 
 
705
        /* If there is EDID, then default to use EDID */
 
706
        if (!display_params || (display_params->flags & IGD_DISPLAY_READ_EDID)) {
 
707
                /* Read firmware (EDID/DisplayID) on I2C */
 
708
                ret = pi_context->i2c_dispatch->i2c_read_regs(
 
709
                        pi_context->igd_context,
 
710
                        port->ddc_reg,      /* DDC register */
 
711
                        port->ddc_speed,    /* DDC speed */
 
712
                        port->ddc_dab,      /* Data Addr Byte*/
 
713
                        0,                  /* Register */
 
714
                        firmware_data,      /* Values */
 
715
                        128);               /* Num bytes to read */
 
716
 
 
717
                /* If EDID is present then use EDID.
 
718
                 * edid_flags will be corrected later if display_params are present */
 
719
                if (ret == 0) {
 
720
                        edid_flags |= IGD_DISPLAY_USE_EDID;
 
721
                }
 
722
        }
 
723
 
 
724
        /* Check for display params */
 
725
        if (display_params) {
 
726
                if (edid_flags & IGD_DISPLAY_USE_EDID) {
 
727
                        /* Adjust edid_flags to use edid_avail
 
728
                         * if both edid is present and edid_avail is not 0 */
 
729
                        if (display_params->edid_avail) {
 
730
                                edid_flags = display_params->edid_avail;
 
731
                                EMGD_DEBUG("EDID_Avail: 0x%lx", edid_flags);
 
732
                        }
 
733
                } else {
 
734
                        /* Adjust edid_flags to use edid_not_avail
 
735
                         * if edid is not present and edid_not_avail is not 0 */
 
736
                        if (display_params->edid_not_avail) {
 
737
                                edid_flags =
 
738
                                        display_params->edid_not_avail & ~IGD_DISPLAY_USE_EDID;
 
739
                                EMGD_DEBUG("EDID_Not_Avail: 0x%lx", edid_flags);
 
740
                        }
 
741
                }
 
742
        }
 
743
 
 
744
        /* Make a copy of crt_timing_table */
 
745
        /* All crt timings are already enabled in mode_table.c */
 
746
        std_timings = (igd_timing_info_t *) OS_ALLOC(crt_timing_table_size);
 
747
        OS_MEMCPY(std_timings, crt_timing_table, crt_timing_table_size);
 
748
 
 
749
        /* Include Standard built-in modes */
 
750
        if (edid_flags & IGD_DISPLAY_USE_STD_TIMINGS) {
 
751
                EMGD_DEBUG("Using STD TIMINGS ");
 
752
                final_timings = std_timings;
 
753
        }
 
754
 
 
755
        /* Include user DTDs */
 
756
        if (edid_flags & IGD_DISPLAY_USE_USERDTDS) {
 
757
                EMGD_DEBUG("Using USER-DTDs ");
 
758
                user_timings = get_user_timings(port->dtd_list);
 
759
 
 
760
                if (user_timings) {
 
761
                        /* Add user DTDs at the begining of the final timings */
 
762
                        user_timings[port->dtd_list->num_dtds].extn_ptr = final_timings;
 
763
                        final_timings = user_timings;
 
764
                }
 
765
        }
 
766
 
 
767
        /* Include EDID timings and filter modes */
 
768
        if (edid_flags & IGD_DISPLAY_USE_EDID) {
 
769
                EMGD_DEBUG("Using EDID-DTDs ");
 
770
                ret = get_firmware_timings(port, firmware_data, final_timings);
 
771
                if (port->firmware_type == PI_FIRMWARE_EDID) {
 
772
                        firmware_timings = port->edid->timings;
 
773
                        num_firmware_timings = port->edid->num_timings;
 
774
                } else if (port->firmware_type == PI_FIRMWARE_DISPLAYID) {
 
775
                        firmware_timings = port->displayid->timings;
 
776
                        num_firmware_timings = port->displayid->num_timings;
 
777
                }
 
778
                if (ret == 0 && num_firmware_timings) {
 
779
                        /* Add EDID DTDs at the begining of the final timings */
 
780
                        firmware_timings[num_firmware_timings].extn_ptr =
 
781
                                (void *)final_timings;
 
782
                        final_timings = firmware_timings;
 
783
                }
 
784
        }
 
785
 
 
786
        /* Replace any common timings */
 
787
        replace_common_dtds(std_timings, firmware_timings);
 
788
        replace_common_dtds(std_timings, user_timings);
 
789
        replace_common_dtds(firmware_timings, user_timings);
 
790
 
 
791
        /* Count the number of timings in final_timings.  If the above functions
 
792
         * result in an empty timing list, then use std_timings as default.
 
793
         */
 
794
        if (!get_native_dtd(final_timings, PI_SUPPORTED_TIMINGS, NULL, 0)) {
 
795
                EMGD_DEBUG("User options resulted in 0 timings; using std timings.");
 
796
                final_timings = std_timings;
 
797
                enable_disable_timings(final_timings, 1);
 
798
        }
 
799
 
 
800
        /* Update port driver attributes */
 
801
        update_attrs(port);
 
802
 
 
803
        /* Now get the timing list filtered by PORT DRIVER */
 
804
        ret = port->pd_driver->get_timing_list(port->pd_context,
 
805
                        final_timings, &pd_timing_table);
 
806
 
 
807
        if (ret || !pd_timing_table) {
 
808
                EMGD_ERROR_EXIT("port driver: get timing list error.");
 
809
                return PD_ERR_NO_TIMINGS;
 
810
        }
 
811
 
 
812
        /* Delete temporary lists and buffers */
 
813
        if (user_timings) {
 
814
                OS_FREE(user_timings);
 
815
        }
 
816
        if (std_timings) {
 
817
                OS_FREE(std_timings);
 
818
        }
 
819
 
 
820
        /* Filter modes based on chipset type */
 
821
        pi_context->igd_context->mod_dispatch.filter_modes(pi_context->igd_context,
 
822
                port, pd_timing_table);
 
823
 
 
824
        /* Now save the timings in port */
 
825
        port->timing_table = pd_timing_table;
 
826
        port->num_timing = get_native_dtd(pd_timing_table,
 
827
                        PI_SUPPORTED_TIMINGS, &port->fp_native_dtd, PD_MODE_DTD_FP_NATIVE);
 
828
 
 
829
        assign_dynamic_numbers(port->timing_table);
 
830
 
 
831
#ifdef DEBUG_FIRMWARE
 
832
        {
 
833
                int ti;
 
834
                EMGD_DEBUG("Supported timings for \"%s\" (%lu)",
 
835
                        port->pd_driver->name, port->num_timing);
 
836
                ti = 0;
 
837
                while (port->timing_table[ti].width != PD_TIMING_LIST_END) {
 
838
                        if (port->timing_table[ti].mode_info_flags & PD_MODE_SUPPORTED) {
 
839
                                EMGD_DEBUG("\t%ux%u@%u dclk=%lu mode_num=%d hsync=%luKHz "
 
840
                                                        "vsync=%luHz flags=0x%lx",
 
841
                                        port->timing_table[ti].width,
 
842
                                        port->timing_table[ti].height,
 
843
                                        port->timing_table[ti].refresh,
 
844
                                        port->timing_table[ti].dclk,
 
845
                                        port->timing_table[ti].mode_number,
 
846
                                        port->timing_table[ti].dclk/port->timing_table[ti].htotal,
 
847
                                        ((port->timing_table[ti].dclk * 1000)/
 
848
                                        port->timing_table[ti].htotal)/
 
849
                                        port->timing_table[ti].vtotal,
 
850
                                        port->timing_table[ti].mode_info_flags);
 
851
                        }
 
852
                        ti++;
 
853
                }
 
854
        }
 
855
#endif
 
856
 
 
857
 
 
858
        /*
 
859
         * Exit early when called by emgd_driver_pre_init to poke the X driver's
 
860
         * (i.e. "xorg.conf") DTDs and attr's into the port drivers (done above).
 
861
         */
 
862
        if (!drm_load_time) {
 
863
                EMGD_TRACE_EXIT;
 
864
                return PD_SUCCESS;
 
865
        }
 
866
 
 
867
 
 
868
#ifndef CONFIG_MICRO
 
869
        if(pi_context->igd_context->mod_dispatch.reg_get_mod_state) {
 
870
                module_state_h     *state = NULL;
 
871
                unsigned long *flags = NULL;
 
872
                pi_context->igd_context->mod_dispatch.reg_get_mod_state(
 
873
                        REG_MODE_STATE,
 
874
                        &state,
 
875
                        &flags);
 
876
 
 
877
                if (state) {
 
878
                        mstate = (mode_state_t *)(*state);
 
879
                }
 
880
        }
 
881
 
 
882
        /* If mode state is present in register context,
 
883
         * then call save() function to save the port driver's state */
 
884
        if (mstate) {
 
885
                ret = port->pd_driver->pd_save(port->pd_context,
 
886
                                &(mstate->pd_state[pi_context->num_pi_drivers].state), 0);
 
887
                if (ret) {
 
888
                        EMGD_ERROR_EXIT("port driver: reg saving error. ret = %d", ret);
 
889
                        return ret;
 
890
                }
 
891
                mstate->pd_state[pi_context->num_pi_drivers].port = port;
 
892
        }
 
893
#endif
 
894
 
 
895
        if(port->displayid != NULL){
 
896
                /* Driver to init audio if cea extension available */
 
897
                if(port->firmware_type == PI_FIRMWARE_EDID){
 
898
                        port->callback->eld = &(port->edid->cea);
 
899
                }
 
900
                /* Displayid unsupported for now. Uncomment this code when audio
 
901
                information is available for Display ID
 
902
                else if(port->firmware_type == PI_FIRMWARE_EDID){
 
903
                        port->callback->eld = &(port->displayid->cea);
 
904
                }
 
905
                */
 
906
                else{
 
907
                        port->callback->eld = NULL;
 
908
                }
 
909
        }
 
910
        ret = port->pd_driver->init_device(port->pd_context);
 
911
        if (ret) {
 
912
#ifndef CONFIG_MICRO
 
913
                /* TODO: Restore the pd state? */
 
914
                EMGD_ERROR_EXIT("port driver: init_device error. ret = %d", ret);
 
915
                if (mstate) {
 
916
                        mstate->pd_state[pi_context->num_pi_drivers].port = NULL;
 
917
                        mstate->pd_state[pi_context->num_pi_drivers].state = NULL;
 
918
                }
 
919
#endif
 
920
                return ret;
 
921
        }
 
922
 
 
923
        /* Increment the number of port drivers */
 
924
        pi_context->num_pi_drivers++;
 
925
 
 
926
        /* save the port driver display type & flags in port. These additions are
 
927
         * required to support different types displays by same port driver. */
 
928
        port->pd_type = port->pd_driver->type;
 
929
        port->pd_flags = port->pd_driver->flags;
 
930
 
 
931
        EMGD_TRACE_EXIT;
 
932
        return PD_SUCCESS;
 
933
} /* end pi_pd_init */
 
934
 
 
935
/*!
 
936
 * Function to read registers
 
937
 *
 
938
 * @param context
 
939
 * @param list
 
940
 * @param type
 
941
 *
 
942
 * @return PD_SUCCESS on success
 
943
 * @return PD_ERR_NULL_PTR, PD_ERR_I2C_READ, PD_ERR_UNSUCCESSFUL on failure
 
944
 */
 
945
int pi_read_regs(void *callback_context, pd_reg_t *list, unsigned long type)
 
946
{
 
947
        int ret;
 
948
        igd_display_port_t *port = callback_context;
 
949
        unsigned char      *mmio;
 
950
 
 
951
        /*EMGD_TRACE_EXIT;*/
 
952
 
 
953
        if (!port) {
 
954
                EMGD_ERROR_EXIT("Null callback context passed.");
 
955
                return PD_ERR_NULL_PTR;
 
956
        }
 
957
 
 
958
        if (!port->pd_driver) {
 
959
                EMGD_ERROR_EXIT("Null pd_driver in port entry.");
 
960
                return PD_ERR_NULL_PTR;
 
961
        }
 
962
 
 
963
        mmio = EMGD_MMIO(pi_context->igd_context->device_context.virt_mmadr);
 
964
 
 
965
        /* Based on the port type either read GMCH registers or I2C registers */
 
966
        switch (type) {
 
967
        case PD_REG_I2C:
 
968
                ret = 0;
 
969
                while (list->reg != PD_REG_LIST_END) {
 
970
                        ret = pi_context->i2c_dispatch->i2c_read_regs(
 
971
                                pi_context->igd_context,
 
972
                                port->i2c_reg,
 
973
                                port->i2c_speed,
 
974
                                port->dab,
 
975
                                (unsigned char)list->reg,
 
976
                                (unsigned char *)&list->value, 1);
 
977
                        if (ret) {
 
978
                                EMGD_DEBUG("i2c_read_reg: 0x%lx failed.", list->reg);
 
979
                                break;
 
980
                        }
 
981
                        list++;
 
982
                }
 
983
                if (ret) {
 
984
                        return PD_ERR_I2C_READ;
 
985
                }
 
986
                break;
 
987
        case PD_REG_DDC:
 
988
                ret = 0;
 
989
                while (list->reg != PD_REG_LIST_END) {
 
990
                        ret = pi_context->i2c_dispatch->i2c_read_regs(
 
991
                                pi_context->igd_context,
 
992
                                port->ddc_reg,
 
993
                                port->ddc_speed,
 
994
                                port->ddc_dab,
 
995
                                (unsigned char)list->reg,
 
996
                                (unsigned char *)&list->value, 1);
 
997
                        if (ret) {
 
998
                                EMGD_DEBUG("i2c_read_reg: 0x%lx failed.", list->reg);
 
999
                                break;
 
1000
                        }
 
1001
                        list++;
 
1002
                }
 
1003
                if (ret) {
 
1004
                        return PD_ERR_I2C_READ;
 
1005
                }
 
1006
                break;
 
1007
        case PD_REG_PIO8:
 
1008
                while (list->reg != PD_REG_LIST_END) {
 
1009
                        list->value = EMGD_READ_PORT8(list->reg);
 
1010
                        list++;
 
1011
                }
 
1012
                break;
 
1013
        case PD_REG_PIO16:
 
1014
                while (list->reg != PD_REG_LIST_END) {
 
1015
                        list->value = EMGD_READ_PORT16(list->reg);
 
1016
                        list++;
 
1017
                }
 
1018
                break;
 
1019
        case PD_REG_PIO32:
 
1020
                while (list->reg != PD_REG_LIST_END) {
 
1021
                        list->value = EMGD_READ_PORT32(list->reg);
 
1022
                        list++;
 
1023
                }
 
1024
                break;
 
1025
        case PD_REG_MIO :
 
1026
        case PD_REG_MIO8 :
 
1027
                if ((port->port_type == IGD_PORT_ANALOG) ||
 
1028
                        (port->port_type == IGD_PORT_TV)     ||  /* For Integrated TV */
 
1029
                        (port->port_type == IGD_PORT_LVDS)       ||
 
1030
                        (port->port_type == IGD_PORT_DIGITAL)) {
 
1031
                        while (list->reg != PD_REG_LIST_END) {
 
1032
                                if (type == PD_REG_MIO) {
 
1033
                                        if (BIT31 & list->reg) {
 
1034
#ifdef CONFIG_TNC
 
1035
                                                /* Atom E6xx si hack: Si folks defined LVDS (0:2:0)
 
1036
                                                 * related register in 0:3:0 (sdvo device) as they
 
1037
                                                 * are afraid to touch Lincroft hardmacro.
 
1038
                                                 * This triggered LVDS port driver to touch 0:3:0
 
1039
                                                 * registers for its operation. As this is done for
 
1040
                                                 * LVDS operation and LVDS port driver is internal,
 
1041
                                                 * BIT31 is defined to access 0:3:0 device. */
 
1042
                                                list->value = READ_MMIO_REG_TNC(IGD_PORT_SDVO,
 
1043
                                                        list->reg);
 
1044
#endif
 
1045
                                        } else {
 
1046
                                                list->value = EMGD_READ32(EMGD_MMIO(mmio) + list->reg);
 
1047
                                        }
 
1048
                                } else {
 
1049
                                        list->value = EMGD_READ8(EMGD_MMIO(mmio) + list->reg);
 
1050
                                }
 
1051
                                list++;
 
1052
                        }
 
1053
                }
 
1054
                break;
 
1055
#ifdef CONFIG_TNC
 
1056
        case PD_REG_LPC:
 
1057
                if (port->port_type == IGD_PORT_LVDS) {
 
1058
                        while (list->reg != PD_REG_LIST_END) {
 
1059
                                list->value = READ_MMIO_REG_TNC(IGD_PORT_LPC, list->reg);
 
1060
                                list++;
 
1061
                        }
 
1062
                }
 
1063
                break;
 
1064
#endif
 
1065
        case PD_REG_PCI:
 
1066
                /* Rightnow this is only to provide the device id */
 
1067
                while (list->reg != PD_REG_LIST_END) {
 
1068
#if 0
 
1069
                        /* Assume IGD at bus=0, dev=2, func=0 */
 
1070
                        EMGD_WRITE_PORT32(0xCF8,
 
1071
                                (0x80000000 | (0L << 16) | (2L << 11) | (0L << 8) |
 
1072
                                        (list->reg & 0xFC)));
 
1073
                        list->value = EMGD_READ_PORT32(0xCFC + (list->reg & 0x03));
 
1074
#endif
 
1075
                        list->value = pi_context->igd_context->device_context.did;
 
1076
                        list++;
 
1077
                }
 
1078
                break;
 
1079
        case PD_REG_BRIDGE_OPCODE:
 
1080
                /* right now, we only return the graphics frequency to calculate the
 
1081
                 * PWM Backlight modulation frequency. This is only available for pouslbo */
 
1082
                while (list->reg != PD_REG_LIST_END) {
 
1083
                        list->value = pi_context->igd_context->device_context.gfx_freq;
 
1084
                        list++;
 
1085
                }
 
1086
 
 
1087
                break;
 
1088
        default:
 
1089
                EMGD_ERROR_EXIT("Unknown reg type (0x%lx).", type);
 
1090
                return PD_ERR_UNSUCCESSFUL;
 
1091
                break;
 
1092
        }
 
1093
 
 
1094
        /*EMGD_TRACE_EXIT;*/
 
1095
        return PD_SUCCESS;
 
1096
} /* end pi_read_regs */
 
1097
 
 
1098
/*!
 
1099
 * Function to write registers
 
1100
 *
 
1101
 * @param context
 
1102
 * @param list
 
1103
 * @param type
 
1104
 *
 
1105
 * @return 0 on success
 
1106
 * @return PD_ERR_NULL_PTR, PD_ERR_I2C_WRITE, PD_ERR_UNSUCCESSFUL on failure
 
1107
 */
 
1108
extern unsigned short io_base_sdvo;
 
1109
extern unsigned short io_base;
 
1110
 
 
1111
int pi_write_regs(void *callback_context, pd_reg_t *list, unsigned long type)
 
1112
{
 
1113
        igd_display_port_t *port = callback_context;
 
1114
        int           ret;
 
1115
        unsigned char *mmio;
 
1116
 
 
1117
        /*EMGD_TRACE_ENTER;*/
 
1118
 
 
1119
        if (!port) {
 
1120
                EMGD_ERROR_EXIT("Null callback context passed.");
 
1121
                return PD_ERR_NULL_PTR;
 
1122
        }
 
1123
 
 
1124
        if (!port->pd_driver) {
 
1125
                EMGD_ERROR_EXIT("Null pd_driver.");
 
1126
                return PD_ERR_NULL_PTR;
 
1127
        }
 
1128
 
 
1129
        mmio = EMGD_MMIO(pi_context->igd_context->device_context.virt_mmadr);
 
1130
 
 
1131
        /* Based on the port type either write GMCH registers or I2C registers */
 
1132
        switch (type) {
 
1133
        case PD_REG_I2C:
 
1134
                ret = pi_context->i2c_dispatch->i2c_write_reg_list(
 
1135
                        pi_context->igd_context,
 
1136
                        port->i2c_reg,
 
1137
                        port->i2c_speed,
 
1138
                        port->dab,
 
1139
                        list,
 
1140
                        0);
 
1141
                if (ret) {
 
1142
                        EMGD_DEBUG("i2c_write_reg: 0x%lx = 0x%lx failed.",
 
1143
                                list->reg, list->value);
 
1144
                        return PD_ERR_I2C_WRITE;
 
1145
                }
 
1146
                break;
 
1147
        case PD_REG_PIO8:
 
1148
                while (list->reg != PD_REG_LIST_END) {
 
1149
                        EMGD_WRITE_PORT8(list->reg, list->value);
 
1150
                        list++;
 
1151
                }
 
1152
                break;
 
1153
        case PD_REG_PIO16:
 
1154
                while (list->reg != PD_REG_LIST_END) {
 
1155
                        EMGD_WRITE_PORT16(list->reg, list->value);
 
1156
                        list++;
 
1157
                }
 
1158
                break;
 
1159
        case PD_REG_PIO32:
 
1160
                while (list->reg != PD_REG_LIST_END) {
 
1161
                        EMGD_WRITE_PORT32(list->reg, list->value);
 
1162
                        list++;
 
1163
                }
 
1164
                break;
 
1165
        case PD_REG_MIO :
 
1166
        case PD_REG_MIO8 :
 
1167
                if ((port->port_type == IGD_PORT_ANALOG) ||
 
1168
                        (port->port_type == IGD_PORT_TV)     ||  /* For Integrated TV */
 
1169
                        (port->port_type == IGD_PORT_LVDS)       ||
 
1170
                        (port->port_type == IGD_PORT_DIGITAL)) {
 
1171
                        while (list->reg != PD_REG_LIST_END) {
 
1172
                                if (type == PD_REG_MIO) {
 
1173
                                        if (BIT31 & list->reg) {
 
1174
#ifdef CONFIG_TNC
 
1175
                                                /* BIT31 indicates write to 0:3:0 SDVO device */
 
1176
                                                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, list->reg,
 
1177
                                                        list->value);
 
1178
#endif
 
1179
                                        } else {
 
1180
                                                EMGD_WRITE32(list->value, EMGD_MMIO(mmio) + list->reg);
 
1181
                                        }
 
1182
                                } else {
 
1183
                                        EMGD_WRITE8(list->value, EMGD_MMIO(mmio) + list->reg);
 
1184
                                }
 
1185
                                list++;
 
1186
                        }
 
1187
                }
 
1188
                break;
 
1189
#ifdef CONFIG_TNC
 
1190
        case PD_REG_LPC:
 
1191
                if (port->port_type == IGD_PORT_LVDS) {
 
1192
                        while (list->reg != PD_REG_LIST_END) {
 
1193
                                WRITE_MMIO_REG_TNC(IGD_PORT_LPC, list->reg, list->value);
 
1194
                                list++;
 
1195
                        }
 
1196
                }
 
1197
                break;
 
1198
#endif
 
1199
        default:
 
1200
                EMGD_ERROR_EXIT("Unknown reg type (0x%lx).", type);
 
1201
                return PD_ERR_UNSUCCESSFUL;
 
1202
                break;
 
1203
        }
 
1204
 
 
1205
        /*EMGD_TRACE_EXIT;*/
 
1206
        return 0;
 
1207
} /* end pi_write_regs */
 
1208
 
 
1209
/*!
 
1210
 * Depending on the parameters, this function does multiple things.  It always
 
1211
 * counts and returns the number of [supported] timings.  If desired, it also
 
1212
 * finds the timing with a desired "mode_info_flags" that has the largest value
 
1213
 * of width, height, OR refresh rate, which it sets to the "native_dtd"
 
1214
 * parameter.
 
1215
 *
 
1216
 * @param timing
 
1217
 * @param flags
 
1218
 * @param native_dtd
 
1219
 * @param nflags
 
1220
 *
 
1221
 * @return 0 on failure
 
1222
 * @return native dtd on success
 
1223
 */
 
1224
unsigned long get_native_dtd(igd_timing_info_t *timing,
 
1225
        unsigned long flags, pd_timing_t **native_dtd, unsigned long nflags)
 
1226
{
 
1227
        unsigned long entries = 0;
 
1228
 
 
1229
        EMGD_TRACE_EXIT;
 
1230
 
 
1231
        if (!timing) {
 
1232
                return 0;
 
1233
        }
 
1234
        if (native_dtd) {
 
1235
                *native_dtd = NULL;
 
1236
        }
 
1237
        while (timing->width != IGD_TIMING_TABLE_END) {
 
1238
                if (flags & PI_SUPPORTED_TIMINGS) {
 
1239
                        if (timing->mode_info_flags & PD_MODE_SUPPORTED) {
 
1240
                                entries++;
 
1241
                        }
 
1242
                        if ((native_dtd) &&
 
1243
                                (timing->mode_info_flags & nflags)) {
 
1244
                                /* Native Resolution is defined as the largest resolution the
 
1245
                                 * panel can display. However, some panels contain more than one
 
1246
                                 * DTD in its EDID. We will choose the largest resolution
 
1247
                                 * available from EDID */
 
1248
                                if(((*native_dtd) && (nflags == PD_MODE_DTD)) &&
 
1249
                                        (((pd_timing_t*)(*native_dtd))->width > timing->width ||
 
1250
                                        ((pd_timing_t*)(*native_dtd))->height > timing->height ||
 
1251
                                        ((pd_timing_t*)(*native_dtd))->refresh > timing->refresh)){
 
1252
                                                /* do nothing */
 
1253
                                } else {
 
1254
                                        *native_dtd = timing;
 
1255
                                }
 
1256
                        }
 
1257
                } else {
 
1258
                        entries++;
 
1259
                }
 
1260
 
 
1261
                timing++;
 
1262
                if ((timing->width == PD_TIMING_LIST_END) && timing->extn_ptr) {
 
1263
                        timing = timing->extn_ptr;
 
1264
                }
 
1265
        }
 
1266
 
 
1267
        EMGD_TRACE_EXIT;
 
1268
        return entries;
 
1269
}
 
1270
 
 
1271
#ifndef CONFIG_MICRO
 
1272
unsigned long get_magic_cookie(pd_driver_t *pd_driver)
 
1273
{
 
1274
        /* FIXME: Implement cookie checking */
 
1275
        return 0;
 
1276
}
 
1277
#endif
 
1278
 
 
1279
/*!
 
1280
 * Function to filter modes based on EDID or DisplayID
 
1281
 *
 
1282
 * @param port
 
1283
 * @param firmware_data
 
1284
 * @param timing_table
 
1285
 *
 
1286
 * @return 0 on success
 
1287
 * @return -IGD_ERROR_EDID, -IGD_ERROR_NOMEM on failure
 
1288
 */
 
1289
int get_firmware_timings(igd_display_port_t *port,
 
1290
        unsigned char *firmware_data, igd_timing_info_t *timing_table)
 
1291
{
 
1292
        edid_t         *edid;
 
1293
        displayid_t    *displayid;
 
1294
        int            ret = -1;
 
1295
 
 
1296
        EMGD_TRACE_ENTER;
 
1297
 
 
1298
        if (!firmware_data) {
 
1299
                return -IGD_ERROR_EDID;
 
1300
        }
 
1301
 
 
1302
        if (!port->displayid) {
 
1303
                /* EDID and DisplayID use same memory */
 
1304
                displayid = (displayid_t *) OS_ALLOC(sizeof(displayid_t));
 
1305
                if (!displayid) {
 
1306
                        return -IGD_ERROR_NOMEM;
 
1307
                }
 
1308
                edid = (edid_t *) displayid;
 
1309
        } else {
 
1310
                displayid = port->displayid;
 
1311
                edid = (edid_t *) displayid;
 
1312
        }
 
1313
        OS_MEMSET(displayid, 0, sizeof(displayid_t));
 
1314
 
 
1315
        /* Now parse the EDID or DisplayID */
 
1316
        /* Check the header to determine whether the data is EDID or DisplayID */
 
1317
        /* EDID header first 8 bytes =
 
1318
         *     byte 0, 1, 2, 3: 00 ff ff ff = unsigned long 0xFFFFFF00
 
1319
         *     byte 4, 5, 6, 7: ff ff ff 00 = unsigned long 0x00FFFFFF */
 
1320
        if (*(unsigned long *) &firmware_data[0] == 0xFFFFFF00 &&
 
1321
                *(unsigned long *) &firmware_data[4] == 0x00FFFFFF) {
 
1322
#ifdef DEBUG_FIRMWARE
 
1323
                firmware_dump(firmware_data, 256);
 
1324
#endif
 
1325
                /* This is EDID data */
 
1326
                ret = edid_parse(firmware_data, edid, timing_table, 0,
 
1327
                        (unsigned char) (port->pd_driver->flags&PD_FLAG_UP_SCALING?1:0));
 
1328
                if (ret == EDID_READ_AGAIN) {
 
1329
                        /* Check to see if there is an extension block */
 
1330
                        if((firmware_data[0x7e] == 0x1)){
 
1331
                                ret = pi_context->i2c_dispatch->i2c_read_regs(
 
1332
                                        pi_context->igd_context,
 
1333
                                        port->ddc_reg,      /* DDC register */
 
1334
                                        port->ddc_speed,    /* DDC speed */
 
1335
                                        port->ddc_dab,      /* Data Addr Byte*/
 
1336
                                        0x80,                /* Register */
 
1337
                                        &firmware_data[128], /* Values */
 
1338
                                        128);                            /* next 128 bytes include extension */
 
1339
                                ret = edid_ext_parse(&firmware_data[128], edid, timing_table,0,
 
1340
                                        (unsigned char)(port->pd_driver->flags&
 
1341
                                        PD_FLAG_UP_SCALING?1:0));
 
1342
                                /* Parse next 128 bytes of EDID block */
 
1343
                        }else{
 
1344
                                ret = 0;
 
1345
                        }
 
1346
                } else if (ret) {
 
1347
                        OS_FREE(edid);
 
1348
                        return -IGD_ERROR_EDID;
 
1349
                }
 
1350
 
 
1351
                port->firmware_type = PI_FIRMWARE_EDID;
 
1352
#ifdef DEBUG_FIRMWARE
 
1353
                edid_print(edid);
 
1354
#endif
 
1355
 
 
1356
#ifndef CONFIG_NO_DISPLAYID
 
1357
        } else {
 
1358
                /* size  = payload + 5 */
 
1359
                /* +5 is for the 5 mandatory bytes not included in payload */
 
1360
                unsigned short displayid_size = firmware_data[1] + 5;
 
1361
                if (displayid_size > 256) {
 
1362
                        EMGD_DEBUG("Invalid DisplayID size = %u (incl 5 mand bytes) > 256",
 
1363
                                displayid_size);
 
1364
                        return -IGD_ERROR_EDID;
 
1365
                }
 
1366
 
 
1367
                /* If the DisplayID is greater than 128 bytes */
 
1368
                if (displayid_size > 128) {
 
1369
                        ret = pi_context->i2c_dispatch->i2c_read_regs(
 
1370
                                pi_context->igd_context,
 
1371
                                port->ddc_reg,      /* DDC register */
 
1372
                                port->ddc_speed,    /* DDC speed */
 
1373
                                port->ddc_dab,      /* Data Addr Byte*/
 
1374
                                0,                  /* Register */
 
1375
                                firmware_data,      /* Values */
 
1376
                                displayid_size);    /* Num bytes to read */
 
1377
                }
 
1378
 
 
1379
#ifdef DEBUG_FIRMWARE
 
1380
                firmware_dump(firmware_data, 256);
 
1381
#endif
 
1382
                /* This is DisplayID data */
 
1383
                ret = displayid_parse(firmware_data, displayid, timing_table, 0,
 
1384
                        (unsigned char) (port->pd_driver->flags&PD_FLAG_UP_SCALING?1:0));
 
1385
                if (!ret) {
 
1386
                        port->firmware_type = PI_FIRMWARE_DISPLAYID;
 
1387
                } else {
 
1388
                        OS_FREE(displayid);
 
1389
                }
 
1390
#ifdef DEBUG_FIRMWARE
 
1391
                displayid_print(firmware_data, displayid);
 
1392
#endif
 
1393
#else
 
1394
        /* If DisplayID isn't enabled then print a debug message and return error */
 
1395
        } else {
 
1396
                EMGD_ERROR_EXIT("EDID header is wrong! Will ignore");
 
1397
                return -IGD_ERROR_EDID;
 
1398
#endif
 
1399
        }
 
1400
 
 
1401
        port->edid = edid;
 
1402
 
 
1403
        EMGD_TRACE_EXIT;
 
1404
        return ret;
 
1405
} /* end get_firmware_timings() */
 
1406
 
 
1407
/*!
 
1408
 * Update port driver attributes with incoming values from IAL
 
1409
 *
 
1410
 * @param in_list attributes in this list are used to update corresponding
 
1411
 *      attributes in out_list
 
1412
 * @param fp_info flat panel attributes used to update ocrresponding
 
1413
 *      attributes in out_list
 
1414
 * @param out_num_attrs size of out_list
 
1415
 * @param out_list contains a list of attributes to be updated
 
1416
 *
 
1417
 * @return 0
 
1418
 */
 
1419
int update_attrs(igd_display_port_t *port)
 
1420
{
 
1421
        int          ret;
 
1422
        unsigned int i = 0;
 
1423
 
 
1424
        igd_param_attr_list_t *in_list = port->attr_list;
 
1425
        igd_param_fp_info_t   *fp_info = port->fp_info;
 
1426
 
 
1427
        /* Initial 5 attributes are for fp_info,
 
1428
         * Note: If both igd_param_fp_info_t and fp_info attributes
 
1429
         * were specified then fp_info values takes the precedence */
 
1430
        unsigned long         out_num_attrs = 5;
 
1431
        pd_attr_t             *out_list;
 
1432
 
 
1433
        EMGD_TRACE_ENTER;
 
1434
 
 
1435
        /* if: there's something in in_list */
 
1436
        if (in_list) {
 
1437
                out_num_attrs += in_list->num_attrs;
 
1438
        }
 
1439
 
 
1440
        out_list = OS_ALLOC(sizeof(pd_attr_t) * out_num_attrs);
 
1441
        if (!out_list) {
 
1442
                EMGD_DEBUG("No memory to make attr_list.");
 
1443
                return 0;
 
1444
        }
 
1445
        OS_MEMSET(out_list, 0, sizeof(pd_attr_t) * out_num_attrs);
 
1446
 
 
1447
        /* Pass user specified attributes */
 
1448
        if (in_list) {
 
1449
                /* For every incoming attr, make a pd_attr_t */
 
1450
                for (i = 0; i < in_list->num_attrs; i++) {
 
1451
                        /* This will work for all kinds of attributes:
 
1452
                         * in_list->attr[i].value =
 
1453
                         *      actual value for range attributes
 
1454
                         *      index for list  attributes
 
1455
                         *      value for boolean attributes.
 
1456
                         * This works because
 
1457
                         *   pd_attr_t, pd_range_attr_t, pd_list_attr_t,
 
1458
                         *   pd_boolean_attr_t all have save offsets for
 
1459
                         *   default values. */
 
1460
                        out_list[i].id = in_list->attr[i].id;
 
1461
                        out_list[i].flags = PD_ATTR_FLAG_VALUE_CHANGED;
 
1462
                        out_list[i].current_value = in_list->attr[i].value;
 
1463
                }
 
1464
        }  /* if: there's something in in_list */
 
1465
 
 
1466
        /* Pass flat panel attributes to the port driver, if necessary */
 
1467
        if (fp_info) {
 
1468
                /* Initialize flat panel attributes */
 
1469
                /* Update FP attributes */
 
1470
                if (fp_info->fp_pwr_method == IGD_PARAM_FP_PWR_METHOD_PD) {
 
1471
                        /* The only thing remaining is the FP_PWR_Tx, so check
 
1472
                         * to ensure it is for an FP_PWR_METHOD_PD */
 
1473
                        out_list[i].id = PD_ATTR_ID_FP_PWR_T1;
 
1474
                        out_list[i].flags = PD_ATTR_FLAG_VALUE_CHANGED;
 
1475
                        out_list[i++].current_value = fp_info->fp_pwr_t1;
 
1476
 
 
1477
                        out_list[i].id = PD_ATTR_ID_FP_PWR_T2;
 
1478
                        out_list[i].flags = PD_ATTR_FLAG_VALUE_CHANGED;
 
1479
                        out_list[i++].current_value = fp_info->fp_pwr_t2;
 
1480
 
 
1481
                        out_list[i].id = PD_ATTR_ID_FP_PWR_T3;
 
1482
                        out_list[i].flags = PD_ATTR_FLAG_VALUE_CHANGED;
 
1483
                        out_list[i++].current_value = fp_info->fp_pwr_t3;
 
1484
 
 
1485
                        out_list[i].id = PD_ATTR_ID_FP_PWR_T4;
 
1486
                        out_list[i].flags = PD_ATTR_FLAG_VALUE_CHANGED;
 
1487
                        out_list[i++].current_value = fp_info->fp_pwr_t4;
 
1488
 
 
1489
                        out_list[i].id = PD_ATTR_ID_FP_PWR_T5;
 
1490
                        out_list[i].flags = PD_ATTR_FLAG_VALUE_CHANGED;
 
1491
                        out_list[i++].current_value = fp_info->fp_pwr_t5;
 
1492
                }
 
1493
        }
 
1494
 
 
1495
#ifndef CONFIG_NO_DISPLAYID
 
1496
        /* Based on our architecture, any user-defined config option will override
 
1497
         * firmware options. i.e., First send the DisplayID attributes
 
1498
         * then send the config attributes to port drivers. */
 
1499
        if (port->firmware_type == PI_FIRMWARE_DISPLAYID) {
 
1500
                ret = port->pd_driver->set_attrs(port->pd_context,
 
1501
                        port->displayid->num_attrs,
 
1502
                        port->displayid->attr_list);
 
1503
        }
 
1504
#endif
 
1505
        ret = port->pd_driver->set_attrs(port->pd_context, i, out_list);
 
1506
        if (ret) {
 
1507
                EMGD_DEBUG("Attribute update failed. ret = %d.", ret);
 
1508
        }
 
1509
        OS_FREE(out_list);
 
1510
 
 
1511
        EMGD_TRACE_EXIT;
 
1512
        return 0;
 
1513
} /* update_attrs */
 
1514
 
 
1515
/* Add user defined timings to big timing table */
 
1516
pd_timing_t *get_user_timings(igd_param_dtd_list_t *in_list)
 
1517
{
 
1518
        pd_timing_t        *t = NULL, *timing = NULL;
 
1519
        igd_display_info_t *dtd;
 
1520
        unsigned long i;
 
1521
        int ret = 0;
 
1522
 
 
1523
        EMGD_TRACE_ENTER;
 
1524
 
 
1525
        if (!in_list || !(in_list->num_dtds) || !(in_list->dtd)) {
 
1526
                return NULL;
 
1527
        }
 
1528
 
 
1529
        t = (pd_timing_t *)OS_ALLOC((in_list->num_dtds + 1)
 
1530
                        * sizeof(pd_timing_t));
 
1531
        if (!t) {
 
1532
                return NULL;
 
1533
        }
 
1534
 
 
1535
        OS_MEMSET(t, 0, (in_list->num_dtds + 1) * sizeof(pd_timing_t));
 
1536
        timing = t;
 
1537
        dtd = in_list->dtd;
 
1538
 
 
1539
        /*
 
1540
         * OPTIMIZEME: When igd_display_info_t goes away there will be no reason
 
1541
         * to copy this data. A Rule can be imposed that anything passed to
 
1542
         * the HAL during init must remain in scope until the HAL is shut
 
1543
         * down. The HAL can then just use this directly.
 
1544
         */
 
1545
        for (i = 0; i < in_list->num_dtds; i++) {
 
1546
                OS_MEMCPY(t, dtd, sizeof(igd_display_info_t));
 
1547
                t->mode_info_flags = dtd->flags | PD_MODE_DTD_USER | PD_MODE_SUPPORTED;
 
1548
#if 0
 
1549
                /* Assume there is no border, then htotal and vtotal are the same as
 
1550
                 * hblank_end and vblank_end */
 
1551
                t->htotal = t->hblank_end;
 
1552
                t->vtotal = t->vblank_end;
 
1553
                if (dtd->refresh) {
 
1554
                        t->refresh = (unsigned short)dtd->refresh;
 
1555
                } else if (t->htotal && t->vtotal) {
 
1556
                        t->refresh = (unsigned short)
 
1557
                                ((unsigned long)((unsigned long)(t->dclk) * 1000) /
 
1558
                                        ((unsigned long)(t->htotal) *
 
1559
                                                (unsigned long)(t->vtotal)));
 
1560
                }
 
1561
#endif
 
1562
 
 
1563
#ifndef CONFIG_MICRO
 
1564
               /*
 
1565
                * If the VESA flag is set, set the mode mode number to VESA.
 
1566
                * DTD may not contain mode number but the VESA flag is set
 
1567
                * This will cause program pipe VGA to be executed and fail
 
1568
                * Need to make sure that if USER wants to use VGA mode, that the
 
1569
                * mode_number is entered in the user DTD
 
1570
                */
 
1571
               if((t->mode_info_flags & PD_MODE_VESA) && (!t->mode_number)){
 
1572
                       t->mode_number = VGA_MODE_NUM_MAX + 1;
 
1573
               }
 
1574
 
 
1575
               /*
 
1576
                * Handle the corner case where user DTD is derived from std timing.
 
1577
                * Two std timings have border (htotal != h_blank_end).
 
1578
                * Compare the timing attribute with the std timing and use the
 
1579
                * total and refresh rate from std timing.
 
1580
                * Only happens when using Harmonic tool so the change is limited
 
1581
                * to Atom E6xx through the dispatch function
 
1582
                */
 
1583
                if(pi_context->igd_context->mod_dispatch.get_refresh_in_border){
 
1584
                       /* returns 1 if a refresh was obtained */
 
1585
                       ret = pi_context->igd_context->mod_dispatch.get_refresh_in_border(t);
 
1586
               }
 
1587
#endif
 
1588
               if(!ret){
 
1589
                       /* Assume there is no border, then htotal and vtotal are the same as
 
1590
                        * hblank_end and vblank_end */
 
1591
                       t->htotal = t->hblank_end;
 
1592
                       t->vtotal = t->vblank_end;
 
1593
                       if (dtd->refresh) {
 
1594
                               t->refresh = (unsigned short)dtd->refresh;
 
1595
                       } else if (t->htotal && t->vtotal) {
 
1596
                               /*
 
1597
                                * Refresh is used mainly for esthetic, mainly in GUI.
 
1598
                                * The compiler will truncate the decimals, not rounding
 
1599
                                * UP the value (in this case, 59.7 will be 59Hz and not 60Hz
 
1600
                                * Need to manually handle the rounding.
 
1601
                                *
 
1602
                                * We multiply the dclk by 10, therefore shifting the final
 
1603
                                * decimal place by one, then check if the last digit is
 
1604
                                * >4 to round up the refresh by 1 after dividing by 10.
 
1605
                                */
 
1606
                               unsigned short temp_refresh = (unsigned short)
 
1607
                                       ((unsigned long)((unsigned long)(t->dclk) * 10000) /
 
1608
                                               ((unsigned long)(t->htotal) *
 
1609
                                                       (unsigned long)(t->vtotal)));
 
1610
                               if((temp_refresh % 10) > 4){
 
1611
                                       t->refresh = (temp_refresh / 10 ) + 1;
 
1612
                               } else {
 
1613
                                       t->refresh = (temp_refresh / 10);
 
1614
                               }
 
1615
                       }
 
1616
               }
 
1617
 
 
1618
                /* t->pd_extn_ptr = NULL; */
 
1619
                t->extn_ptr = NULL;
 
1620
 
 
1621
                t++;
 
1622
                dtd++;
 
1623
        }
 
1624
 
 
1625
        /* End the table with end marker */
 
1626
        t->width = IGD_TIMING_TABLE_END;
 
1627
 
 
1628
        EMGD_TRACE_EXIT;
 
1629
 
 
1630
        return timing;
 
1631
}
 
1632
 
 
1633
/*!
 
1634
 * Assign dynamic VBE numbers to the modes that do not already have
 
1635
 * VESA defined numbers.
 
1636
 *
 
1637
 * @param timing_table
 
1638
 *
 
1639
 * @return void
 
1640
 */
 
1641
#define FIRST_DYNAMIC_MODE_NUMBER 0x120
 
1642
void assign_dynamic_numbers(igd_timing_info_t *timing_table)
 
1643
{
 
1644
        unsigned short next_number = FIRST_DYNAMIC_MODE_NUMBER;
 
1645
        unsigned int i;
 
1646
        unsigned short vesa_mode_table[] = {
 
1647
                640, 480, 0x101,
 
1648
                800, 600, 0x103,
 
1649
                1024, 768, 0x105,
 
1650
                1280, 1024, 0x107,
 
1651
                0xffff, 0xffff, 0xffff,
 
1652
        };
 
1653
 
 
1654
        EMGD_TRACE_ENTER;
 
1655
 
 
1656
        while(timing_table->width != IGD_TIMING_TABLE_END) {
 
1657
                if((timing_table->mode_info_flags & IGD_MODE_SUPPORTED) &&
 
1658
                        !(timing_table->mode_info_flags & IGD_MODE_VESA)) {
 
1659
 
 
1660
                        for (i=0; vesa_mode_table[i] != 0xffff; i+=3) {
 
1661
                                if ((timing_table->width == vesa_mode_table[i]) &&
 
1662
                                        (timing_table->height == vesa_mode_table[i+1])) {
 
1663
                                        /* This is a VESA Standard mode, so assign it to the
 
1664
                                         * correct VESA mode number.  This can occur with
 
1665
                                         * modes added either through User Defined DTDs or
 
1666
                                         * potentially EDID. */
 
1667
                                        timing_table->mode_number = vesa_mode_table[i+2];
 
1668
                                        timing_table->mode_info_flags |= IGD_MODE_VESA;
 
1669
                                        break;
 
1670
                                }
 
1671
                        }
 
1672
                        if (vesa_mode_table[i] == 0xffff) {
 
1673
                                /* Assign this mode a Dynamic number, if it is not
 
1674
                                 * a VESA Standard mode. */
 
1675
                                timing_table->mode_number = next_number;
 
1676
                                /* VBE modes use lower 2 bits for depth so next mode is += 4 */
 
1677
                                next_number += 4;
 
1678
                                timing_table->mode_info_flags |= IGD_MODE_VESA;
 
1679
                        }
 
1680
                }
 
1681
                timing_table++;
 
1682
 
 
1683
                /* If reached the first table END,
 
1684
                 * then check for the added modes */
 
1685
                if (timing_table->width == IGD_TIMING_TABLE_END &&
 
1686
                        timing_table->extn_ptr) {
 
1687
                        timing_table = timing_table->extn_ptr;
 
1688
                }
 
1689
        }
 
1690
 
 
1691
        EMGD_TRACE_EXIT;
 
1692
        return;
 
1693
}
 
1694
 
 
1695
/*!
 
1696
 * This is a utility function that can be used througout the HAL.
 
1697
 * It can be used to get a ptr to an attr structure and/or the
 
1698
 * actual current_value of that attribute.
 
1699
 * According to usage modal at time of creation of this function:
 
1700
 *      - the *caller_pd_attr must be NULL if the attr was not found.
 
1701
 *      - the *attr_value is only changed if the attr was found
 
1702
 *
 
1703
 * @param port
 
1704
 * @param attr_id
 
1705
 * @param flag
 
1706
 * @param caller_pd_attr
 
1707
 * @param attr_value
 
1708
 *
 
1709
 * @return 0 on success
 
1710
 * @return -IGD_ERROR_INVAL on failure
 
1711
 */
 
1712
int pi_pd_find_attr_and_value(igd_display_port_t *port,
 
1713
                unsigned long attr_id,
 
1714
                unsigned long flag,
 
1715
                pd_attr_t   **caller_pd_attr,
 
1716
                unsigned long *attr_value)
 
1717
{
 
1718
        unsigned long pd_attr_length   = 0;
 
1719
        pd_attr_t    *pd_attr_list     = NULL;
 
1720
        pd_attr_t    *found_pd_attr    = NULL;
 
1721
 
 
1722
        EMGD_TRACE_ENTER;
 
1723
 
 
1724
        if(!port || !(port->pd_driver)) {
 
1725
                return -IGD_ERROR_INVAL;
 
1726
        }
 
1727
 
 
1728
        if(flag == PD_ATTR_FLAG_GENERAL){
 
1729
                pd_attr_length = PD_QUERY_GENERAL_ATTR;
 
1730
        }
 
1731
        port->pd_driver->get_attrs(port->pd_context, &pd_attr_length,
 
1732
                &pd_attr_list);
 
1733
        if(!pd_attr_length) {
 
1734
                return -IGD_ERROR_INVAL;
 
1735
        }
 
1736
 
 
1737
        found_pd_attr = pd_get_attr(pd_attr_list, pd_attr_length, attr_id, flag);
 
1738
 
 
1739
        if (!found_pd_attr) {
 
1740
                if(caller_pd_attr) {
 
1741
                        *caller_pd_attr = NULL;
 
1742
                }
 
1743
                return -IGD_INVAL;
 
1744
        }
 
1745
        if(caller_pd_attr) {
 
1746
                *caller_pd_attr = found_pd_attr;
 
1747
        }
 
1748
        if(attr_value) {
 
1749
                *attr_value = found_pd_attr->current_value;
 
1750
        }
 
1751
 
 
1752
        EMGD_TRACE_EXIT;
 
1753
        return 0;
 
1754
}
 
1755
 
 
1756
/*!
 
1757
 *
 
1758
 * @param port
 
1759
 * @param id
 
1760
 * @param value
 
1761
 *
 
1762
 * @return 0 on success
 
1763
 * @return -IGD_ERROR_INVAL on failure
 
1764
 */
 
1765
int pi_get_port_init_attr(igd_display_port_t *port,
 
1766
                unsigned long id,
 
1767
                unsigned long *value)
 
1768
{
 
1769
        unsigned short i;
 
1770
 
 
1771
        EMGD_TRACE_ENTER;
 
1772
 
 
1773
        if (!port || !port->attr_list) {
 
1774
                return -IGD_ERROR_INVAL;
 
1775
        }
 
1776
 
 
1777
        for (i = 0; i < (unsigned short) port->attr_list->num_attrs; i++) {
 
1778
                if (port->attr_list->attr[i].id == id) {
 
1779
                        *value = port->attr_list->attr[i].value;
 
1780
                        EMGD_TRACE_EXIT;
 
1781
                        return 0;
 
1782
                }
 
1783
        }
 
1784
 
 
1785
        EMGD_DEBUG("Attribute (0x%ld) Not Found", id);
 
1786
        EMGD_TRACE_EXIT;
 
1787
        return -IGD_ERROR_INVAL;
 
1788
}
 
1789
 
 
1790
/*----------------------------------------------------------------------------
 
1791
 * File Revision History
 
1792
 * $Id: pi.c,v 1.14 2010/11/10 19:44:23 rclovrie Exp $
 
1793
 * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/display/pi/cmn/pi.c,v $
 
1794
 *----------------------------------------------------------------------------
 
1795
 */