2
*-----------------------------------------------------------------------------
5
*-----------------------------------------------------------------------------
6
* Copyright © 2002-2010, Intel Corporation.
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.
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
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.
21
*-----------------------------------------------------------------------------
23
* This file contains all the necessary functions for port interface
24
* module. This module abstracts all hardware port interfaces and
26
*-----------------------------------------------------------------------------
29
#define MODULE_NAME hal.dpd
33
#include <igd_errno.h>
52
#include <mode_access.h>
54
#include <displayid.h>
56
#include "i2c_dispatch.h"
61
* @addtogroup display_group
65
typedef struct _pi_context {
66
igd_context_t *igd_context;
67
i2c_dispatch_t *i2c_dispatch;
68
unsigned long num_pi_drivers;
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);
75
int pi_pd_init(igd_display_port_t *port, unsigned long port_feature,
76
unsigned long second_port_feature, int drm_load_time);
78
unsigned long get_magic_cookie(pd_driver_t *pd_driver);
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);
85
extern int pi_init_all(void *handle);
88
extern i2c_dispatch_t i2c_dispatch_plb;
89
extern i2c_dispatch_t i2c_dispatch_tnc;
93
return -IGD_ERROR_NODEV;
96
static i2c_dispatch_t i2c_dispatch_null = {
104
static dispatch_table_t i2c_dispatch_list[] = {
107
{PCI_DEVICE_ID_VGA_PLB, &i2c_dispatch_plb},
110
{PCI_DEVICE_ID_VGA_TNC, &i2c_dispatch_tnc},
116
static unsigned char firmware_data[256];
118
static pi_context_t pi_context[1];
120
/*----------------------------------------------------------------------
121
* FUNCTION DEFINITIONS
122
*----------------------------------------------------------------------*/
130
static void pi_shutdown(igd_context_t *context)
132
igd_display_port_t *port;
136
if (pi_context->igd_context == NULL) {
140
/* Close the port drivers */
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;
151
OS_FREE(port->fp_info);
152
port->fp_info = NULL;
154
if (port->callback) {
155
OS_FREE(port->callback);
156
port->callback = NULL;
171
int pi_full_init(igd_context_t *context)
173
/* Optional Inter-module interfaces */
174
context->mod_dispatch.pi_shutdown = pi_shutdown;
187
static int pi_get_config_info(igd_context_t *context,
188
igd_config_info_t *config_info)
192
EMGD_ASSERT(context, "Null context", -IGD_ERROR_INVAL);
193
EMGD_ASSERT(config_info, "Null config_info", -IGD_ERROR_INVAL);
195
config_info->num_act_dsp_ports = pi_context->num_pi_drivers;
207
int pi_init(igd_context_t *context)
209
i2c_dispatch_t *i2c_dispatch;
213
OS_MEMSET(pi_context, 0, sizeof(pi_context_t));
215
/* Save igd_context in local_igd_context. */
216
pi_context->igd_context = context;
218
/* Get I2C dispatch table */
219
i2c_dispatch = (i2c_dispatch_t *)dispatch_acquire(context,
222
EMGD_DEBUG("No i2c Dispatch available for PI module");
224
pi_context->i2c_dispatch = i2c_dispatch;
227
* If Dynamic Port drivers are not used then init the static drivers
230
#ifndef IGD_DPD_ENABLED
234
ret = pi_init_all(handle);
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;
244
OPT_MICRO_CALL(pi_full_init(context));
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.
257
* @return port on success
258
* @return NULL on failure
260
igd_display_port_t *pi_get_feature_port(unsigned long feature,
261
igd_display_port_t *last)
263
igd_display_port_t *port;
264
inter_module_dispatch_t *md = &pi_context->igd_context->mod_dispatch;
266
while ((port = md->dsp_get_next_port(pi_context->igd_context, last, 0))) {
269
if (port->port_features & feature) {
283
* Function to register port driver with display driver
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
291
int pi_pd_register(pd_driver_t *pd_driver)
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;
306
EMGD_ERROR_EXIT("Null pd_driver received.");
307
return PD_ERR_NULL_PTR;
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;
323
/* Do magic cookie hand shaking */
325
cookie_sent = get_magic_cookie(pd_driver);
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. */
333
EMGD_ERROR("Error, magic cookie handshaking failed.");
334
return PD_ERR_HAND_SHAKE;
338
init_params = pi_context->igd_context->mod_dispatch.init_params;
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|
356
/* Allocate DVO port which is the only kind of port exported to
357
* 3rd party encoders */
358
port_type = IGD_PORT_DIGITAL;
360
if (pd_driver->flags & PD_FLAG_GANG_MODE) {
361
igd_display_port_t *portb;
362
unsigned long user_gang = 0;
364
pi_context->igd_context->mod_dispatch.dsp_get_display(2,
367
if (portb->attr_list && portb->attr_list->num_attrs != 0) {
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;
376
/* If both user attribute and port driver flag are set to GANG MODE,
377
* then allocate a gang display port */
379
port_feature = IGD_PORT_GANG;
380
second_port_feature = IGD_PORT_GANG;
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;
388
EMGD_ERROR_EXIT("Invalid display type.");
389
return PD_ERR_DISPLAY_TYPE;
392
/* Get the port entry */
394
while((port = pi_get_feature_port(port_feature, port))) {
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)) {
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.");
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 */
416
/* SDVO port driver needs the port number */
417
port->callback->port_num = port->port_number;
419
/* now save the pd_driver in port entry */
420
port->pd_driver = pd_driver;
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:
430
/* Try detecting the encoder by calling port driver open() */
432
((port->dab == 0) && (pd_driver->dab_list[0] == PD_DAB_LIST_END))) {
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
443
EMGD_DEBUG("1+ encoders have same I2C bus and DAB");
446
/* Call open() only once if either user provides a DAB
448
* no required to open an encoder. ex: analog, rgba, lvds etc.
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));
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];
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.
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
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.
478
* In this case open the port driver again. */
481
port->pd_context = NULL;
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));
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);
505
/* Initialize our port entry */
506
ret = pi_pd_init(port, port_feature, second_port_feature, TRUE);
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;
520
EMGD_DEBUG("Device found on %s port for \"%s\"", port->port_name,
523
prev_instance_dab = port->dab;
524
prev_instance_i2c_reg = port->i2c_reg;
527
/* If Multi-DVO support is enabled then detect next encoder of
529
if (init_params->display_flags & IGD_DISPLAY_MULTI_DVO){
530
/* Continue to find next encoder */
533
/* Found one encoder and return to port driver */
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;
546
} /* end while(port == feature_port()) */
548
if (num_instances == 0) {
549
EMGD_DEBUG("No device found for \"%s\"", pd_driver->name);
550
return PD_ERR_NOPORT_AVAIL;
555
} /* end pi_pd_register() */
557
/* Function to replace common timings in 1st list with 2nd list, 2nd list
559
void replace_common_dtds(igd_timing_info_t *dtds1,
560
igd_timing_info_t *dtds2)
562
igd_timing_info_t *temp;
565
if (!dtds2 || !dtds1) {
569
while (dtds1->width != IGD_TIMING_TABLE_END) {
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
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;
601
int check_port_attrs(igd_display_port_t *port)
604
unsigned long attr_value = 0;
606
pd_attr_t out_list,*temp_list;
607
temp_list = &out_list;
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
614
ret = pi_pd_find_attr_and_value(port, PD_ATTR_ID_PORT_DDC_REG,
615
PD_ATTR_FLAG_GENERAL, NULL, &attr_value);
617
EMGD_DEBUG("ddr_reg value unique = %ld.", attr_value);
618
port->ddc_reg = attr_value;
621
ret = pi_pd_find_attr_and_value(port, PD_ATTR_ID_PORT_NAME,
622
PD_ATTR_FLAG_GENERAL, &(temp_list), &attr_value);
624
EMGD_DEBUG("ddr_reg value unique = %ld.", attr_value);
625
pd_strcpy(port->port_name, temp_list->name);
633
* Function to initialize port driver related members in port table entry
636
* @param port_feature
637
* @param second_port_feature
638
* @param drm_load_time
640
* @return PD_SUCCESS on success
641
* @return 1 on failure
643
int pi_pd_init(igd_display_port_t *port,
644
unsigned long port_feature,
645
unsigned long second_port_feature,
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;
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);
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;
676
/* now link second port to first one */
677
port->mult_port = second_port;
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
687
* based on edid_flags.
689
* If there are no flags, then it defaults to use STD TIMINGS + EDID DTDs
692
/* Get the display params for this port */
693
init_params = pi_context->igd_context->mod_dispatch.init_params;
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];
702
/* Start with STD TIMINGS */
703
edid_flags = IGD_DISPLAY_USE_STD_TIMINGS;
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*/
714
firmware_data, /* Values */
715
128); /* Num bytes to read */
717
/* If EDID is present then use EDID.
718
* edid_flags will be corrected later if display_params are present */
720
edid_flags |= IGD_DISPLAY_USE_EDID;
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);
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) {
738
display_params->edid_not_avail & ~IGD_DISPLAY_USE_EDID;
739
EMGD_DEBUG("EDID_Not_Avail: 0x%lx", edid_flags);
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);
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;
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);
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;
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;
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;
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);
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.
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);
800
/* Update port driver attributes */
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);
807
if (ret || !pd_timing_table) {
808
EMGD_ERROR_EXIT("port driver: get timing list error.");
809
return PD_ERR_NO_TIMINGS;
812
/* Delete temporary lists and buffers */
814
OS_FREE(user_timings);
817
OS_FREE(std_timings);
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);
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);
829
assign_dynamic_numbers(port->timing_table);
831
#ifdef DEBUG_FIRMWARE
834
EMGD_DEBUG("Supported timings for \"%s\" (%lu)",
835
port->pd_driver->name, port->num_timing);
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);
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).
862
if (!drm_load_time) {
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(
878
mstate = (mode_state_t *)(*state);
882
/* If mode state is present in register context,
883
* then call save() function to save the port driver's state */
885
ret = port->pd_driver->pd_save(port->pd_context,
886
&(mstate->pd_state[pi_context->num_pi_drivers].state), 0);
888
EMGD_ERROR_EXIT("port driver: reg saving error. ret = %d", ret);
891
mstate->pd_state[pi_context->num_pi_drivers].port = port;
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);
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);
907
port->callback->eld = NULL;
910
ret = port->pd_driver->init_device(port->pd_context);
913
/* TODO: Restore the pd state? */
914
EMGD_ERROR_EXIT("port driver: init_device error. ret = %d", ret);
916
mstate->pd_state[pi_context->num_pi_drivers].port = NULL;
917
mstate->pd_state[pi_context->num_pi_drivers].state = NULL;
923
/* Increment the number of port drivers */
924
pi_context->num_pi_drivers++;
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;
933
} /* end pi_pd_init */
936
* Function to read registers
942
* @return PD_SUCCESS on success
943
* @return PD_ERR_NULL_PTR, PD_ERR_I2C_READ, PD_ERR_UNSUCCESSFUL on failure
945
int pi_read_regs(void *callback_context, pd_reg_t *list, unsigned long type)
948
igd_display_port_t *port = callback_context;
954
EMGD_ERROR_EXIT("Null callback context passed.");
955
return PD_ERR_NULL_PTR;
958
if (!port->pd_driver) {
959
EMGD_ERROR_EXIT("Null pd_driver in port entry.");
960
return PD_ERR_NULL_PTR;
963
mmio = EMGD_MMIO(pi_context->igd_context->device_context.virt_mmadr);
965
/* Based on the port type either read GMCH registers or I2C registers */
969
while (list->reg != PD_REG_LIST_END) {
970
ret = pi_context->i2c_dispatch->i2c_read_regs(
971
pi_context->igd_context,
975
(unsigned char)list->reg,
976
(unsigned char *)&list->value, 1);
978
EMGD_DEBUG("i2c_read_reg: 0x%lx failed.", list->reg);
984
return PD_ERR_I2C_READ;
989
while (list->reg != PD_REG_LIST_END) {
990
ret = pi_context->i2c_dispatch->i2c_read_regs(
991
pi_context->igd_context,
995
(unsigned char)list->reg,
996
(unsigned char *)&list->value, 1);
998
EMGD_DEBUG("i2c_read_reg: 0x%lx failed.", list->reg);
1004
return PD_ERR_I2C_READ;
1008
while (list->reg != PD_REG_LIST_END) {
1009
list->value = EMGD_READ_PORT8(list->reg);
1014
while (list->reg != PD_REG_LIST_END) {
1015
list->value = EMGD_READ_PORT16(list->reg);
1020
while (list->reg != PD_REG_LIST_END) {
1021
list->value = EMGD_READ_PORT32(list->reg);
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) {
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,
1046
list->value = EMGD_READ32(EMGD_MMIO(mmio) + list->reg);
1049
list->value = EMGD_READ8(EMGD_MMIO(mmio) + list->reg);
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);
1066
/* Rightnow this is only to provide the device id */
1067
while (list->reg != PD_REG_LIST_END) {
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));
1075
list->value = pi_context->igd_context->device_context.did;
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;
1089
EMGD_ERROR_EXIT("Unknown reg type (0x%lx).", type);
1090
return PD_ERR_UNSUCCESSFUL;
1094
/*EMGD_TRACE_EXIT;*/
1096
} /* end pi_read_regs */
1099
* Function to write registers
1105
* @return 0 on success
1106
* @return PD_ERR_NULL_PTR, PD_ERR_I2C_WRITE, PD_ERR_UNSUCCESSFUL on failure
1108
extern unsigned short io_base_sdvo;
1109
extern unsigned short io_base;
1111
int pi_write_regs(void *callback_context, pd_reg_t *list, unsigned long type)
1113
igd_display_port_t *port = callback_context;
1115
unsigned char *mmio;
1117
/*EMGD_TRACE_ENTER;*/
1120
EMGD_ERROR_EXIT("Null callback context passed.");
1121
return PD_ERR_NULL_PTR;
1124
if (!port->pd_driver) {
1125
EMGD_ERROR_EXIT("Null pd_driver.");
1126
return PD_ERR_NULL_PTR;
1129
mmio = EMGD_MMIO(pi_context->igd_context->device_context.virt_mmadr);
1131
/* Based on the port type either write GMCH registers or I2C registers */
1134
ret = pi_context->i2c_dispatch->i2c_write_reg_list(
1135
pi_context->igd_context,
1142
EMGD_DEBUG("i2c_write_reg: 0x%lx = 0x%lx failed.",
1143
list->reg, list->value);
1144
return PD_ERR_I2C_WRITE;
1148
while (list->reg != PD_REG_LIST_END) {
1149
EMGD_WRITE_PORT8(list->reg, list->value);
1154
while (list->reg != PD_REG_LIST_END) {
1155
EMGD_WRITE_PORT16(list->reg, list->value);
1160
while (list->reg != PD_REG_LIST_END) {
1161
EMGD_WRITE_PORT32(list->reg, list->value);
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) {
1175
/* BIT31 indicates write to 0:3:0 SDVO device */
1176
WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, list->reg,
1180
EMGD_WRITE32(list->value, EMGD_MMIO(mmio) + list->reg);
1183
EMGD_WRITE8(list->value, EMGD_MMIO(mmio) + list->reg);
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);
1200
EMGD_ERROR_EXIT("Unknown reg type (0x%lx).", type);
1201
return PD_ERR_UNSUCCESSFUL;
1205
/*EMGD_TRACE_EXIT;*/
1207
} /* end pi_write_regs */
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"
1221
* @return 0 on failure
1222
* @return native dtd on success
1224
unsigned long get_native_dtd(igd_timing_info_t *timing,
1225
unsigned long flags, pd_timing_t **native_dtd, unsigned long nflags)
1227
unsigned long entries = 0;
1237
while (timing->width != IGD_TIMING_TABLE_END) {
1238
if (flags & PI_SUPPORTED_TIMINGS) {
1239
if (timing->mode_info_flags & PD_MODE_SUPPORTED) {
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)){
1254
*native_dtd = timing;
1262
if ((timing->width == PD_TIMING_LIST_END) && timing->extn_ptr) {
1263
timing = timing->extn_ptr;
1271
#ifndef CONFIG_MICRO
1272
unsigned long get_magic_cookie(pd_driver_t *pd_driver)
1274
/* FIXME: Implement cookie checking */
1280
* Function to filter modes based on EDID or DisplayID
1283
* @param firmware_data
1284
* @param timing_table
1286
* @return 0 on success
1287
* @return -IGD_ERROR_EDID, -IGD_ERROR_NOMEM on failure
1289
int get_firmware_timings(igd_display_port_t *port,
1290
unsigned char *firmware_data, igd_timing_info_t *timing_table)
1293
displayid_t *displayid;
1298
if (!firmware_data) {
1299
return -IGD_ERROR_EDID;
1302
if (!port->displayid) {
1303
/* EDID and DisplayID use same memory */
1304
displayid = (displayid_t *) OS_ALLOC(sizeof(displayid_t));
1306
return -IGD_ERROR_NOMEM;
1308
edid = (edid_t *) displayid;
1310
displayid = port->displayid;
1311
edid = (edid_t *) displayid;
1313
OS_MEMSET(displayid, 0, sizeof(displayid_t));
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);
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 */
1348
return -IGD_ERROR_EDID;
1351
port->firmware_type = PI_FIRMWARE_EDID;
1352
#ifdef DEBUG_FIRMWARE
1356
#ifndef CONFIG_NO_DISPLAYID
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",
1364
return -IGD_ERROR_EDID;
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*/
1375
firmware_data, /* Values */
1376
displayid_size); /* Num bytes to read */
1379
#ifdef DEBUG_FIRMWARE
1380
firmware_dump(firmware_data, 256);
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));
1386
port->firmware_type = PI_FIRMWARE_DISPLAYID;
1390
#ifdef DEBUG_FIRMWARE
1391
displayid_print(firmware_data, displayid);
1394
/* If DisplayID isn't enabled then print a debug message and return error */
1396
EMGD_ERROR_EXIT("EDID header is wrong! Will ignore");
1397
return -IGD_ERROR_EDID;
1405
} /* end get_firmware_timings() */
1408
* Update port driver attributes with incoming values from IAL
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
1419
int update_attrs(igd_display_port_t *port)
1424
igd_param_attr_list_t *in_list = port->attr_list;
1425
igd_param_fp_info_t *fp_info = port->fp_info;
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;
1435
/* if: there's something in in_list */
1437
out_num_attrs += in_list->num_attrs;
1440
out_list = OS_ALLOC(sizeof(pd_attr_t) * out_num_attrs);
1442
EMGD_DEBUG("No memory to make attr_list.");
1445
OS_MEMSET(out_list, 0, sizeof(pd_attr_t) * out_num_attrs);
1447
/* Pass user specified attributes */
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;
1464
} /* if: there's something in in_list */
1466
/* Pass flat panel attributes to the port driver, if necessary */
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;
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;
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;
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;
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;
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);
1505
ret = port->pd_driver->set_attrs(port->pd_context, i, out_list);
1507
EMGD_DEBUG("Attribute update failed. ret = %d.", ret);
1513
} /* update_attrs */
1515
/* Add user defined timings to big timing table */
1516
pd_timing_t *get_user_timings(igd_param_dtd_list_t *in_list)
1518
pd_timing_t *t = NULL, *timing = NULL;
1519
igd_display_info_t *dtd;
1525
if (!in_list || !(in_list->num_dtds) || !(in_list->dtd)) {
1529
t = (pd_timing_t *)OS_ALLOC((in_list->num_dtds + 1)
1530
* sizeof(pd_timing_t));
1535
OS_MEMSET(t, 0, (in_list->num_dtds + 1) * sizeof(pd_timing_t));
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.
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;
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;
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)));
1563
#ifndef CONFIG_MICRO
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
1571
if((t->mode_info_flags & PD_MODE_VESA) && (!t->mode_number)){
1572
t->mode_number = VGA_MODE_NUM_MAX + 1;
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
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);
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;
1594
t->refresh = (unsigned short)dtd->refresh;
1595
} else if (t->htotal && t->vtotal) {
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.
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.
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;
1613
t->refresh = (temp_refresh / 10);
1618
/* t->pd_extn_ptr = NULL; */
1625
/* End the table with end marker */
1626
t->width = IGD_TIMING_TABLE_END;
1634
* Assign dynamic VBE numbers to the modes that do not already have
1635
* VESA defined numbers.
1637
* @param timing_table
1641
#define FIRST_DYNAMIC_MODE_NUMBER 0x120
1642
void assign_dynamic_numbers(igd_timing_info_t *timing_table)
1644
unsigned short next_number = FIRST_DYNAMIC_MODE_NUMBER;
1646
unsigned short vesa_mode_table[] = {
1651
0xffff, 0xffff, 0xffff,
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)) {
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;
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 */
1678
timing_table->mode_info_flags |= IGD_MODE_VESA;
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;
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
1706
* @param caller_pd_attr
1709
* @return 0 on success
1710
* @return -IGD_ERROR_INVAL on failure
1712
int pi_pd_find_attr_and_value(igd_display_port_t *port,
1713
unsigned long attr_id,
1715
pd_attr_t **caller_pd_attr,
1716
unsigned long *attr_value)
1718
unsigned long pd_attr_length = 0;
1719
pd_attr_t *pd_attr_list = NULL;
1720
pd_attr_t *found_pd_attr = NULL;
1724
if(!port || !(port->pd_driver)) {
1725
return -IGD_ERROR_INVAL;
1728
if(flag == PD_ATTR_FLAG_GENERAL){
1729
pd_attr_length = PD_QUERY_GENERAL_ATTR;
1731
port->pd_driver->get_attrs(port->pd_context, &pd_attr_length,
1733
if(!pd_attr_length) {
1734
return -IGD_ERROR_INVAL;
1737
found_pd_attr = pd_get_attr(pd_attr_list, pd_attr_length, attr_id, flag);
1739
if (!found_pd_attr) {
1740
if(caller_pd_attr) {
1741
*caller_pd_attr = NULL;
1745
if(caller_pd_attr) {
1746
*caller_pd_attr = found_pd_attr;
1749
*attr_value = found_pd_attr->current_value;
1762
* @return 0 on success
1763
* @return -IGD_ERROR_INVAL on failure
1765
int pi_get_port_init_attr(igd_display_port_t *port,
1767
unsigned long *value)
1773
if (!port || !port->attr_list) {
1774
return -IGD_ERROR_INVAL;
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;
1785
EMGD_DEBUG("Attribute (0x%ld) Not Found", id);
1787
return -IGD_ERROR_INVAL;
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
*----------------------------------------------------------------------------