2 *-----------------------------------------------------------------------------
5 *-----------------------------------------------------------------------------
6 * Copyright (c) 2002-2010, Intel Corporation.
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 *-----------------------------------------------------------------------------
28 * This file contains all the necessary functions for port interface
29 * module. This module abstracts all hardware port interfaces and
31 *-----------------------------------------------------------------------------
34 #define MODULE_NAME hal.dpd
38 #include <igd_errno.h>
57 #include <mode_access.h>
59 #include <displayid.h>
62 #include "i2c_dispatch.h"
67 * @addtogroup display_group
71 typedef struct _pi_context {
72 igd_context_t *igd_context;
73 i2c_dispatch_t *i2c_dispatch;
74 unsigned long num_pi_drivers;
77 /* Function to filter the modes using EDID or DisplayID*/
78 int get_firmware_timings(igd_display_port_t *port,
79 unsigned char *firmware_data, pd_timing_t *timing_table);
81 int pi_pd_init(igd_display_port_t *port, unsigned long port_feature,
82 unsigned long second_port_feature, int drm_load_time);
84 unsigned long get_magic_cookie(pd_driver_t *pd_driver);
86 void assign_dynamic_numbers(igd_timing_info_t *timing_table);
87 int update_attrs(igd_display_port_t *port);
88 pd_timing_t *get_user_timings(igd_param_dtd_list_t *in_list);
91 extern int pi_init_all(void *handle);
93 extern emgd_drm_config_t config_drm;
94 extern i2c_dispatch_t i2c_dispatch_plb;
95 extern i2c_dispatch_t i2c_dispatch_tnc;
99 return -IGD_ERROR_NODEV;
101 /* Not currently used
102 static i2c_dispatch_t i2c_dispatch_null = {
110 static dispatch_table_t i2c_dispatch_list[] = {
113 {PCI_DEVICE_ID_VGA_PLB, &i2c_dispatch_plb},
116 {PCI_DEVICE_ID_VGA_TNC, &i2c_dispatch_tnc},
122 static unsigned char firmware_data[256];
124 static pi_context_t pi_context[1];
126 /*----------------------------------------------------------------------
127 * FUNCTION DEFINITIONS
128 *----------------------------------------------------------------------*/
136 static void pi_shutdown(igd_context_t *context)
138 igd_display_port_t *port;
142 if (pi_context->igd_context == NULL) {
146 /* Close the port drivers */
148 while ((port = context->mod_dispatch.dsp_get_next_port(context, port, 0)) != NULL) {
149 if (port->pd_driver) {
150 port->pd_driver->pd_close(port->pd_context);
151 port->pd_driver = NULL;
152 /* pd_context is freed by port driver */
153 port->pd_context = NULL;
154 /* timing_table is freed by port driver */
155 port->timing_table = NULL;
156 port->num_timing = 0;
158 OS_FREE(port->fp_info);
159 port->fp_info = NULL;
161 if (port->callback) {
162 OS_FREE(port->callback);
163 port->callback = NULL;
178 int pi_full_init(igd_context_t *context)
180 /* Optional Inter-module interfaces */
181 context->mod_dispatch.pi_shutdown = pi_shutdown;
194 static int pi_get_config_info(igd_context_t *context,
195 igd_config_info_t *config_info)
198 igd_display_port_t *port = NULL;
199 igd_param_t *init_params = NULL;
200 igd_display_params_t *display_params = NULL;
205 EMGD_ASSERT(context, "Null context", -IGD_ERROR_INVAL);
206 EMGD_ASSERT(config_info, "Null config_info", -IGD_ERROR_INVAL);
208 config_info->num_act_dsp_ports = pi_context->num_pi_drivers;
210 init_params = pi_context->igd_context->mod_dispatch.init_params;
212 while ((port = pi_context->igd_context->mod_dispatch.
213 dsp_get_next_port(pi_context->igd_context, port, 0)) != NULL) {
215 /* Get the display params to check if the user enabled EDID */
216 for (i = 0; i < IGD_MAX_PORTS; i++) {
217 if (init_params->display_params[i].port_number == port->port_number) {
218 display_params = &init_params->display_params[i];
223 /* If DID rotation info is available, pass it to user-space through the
224 * config_info struct */
225 if ((!display_params || (display_params->flags & IGD_DISPLAY_READ_EDID))
226 && (port->firmware_type == PI_FIRMWARE_DISPLAYID
227 && port->displayid != NULL)) {
229 config_info->displayid_rotation[port->port_number - 1].rotation =
230 port->displayid->rotation_info.rotation;
231 config_info->displayid_rotation[port->port_number - 1].flip =
232 port->displayid->rotation_info.flip;
235 config_info->displayid_rotation[port->port_number - 1].rotation = 0;
236 config_info->displayid_rotation[port->port_number - 1].flip = 0;
250 int pi_init(igd_context_t *context)
252 i2c_dispatch_t *i2c_dispatch;
256 OS_MEMSET(pi_context, 0, sizeof(pi_context_t));
258 /* Save igd_context in local_igd_context. */
259 pi_context->igd_context = context;
261 /* Get I2C dispatch table */
262 i2c_dispatch = (i2c_dispatch_t *)dispatch_acquire(context,
265 EMGD_DEBUG("No i2c Dispatch available for PI module");
267 pi_context->i2c_dispatch = i2c_dispatch;
270 * If Dynamic Port drivers are not used then init the static drivers
273 #ifndef IGD_DPD_ENABLED
277 ret = pi_init_all(handle);
281 /* Inter-module dispatch functions */
282 context->mod_dispatch.i2c_read_regs = i2c_dispatch->i2c_read_regs;
283 context->mod_dispatch.i2c_write_reg_list =
284 i2c_dispatch->i2c_write_reg_list;
285 context->mod_dispatch.pi_get_config_info = pi_get_config_info;
287 OPT_MICRO_CALL(pi_full_init(context));
294 * Get a port with the requested feature set from the list. Don't allocate
295 * it just return it. Only consider ports that aren't already in use.
300 * @return port on success
301 * @return NULL on failure
303 igd_display_port_t *pi_get_feature_port(unsigned long feature,
304 igd_display_port_t *last)
306 igd_display_port_t *port;
307 inter_module_dispatch_t *md = &pi_context->igd_context->mod_dispatch;
309 while ((port = md->dsp_get_next_port(pi_context->igd_context, last, 0))) {
312 if (port->port_features & feature) {
326 * Function to register port driver with display driver
330 * @return PD_SUCCESS on success
331 * @return PD_ERR_NULL_PTR, PD_ERR_VER_MISMATCH, PD_ERR_DISPLAY_TYPE,
332 * PD_ERR_NOMEM on failure
334 int pi_pd_register(pd_driver_t *pd_driver)
336 igd_display_port_t *port;
337 igd_param_t *init_params;
338 unsigned long prev_dab = 0, prev_i2c_speed = 0;
339 unsigned long port_type, port_feature, second_port_feature = 0;
340 unsigned long cookie_sent, cookie_rcvd;
341 unsigned long num_instances = 0;
342 unsigned long prev_instance_dab = 0, prev_instance_i2c_reg = 0;
343 unsigned long dab_index = 0;
344 int ret = PD_SUCCESS;
349 EMGD_ERROR_EXIT("Null pd_driver received.");
350 return PD_ERR_NULL_PTR;
353 /* Check the PD SDK version (interface version between main and
354 * port drivers Rightnow this check is useful only for XFree86.
355 * XP and CE already done this checking. */
356 if (pd_driver->pd_sdk_version != PD_SDK_VERSION) {
357 EMGD_ERROR("PD SDK version mismatch between main driver"
358 "and %s. %u.%u != %u.%u", pd_driver->name,
359 (unsigned short) PD_SDK_VERSION>>8,
360 (unsigned short) PD_SDK_VERSION & 0xFF,
361 (unsigned short) pd_driver->pd_sdk_version>>8,
362 (unsigned short) pd_driver->pd_sdk_version & 0xFF);
363 return PD_ERR_VER_MISMATCH;
366 /* Do magic cookie hand shaking */
368 cookie_sent = get_magic_cookie(pd_driver);
372 cookie_rcvd = pd_driver->validate(cookie_sent);
373 if (cookie_sent != cookie_rcvd) {
374 /* TODO: Do this check once we comeup with handshake algorithm. */
376 EMGD_ERROR("Error, magic cookie handshaking failed.");
377 return PD_ERR_HAND_SHAKE;
381 init_params = pi_context->igd_context->mod_dispatch.init_params;
384 /* Get the port features based on the display types */
385 if (pd_driver->type == PD_DISPLAY_CRT) {
386 /* Allocate GMCH onboard CRT port */
387 port_type = IGD_PORT_ANALOG;
388 } else if (pd_driver->type == PD_DISPLAY_LVDS_INT) {
389 /* Allocate GMCH onboard LVDS port */
390 port_type = IGD_PORT_LVDS;
391 } else if (pd_driver->type == PD_DISPLAY_TVOUT_INT) {
392 /* Allocate GMCH onboard TV port */
393 port_type = IGD_PORT_TV;
394 } else if (pd_driver->type &
395 (PD_DISPLAY_TVOUT | PD_DISPLAY_FP | PD_DISPLAY_CRT_EXT |
396 PD_DISPLAY_LVDS_EXT | PD_DISPLAY_HDMI_EXT| PD_DISPLAY_HDMI_INT|
399 /* Allocate DVO port which is the only kind of port exported to
400 * 3rd party encoders */
401 port_type = IGD_PORT_DIGITAL;
403 if (pd_driver->flags & PD_FLAG_GANG_MODE) {
404 igd_display_port_t *portb;
405 unsigned long user_gang = 0;
407 pi_context->igd_context->mod_dispatch.dsp_get_display(2,
410 if (portb->attr_list && portb->attr_list->num_attrs != 0) {
412 for (i = 0; i < portb->attr_list->num_attrs; i++) {
413 if (portb->attr_list->attr[i].id==PD_ATTR_ID_GANG_MODE){
414 user_gang = portb->attr_list->attr[i].value;
419 /* If both user attribute and port driver flag are set to GANG MODE,
420 * then allocate a gang display port */
422 port_feature = IGD_PORT_GANG;
423 second_port_feature = IGD_PORT_GANG;
426 } else if (pd_driver->type == PD_DISPLAY_RGBA) {
427 port_type = IGD_PORT_DIGITAL;
428 port_feature = IGD_RGBA_COLOR;
429 second_port_feature = IGD_RGBA_ALPHA;
431 EMGD_ERROR_EXIT("Invalid display type.");
432 return PD_ERR_DISPLAY_TYPE;
435 /* Get the port entry */
437 while((port = pi_get_feature_port(port_feature, port))) {
441 /* This port already has a port driver,
442 * don't search device on this port. */
443 if (port->pd_driver || (port->port_type != port_type)) {
447 /* allocate memory for callback */
448 port->callback = (pd_callback_t *)OS_ALLOC(sizeof(pd_callback_t));
449 if (port->callback == NULL) {
450 EMGD_ERROR_EXIT("Unable to alloc memory for callback context.");
453 /* Fill entries in pd_callback_t */
454 port->callback->callback_context = port;
455 port->callback->read_regs = pi_read_regs;
456 port->callback->write_regs = pi_write_regs;
457 port->callback->eld = NULL; /* Insert when edid is initialize */
459 /* SDVO port driver needs the port number */
460 port->callback->port_num = port->port_number;
462 /* now save the pd_driver in port entry */
463 port->pd_driver = pd_driver;
465 /* preference is to user specified i2c_speed */
466 prev_dab = port->dab;
467 prev_i2c_speed = port->i2c_speed;
468 if (!port->i2c_speed) {
469 port->i2c_speed = pd_driver->i2c_speed?pd_driver->i2c_speed:
473 /* Try detecting the encoder by calling port driver open() */
475 ((port->dab == 0) && (pd_driver->dab_list[0] == PD_DAB_LIST_END))) {
477 /* Workaround for not to detect 2 encoders if only 1 encoder
478 * is present and both DVOB and DVOC are using same I2C bus */
479 if ((init_params->display_flags & IGD_DISPLAY_MULTI_DVO) &&
480 (num_instances > 0) &&
481 (prev_instance_dab == port->dab) &&
482 (prev_instance_i2c_reg == port->i2c_reg)) {
483 /* Print this msg, because user explicitly mentioned DAB/I2C
484 * bus details which are same as previous encoder's DAB/I2C bus
486 EMGD_DEBUG("1+ encoders have same I2C bus and DAB");
489 /* Call open() only once if either user provides a DAB
491 * no required to open an encoder. ex: analog, rgba, lvds etc.
493 EMGD_DEBUG("Looking for \"%s\" on port 0x%lx with DAB 0x%lx",
494 pd_driver->name, port->port_reg, port->dab);
495 ret = pd_driver->open(port->callback, &(port->pd_context));
499 /* Call open() for each DAB */
500 while (pd_driver->dab_list[dab_index] != PD_DAB_LIST_END) {
501 if(pd_driver->type == PD_DISPLAY_LVDS_INT) {
502 port->ddc_dab = pd_driver->dab_list[dab_index];
503 printk ("NUHAIRI: port->ddc_dab\n" );
505 port->dab = pd_driver->dab_list[dab_index];
508 /* Workaround for not to detect 2 encoders if only 1 encoder
509 * is present and both DVOB and DVOC are using same I2C bus */
510 if ((init_params->display_flags & IGD_DISPLAY_MULTI_DVO) &&
511 (num_instances > 0) &&
512 (prev_instance_dab == port->dab) &&
513 (prev_instance_i2c_reg == port->i2c_reg)) {
514 /* Don't print the debug msg, because this is a valid case.
516 * Algorithm is detecting for multiple encoders with
517 * same DAB and same I2C bus on different ports.
518 * If this case arises, simply continue
520 /* EMGD_DEBUG("1+ encoders have same I2C bus and DAB"); */
521 if (pd_driver->flags & PD_FLAG_DUAL_DVO) {
522 /* If this flag is set, that means port driver is
523 * explicityly requesting to be loaded on
524 * both DVO B & DVO C with same DAB. Example: CH7017.
526 * In this case open the port driver again. */
529 port->pd_context = NULL;
535 EMGD_DEBUG("Looking for \"%s\" on port 0x%lx with DAB 0x%lx",
536 pd_driver->name, port->port_reg, port->dab);
537 ret = pd_driver->open(port->callback, &(port->pd_context));
547 if(pi_context->igd_context->mod_dispatch.check_port_supported && ret == 0){
548 ret = pi_context->igd_context->mod_dispatch.check_port_supported(port);
553 /* Initialize our port entry */
554 ret = pi_pd_init(port, port_feature, second_port_feature, TRUE);
556 port->pd_driver = NULL;
557 port->pd_context = NULL;
558 port->dab = prev_dab;
559 port->i2c_speed = prev_i2c_speed;
560 port->mult_port = NULL;
561 port->timing_table = NULL;
562 port->num_timing = 0;
563 if (port->callback) {
564 OS_FREE(port->callback);
565 port->callback = NULL;
568 EMGD_DEBUG("Device found on %s port for \"%s\"", port->port_name,
571 prev_instance_dab = port->dab;
572 prev_instance_i2c_reg = port->i2c_reg;
575 /* If Multi-DVO support is enabled then detect next encoder of
577 if (init_params->display_flags & IGD_DISPLAY_MULTI_DVO){
578 /* Continue to find next encoder */
581 /* Found one encoder and return to port driver */
585 port->pd_driver = NULL;
586 port->pd_context = NULL;
587 port->dab = prev_dab;
588 port->i2c_speed = prev_i2c_speed;;
589 if (port->callback) {
590 OS_FREE(port->callback);
591 port->callback = NULL;
594 } /* end while(port == feature_port()) */
596 if (num_instances == 0) {
597 EMGD_DEBUG("No device found for \"%s\"", pd_driver->name);
598 return PD_ERR_NOPORT_AVAIL;
603 } /* end pi_pd_register() */
605 /* Function to replace common timings in 1st list with 2nd list, 2nd list
607 void replace_common_dtds(igd_timing_info_t *dtds1,
608 igd_timing_info_t *dtds2)
610 igd_timing_info_t *temp;
613 if (!dtds2 || !dtds1) {
617 while (dtds1->width != IGD_TIMING_TABLE_END) {
621 while (temp->width != IGD_TIMING_TABLE_END && index < NUM_TIMINGS) {
622 /* Replace modes that have common width, height and
623 refresh rate. Removed Dot clock comparison since
624 EDID(CEA modes) may differ in dot clock value.
625 causing duplicate mode.
626 All ial would do a match mode by height, width
629 if ((temp->width == dtds1->width) &&
630 (temp->height == dtds1->height) &&
631 (temp->refresh == dtds1->refresh) &&
632 ((temp->mode_info_flags & PD_SCAN_INTERLACE) ==
633 (dtds1->mode_info_flags & PD_SCAN_INTERLACE))) {
634 dtds1->mode_info_flags &= ~PD_MODE_SUPPORTED;
649 int check_port_attrs(igd_display_port_t *port)
652 unsigned long attr_value = 0;
654 pd_attr_t out_list,*temp_list;
655 temp_list = &out_list;
657 /* Attempt to see if the port driver has this attibutes so it can update
658 the port driver value. For now this is required for internal HDMI which
659 has a different i2c bus and port name from the standard SDVO port driver.
660 DP would most likely use this attribute assuming it uese the same port
662 ret = pi_pd_find_attr_and_value(port, PD_ATTR_ID_PORT_DDC_REG,
663 PD_ATTR_FLAG_GENERAL, NULL, &attr_value);
665 EMGD_DEBUG("ddr_reg value unique = %ld.", attr_value);
666 port->ddc_reg = attr_value;
669 ret = pi_pd_find_attr_and_value(port, PD_ATTR_ID_PORT_NAME,
670 PD_ATTR_FLAG_GENERAL, &(temp_list), &attr_value);
672 EMGD_DEBUG("ddr_reg value unique = %ld.", attr_value);
673 pd_strcpy(port->port_name, temp_list->name);
681 * Function to initialize port driver related members in port table entry
684 * @param port_feature
685 * @param second_port_feature
686 * @param drm_load_time
688 * @return PD_SUCCESS on success
689 * @return 1 on failure
691 int pi_pd_init(igd_display_port_t *port,
692 unsigned long port_feature,
693 unsigned long second_port_feature,
696 igd_display_port_t *second_port;
697 pd_timing_t *user_timings = NULL;
698 pd_timing_t *std_timings = NULL;
699 pd_timing_t *firmware_timings = NULL;
700 pd_timing_t *final_timings = NULL;
701 pd_timing_t *pd_timing_table = NULL;
702 mode_state_t *mstate;
703 int i, ret = PD_SUCCESS;
704 unsigned long edid_flags;
705 unsigned char num_firmware_timings = 0;
706 igd_display_params_t *display_params = NULL;
707 igd_param_t *init_params;
713 /* If the display device is a ganged mode device or RGBA mode, then hook
714 * up second port pointer in first port */
715 if (second_port_feature) {
716 second_port = pi_get_feature_port(second_port_feature, port);
718 /* If second_port is N/A, or second port was already taken by
719 * other port driver, then release main port and return error */
720 if (second_port == NULL || second_port->pd_driver) {
721 EMGD_ERROR_EXIT("Second ganged/RGBA port N/A or already allocated.");
722 return PD_ERR_NOPORT_AVAIL;
724 /* now link second port to first one */
725 port->mult_port = second_port;
728 /* Check port attributes to overwrite port value is any available */
729 check_port_attrs(port);
730 /* Implementation notes to get the timing list:
731 * Any port timing table consists of
735 * based on edid_flags.
737 * If there are no flags, then it defaults to use STD TIMINGS + EDID DTDs
740 /* Get the display params for this port */
741 init_params = pi_context->igd_context->mod_dispatch.init_params;
743 for (i = 0; i < 5; i++) {
744 if (port->port_number == init_params->display_params[i].port_number) {
745 display_params = &init_params->display_params[i];
750 /* Start with STD TIMINGS */
751 edid_flags = IGD_DISPLAY_USE_STD_TIMINGS;
753 /* If there is EDID, then default to use EDID */
754 if (!display_params || (display_params->flags & IGD_DISPLAY_READ_EDID)) {
755 /* Read firmware (EDID/DisplayID) on I2C */
756 ret = pi_context->i2c_dispatch->i2c_read_regs(
757 pi_context->igd_context,
758 port->ddc_reg, /* DDC register */
759 port->ddc_speed, /* DDC speed */
760 port->ddc_dab, /* Data Addr Byte*/
762 firmware_data, /* Values */
763 128, /* Num bytes to read */
766 /* If EDID is present then use EDID.
767 * edid_flags will be corrected later if display_params are present */
769 edid_flags |= IGD_DISPLAY_USE_EDID;
773 /* Check for display params */
774 if (display_params) {
775 if (edid_flags & IGD_DISPLAY_USE_EDID) {
776 /* Adjust edid_flags to use edid_avail
777 * if both edid is present and edid_avail is not 0 */
778 if (display_params->edid_avail) {
779 edid_flags = display_params->edid_avail;
780 EMGD_DEBUG("EDID_Avail: 0x%lx", edid_flags);
783 /* Adjust edid_flags to use edid_not_avail
784 * if edid is not present and edid_not_avail is not 0 */
785 if (display_params->edid_not_avail) {
787 display_params->edid_not_avail & ~IGD_DISPLAY_USE_EDID;
788 EMGD_DEBUG("EDID_Not_Avail: 0x%lx", edid_flags);
793 /* Make a copy of crt_timing_table */
794 /* All crt timings are already enabled in mode_table.c */
795 std_timings = (igd_timing_info_t *) OS_ALLOC(crt_timing_table_size);
796 OS_MEMCPY(std_timings, crt_timing_table, crt_timing_table_size);
798 /* Include Standard built-in modes */
799 if (edid_flags & IGD_DISPLAY_USE_STD_TIMINGS) {
800 EMGD_DEBUG("Using STD TIMINGS ");
801 final_timings = std_timings;
804 /* Include user DTDs */
805 if (edid_flags & IGD_DISPLAY_USE_USERDTDS) {
806 EMGD_DEBUG("Using USER-DTDs ");
807 user_timings = get_user_timings(port->dtd_list);
810 /* Add user DTDs at the begining of the final timings */
811 user_timings[port->dtd_list->num_dtds].extn_ptr = final_timings;
812 final_timings = user_timings;
816 /* Include EDID timings and filter modes */
817 if (edid_flags & IGD_DISPLAY_USE_EDID) {
818 EMGD_DEBUG("Using EDID-DTDs ");
819 ret = get_firmware_timings(port, firmware_data, final_timings);
820 if (port->firmware_type == PI_FIRMWARE_EDID) {
821 firmware_timings = port->edid->timings;
822 num_firmware_timings = port->edid->num_timings;
823 } else if (port->firmware_type == PI_FIRMWARE_DISPLAYID) {
824 firmware_timings = port->displayid->timings;
825 num_firmware_timings = port->displayid->num_timings;
827 if (ret == 0 && num_firmware_timings) {
828 /* Add EDID DTDs at the begining of the final timings */
829 firmware_timings[num_firmware_timings].extn_ptr =
830 (void *)final_timings;
831 final_timings = firmware_timings;
835 /* Replace any common timings */
836 replace_common_dtds(std_timings, firmware_timings);
837 replace_common_dtds(std_timings, user_timings);
838 replace_common_dtds(firmware_timings, user_timings);
840 /* Count the number of timings in final_timings. If the above functions
841 * result in an empty timing list, then use std_timings as default.
843 if (!get_native_dtd(final_timings, PI_SUPPORTED_TIMINGS, NULL, 0)) {
844 EMGD_DEBUG("User options resulted in 0 timings; using std timings.");
845 final_timings = std_timings;
846 enable_disable_timings(final_timings, 1);
849 /* Update port driver attributes */
852 /* Now get the timing list filtered by PORT DRIVER */
853 ret = port->pd_driver->get_timing_list(port->pd_context,
854 final_timings, &pd_timing_table);
856 if (ret || !pd_timing_table) {
857 EMGD_ERROR_EXIT("port driver: get timing list error.");
858 return PD_ERR_NO_TIMINGS;
861 /* Delete temporary lists and buffers */
863 OS_FREE(user_timings);
866 OS_FREE(std_timings);
869 /* Filter modes based on chipset type */
870 pi_context->igd_context->mod_dispatch.filter_modes(pi_context->igd_context,
871 port, pd_timing_table);
873 /* Now save the timings in port */
874 port->timing_table = pd_timing_table;
875 port->num_timing = get_native_dtd(pd_timing_table,
876 PI_SUPPORTED_TIMINGS, &port->fp_native_dtd, PD_MODE_DTD_FP_NATIVE);
878 assign_dynamic_numbers(port->timing_table);
880 #ifdef DEBUG_FIRMWARE
883 EMGD_DEBUG("Supported timings for \"%s\" (%lu)",
884 port->pd_driver->name, port->num_timing);
886 while (port->timing_table[ti].width != PD_TIMING_LIST_END) {
887 if (port->timing_table[ti].mode_info_flags & PD_MODE_SUPPORTED) {
888 EMGD_DEBUG("\t%ux%u@%u dclk=%lu mode_num=%d hsync=%luKHz "
889 "vsync=%luHz flags=0x%lx",
890 port->timing_table[ti].width,
891 port->timing_table[ti].height,
892 port->timing_table[ti].refresh,
893 port->timing_table[ti].dclk,
894 port->timing_table[ti].mode_number,
895 port->timing_table[ti].dclk/port->timing_table[ti].htotal,
896 ((port->timing_table[ti].dclk * 1000)/
897 port->timing_table[ti].htotal)/
898 port->timing_table[ti].vtotal,
899 port->timing_table[ti].mode_info_flags);
908 * Exit early when called by emgd_driver_pre_init to poke the X driver's
909 * (i.e. "xorg.conf") DTDs and attr's into the port drivers (done above).
911 if (!drm_load_time) {
919 * There is only two states that need to be saved; one is the regular state
920 * and the other is for the console.
922 ret = pi_save_mode_state(port, REG_MODE_STATE_REG);
923 if (config_drm.init) {
924 ret = pi_save_mode_state(port, REG_MODE_STATE_CON);
928 if(port->displayid != NULL){
929 /* Driver to init audio if cea extension available */
930 if(port->firmware_type == PI_FIRMWARE_EDID){
931 port->callback->eld = &(port->edid->cea);
933 /* Displayid unsupported for now. Uncomment this code when audio
934 information is available for Display ID
935 else if(port->firmware_type == PI_FIRMWARE_EDID){
936 port->callback->eld = &(port->displayid->cea);
940 port->callback->eld = NULL;
943 ret = port->pd_driver->init_device(port->pd_context);
946 /* TODO: Restore the pd state? */
947 EMGD_ERROR_EXIT("port driver: init_device error. ret = %d", ret);
949 mstate->pd_state[pi_context->num_pi_drivers].port = NULL;
950 mstate->pd_state[pi_context->num_pi_drivers].state = NULL;
956 /* Increment the number of port drivers */
957 pi_context->num_pi_drivers++;
959 /* save the port driver display type & flags in port. These additions are
960 * required to support different types displays by same port driver. */
961 port->pd_type = port->pd_driver->type;
962 port->pd_flags = port->pd_driver->flags;
966 } /* end pi_pd_init */
969 * Function to read registers
975 * @return PD_SUCCESS on success
976 * @return PD_ERR_NULL_PTR, PD_ERR_I2C_READ, PD_ERR_UNSUCCESSFUL on failure
978 int pi_read_regs(void *callback_context, pd_reg_t *list, unsigned long type)
981 igd_display_port_t *port = callback_context;
987 EMGD_ERROR_EXIT("Null callback context passed.");
988 return PD_ERR_NULL_PTR;
991 if (!port->pd_driver) {
992 EMGD_ERROR_EXIT("Null pd_driver in port entry.");
993 return PD_ERR_NULL_PTR;
996 mmio = EMGD_MMIO(pi_context->igd_context->device_context.virt_mmadr);
998 /* Based on the port type either read GMCH registers or I2C registers */
1002 while (list->reg != PD_REG_LIST_END) {
1003 ret = pi_context->i2c_dispatch->i2c_read_regs(
1004 pi_context->igd_context,
1008 (unsigned char)list->reg,
1009 (unsigned char *)&list->value, 1, 0);
1011 EMGD_DEBUG("i2c_read_reg: 0x%lx failed.", list->reg);
1017 return PD_ERR_I2C_READ;
1022 while (list->reg != PD_REG_LIST_END) {
1023 ret = pi_context->i2c_dispatch->i2c_read_regs(
1024 pi_context->igd_context,
1028 (unsigned char)list->reg,
1029 (unsigned char *)&list->value, 1,
1032 EMGD_DEBUG("i2c_read_reg: 0x%lx failed.", list->reg);
1038 return PD_ERR_I2C_READ;
1043 while (list->reg != PD_REG_LIST_END) {
1044 ret = pi_context->i2c_dispatch->i2c_read_regs(
1045 pi_context->igd_context,
1049 (unsigned char)list->reg,
1050 (unsigned char *)&list->value, 1,
1053 EMGD_DEBUG("i2c_read_reg: 0x%lx failed.", list->reg);
1059 return PD_ERR_I2C_READ;
1063 while (list->reg != PD_REG_LIST_END) {
1064 list->value = EMGD_READ_PORT8(list->reg);
1069 while (list->reg != PD_REG_LIST_END) {
1070 list->value = EMGD_READ_PORT16(list->reg);
1075 while (list->reg != PD_REG_LIST_END) {
1076 list->value = EMGD_READ_PORT32(list->reg);
1082 if ((port->port_type == IGD_PORT_ANALOG) ||
1083 (port->port_type == IGD_PORT_TV) || /* For Integrated TV */
1084 (port->port_type == IGD_PORT_LVDS) ||
1085 (port->port_type == IGD_PORT_DIGITAL)) {
1086 while (list->reg != PD_REG_LIST_END) {
1087 if (type == PD_REG_MIO) {
1088 if (BIT31 & list->reg) {
1090 /* Atom E6xx si hack: Si folks defined LVDS (0:2:0)
1091 * related register in 0:3:0 (sdvo device) as they
1092 * are afraid to touch Lincroft hardmacro.
1093 * This triggered LVDS port driver to touch 0:3:0
1094 * registers for its operation. As this is done for
1095 * LVDS operation and LVDS port driver is internal,
1096 * BIT31 is defined to access 0:3:0 device. */
1097 list->value = READ_MMIO_REG_TNC(IGD_PORT_SDVO,
1101 list->value = EMGD_READ32(EMGD_MMIO(mmio) + list->reg);
1104 list->value = EMGD_READ8(EMGD_MMIO(mmio) + list->reg);
1112 if (port->port_type == IGD_PORT_LVDS) {
1113 while (list->reg != PD_REG_LIST_END) {
1114 list->value = READ_MMIO_REG_TNC(IGD_PORT_LPC, list->reg);
1121 /* Rightnow this is only to provide the device id */
1122 while (list->reg != PD_REG_LIST_END) {
1124 /* Assume IGD at bus=0, dev=2, func=0 */
1125 EMGD_WRITE_PORT32(0xCF8,
1126 (0x80000000 | (0L << 16) | (2L << 11) | (0L << 8) |
1127 (list->reg & 0xFC)));
1128 list->value = EMGD_READ_PORT32(0xCFC + (list->reg & 0x03));
1130 list->value = pi_context->igd_context->device_context.did;
1134 case PD_REG_BRIDGE_OPCODE:
1135 /* right now, we only return the graphics frequency to calculate the
1136 * PWM Backlight modulation frequency. This is only available for pouslbo */
1137 while (list->reg != PD_REG_LIST_END) {
1138 list->value = pi_context->igd_context->device_context.gfx_freq;
1144 EMGD_ERROR_EXIT("Unknown reg type (0x%lx).", type);
1145 return PD_ERR_UNSUCCESSFUL;
1149 /*EMGD_TRACE_EXIT;*/
1151 } /* end pi_read_regs */
1154 * Function to write registers
1160 * @return 0 on success
1161 * @return PD_ERR_NULL_PTR, PD_ERR_I2C_WRITE, PD_ERR_UNSUCCESSFUL on failure
1163 extern unsigned short io_base_sdvo;
1164 extern unsigned short io_base;
1165 extern unsigned short io_base_sdvo_st;
1166 extern unsigned short io_base_sdvo_st_gpio;
1168 int pi_write_regs(void *callback_context, pd_reg_t *list, unsigned long type)
1170 igd_display_port_t *port = callback_context;
1172 unsigned char *mmio;
1177 EMGD_ERROR_EXIT("Null callback context passed.");
1178 return PD_ERR_NULL_PTR;
1181 if (!port->pd_driver) {
1182 EMGD_ERROR_EXIT("Null pd_driver.");
1183 return PD_ERR_NULL_PTR;
1186 EMGD_DEBUG("Getting mmio");
1187 mmio = EMGD_MMIO(pi_context->igd_context->device_context.virt_mmadr);
1188 EMGD_DEBUG("mmio = 0x%lx", (unsigned long)mmio);
1190 /* Based on the port type either write GMCH registers or I2C registers */
1193 /*This will use shorter delay than PD_REG_DDC*/
1194 ret = pi_context->i2c_dispatch->i2c_write_reg_list(
1195 pi_context->igd_context,
1202 EMGD_DEBUG("i2c_write_reg: 0x%lx = 0x%lx failed.",
1203 list->reg, list->value);
1204 return PD_ERR_I2C_WRITE;
1208 ret = pi_context->i2c_dispatch->i2c_write_reg_list(
1209 pi_context->igd_context,
1216 EMGD_DEBUG("i2c_write_reg: 0x%lx = 0x%lx failed.",
1217 list->reg, list->value);
1218 return PD_ERR_I2C_WRITE;
1222 ret = pi_context->i2c_dispatch->i2c_write_reg_list(
1223 pi_context->igd_context,
1230 EMGD_DEBUG("i2c_write_reg: 0x%lx = 0x%lx failed.",
1231 list->reg, list->value);
1232 return PD_ERR_I2C_WRITE;
1234 EMGD_DEBUG("i2c_write_reg success");
1237 while (list->reg != PD_REG_LIST_END) {
1238 EMGD_WRITE_PORT8(list->reg, list->value);
1241 EMGD_DEBUG("EMGD_WRITE_PORT8 seemed successful");
1244 while (list->reg != PD_REG_LIST_END) {
1245 EMGD_WRITE_PORT16(list->reg, list->value);
1248 EMGD_DEBUG("EMGD_WRITE_PORT16 seemed successful");
1251 while (list->reg != PD_REG_LIST_END) {
1252 EMGD_WRITE_PORT32(list->reg, list->value);
1255 EMGD_DEBUG("EMGD_WRITE_PORT32 seemed successful");
1259 if ((port->port_type == IGD_PORT_ANALOG) ||
1260 (port->port_type == IGD_PORT_TV) || /* For Integrated TV */
1261 (port->port_type == IGD_PORT_LVDS) ||
1262 (port->port_type == IGD_PORT_DIGITAL)) {
1263 while (list->reg != PD_REG_LIST_END) {
1264 if (type == PD_REG_MIO) {
1265 if (BIT31 & list->reg) {
1267 /* BIT31 indicates write to 0:3:0 SDVO device */
1268 WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, list->reg,
1272 EMGD_WRITE32(list->value, EMGD_MMIO(mmio) + list->reg);
1275 EMGD_WRITE8(list->value, EMGD_MMIO(mmio) + list->reg);
1279 EMGD_DEBUG("complicated write seemed successful");
1284 if (port->port_type == IGD_PORT_LVDS) {
1285 while (list->reg != PD_REG_LIST_END) {
1286 WRITE_MMIO_REG_TNC(IGD_PORT_LPC, list->reg, list->value);
1289 EMGD_DEBUG("Write to IGD_PORT_LPC seemed successful");
1294 EMGD_ERROR_EXIT("Unknown reg type (0x%lx).", type);
1295 return PD_ERR_UNSUCCESSFUL;
1301 } /* end pi_write_regs */
1304 * Depending on the parameters, this function does multiple things. It always
1305 * counts and returns the number of [supported] timings. If desired, it also
1306 * finds the timing with a desired "mode_info_flags" that has the largest value
1307 * of width, height, OR refresh rate, which it sets to the "native_dtd"
1315 * @return 0 on failure
1316 * @return native dtd on success
1318 unsigned long get_native_dtd(igd_timing_info_t *timing,
1319 unsigned long flags, pd_timing_t **native_dtd, unsigned long nflags)
1321 unsigned long entries = 0;
1331 while (timing->width != IGD_TIMING_TABLE_END) {
1332 if (flags & PI_SUPPORTED_TIMINGS) {
1333 if (timing->mode_info_flags & PD_MODE_SUPPORTED) {
1337 (timing->mode_info_flags & nflags)) {
1338 /* Native Resolution is defined as the largest resolution the
1339 * panel can display. However, some panels contain more than one
1340 * DTD in its EDID. We will choose the largest resolution
1341 * available from EDID */
1342 if(((*native_dtd) && (nflags == PD_MODE_DTD)) &&
1343 (((pd_timing_t*)(*native_dtd))->width > timing->width ||
1344 ((pd_timing_t*)(*native_dtd))->height > timing->height ||
1345 ((pd_timing_t*)(*native_dtd))->refresh > timing->refresh)){
1348 *native_dtd = timing;
1356 if ((timing->width == PD_TIMING_LIST_END) && timing->extn_ptr) {
1357 timing = timing->extn_ptr;
1365 #ifndef CONFIG_MICRO
1366 unsigned long get_magic_cookie(pd_driver_t *pd_driver)
1368 /* FIXME: Implement cookie checking */
1374 * Function to filter modes based on EDID or DisplayID
1377 * @param firmware_data
1378 * @param timing_table
1380 * @return 0 on success
1381 * @return -IGD_ERROR_EDID, -IGD_ERROR_NOMEM on failure
1383 int get_firmware_timings(igd_display_port_t *port,
1384 unsigned char *firmware_data, igd_timing_info_t *timing_table)
1387 displayid_t *displayid;
1392 if (!firmware_data) {
1393 return -IGD_ERROR_EDID;
1396 if (!port->displayid) {
1397 /* EDID and DisplayID use same memory */
1398 displayid = (displayid_t *) OS_ALLOC(sizeof(displayid_t));
1400 return -IGD_ERROR_NOMEM;
1402 edid = (edid_t *) displayid;
1404 displayid = port->displayid;
1405 edid = (edid_t *) displayid;
1407 OS_MEMSET(displayid, 0, sizeof(displayid_t));
1409 /* Now parse the EDID or DisplayID */
1410 /* Check the header to determine whether the data is EDID or DisplayID */
1411 /* EDID header first 8 bytes =
1412 * byte 0, 1, 2, 3: 00 ff ff ff = unsigned long 0xFFFFFF00
1413 * byte 4, 5, 6, 7: ff ff ff 00 = unsigned long 0x00FFFFFF */
1414 if (*(unsigned long *) &firmware_data[0] == 0xFFFFFF00 &&
1415 *(unsigned long *) &firmware_data[4] == 0x00FFFFFF) {
1416 #ifdef DEBUG_FIRMWARE
1417 firmware_dump(firmware_data, 256);
1419 /* This is EDID data */
1420 ret = edid_parse(firmware_data, edid, timing_table, 0,
1421 (unsigned char) (port->pd_driver->flags&PD_FLAG_UP_SCALING?1:0));
1422 if (ret == EDID_READ_AGAIN) {
1423 /* Check to see if there is an extension block */
1424 if((firmware_data[0x7e] == 0x1)){
1425 ret = pi_context->i2c_dispatch->i2c_read_regs(
1426 pi_context->igd_context,
1427 port->ddc_reg, /* DDC register */
1428 port->ddc_speed, /* DDC speed */
1429 port->ddc_dab, /* Data Addr Byte*/
1430 0x80, /* Register */
1431 &firmware_data[128], /* Values */
1433 0); /* next 128 bytes include extension */
1434 ret = edid_ext_parse(&firmware_data[128], edid, timing_table,0,
1435 (unsigned char)(port->pd_driver->flags&
1436 PD_FLAG_UP_SCALING?1:0));
1437 /* Parse next 128 bytes of EDID block */
1443 return -IGD_ERROR_EDID;
1446 port->firmware_type = PI_FIRMWARE_EDID;
1447 #ifdef DEBUG_FIRMWARE
1451 #ifndef CONFIG_NO_DISPLAYID
1453 /* size = payload + 5 */
1454 /* +5 is for the 5 mandatory bytes not included in payload */
1455 unsigned short displayid_size = firmware_data[1] + 5;
1456 if (displayid_size > 256) {
1457 EMGD_DEBUG("Invalid DisplayID size = %u (incl 5 mand bytes) > 256",
1459 return -IGD_ERROR_EDID;
1462 /* If the DisplayID is greater than 128 bytes */
1463 if (displayid_size > 128) {
1464 ret = pi_context->i2c_dispatch->i2c_read_regs(
1465 pi_context->igd_context,
1466 port->ddc_reg, /* DDC register */
1467 port->ddc_speed, /* DDC speed */
1468 port->ddc_dab, /* Data Addr Byte*/
1470 firmware_data, /* Values */
1471 displayid_size, /* Num bytes to read */
1475 #ifdef DEBUG_FIRMWARE
1476 firmware_dump(firmware_data, 256);
1478 /* This is DisplayID data */
1479 ret = displayid_parse(firmware_data, displayid, timing_table, 0,
1480 (unsigned char) (port->pd_driver->flags&PD_FLAG_UP_SCALING?1:0));
1482 port->firmware_type = PI_FIRMWARE_DISPLAYID;
1486 #ifdef DEBUG_FIRMWARE
1487 displayid_print(firmware_data, displayid);
1490 /* If DisplayID isn't enabled then print a debug message and return error */
1492 EMGD_ERROR_EXIT("EDID header is wrong! Will ignore");
1493 return -IGD_ERROR_EDID;
1501 } /* end get_firmware_timings() */
1504 * Update port driver attributes with incoming values from IAL
1506 * @param in_list attributes in this list are used to update corresponding
1507 * attributes in out_list
1508 * @param fp_info flat panel attributes used to update ocrresponding
1509 * attributes in out_list
1510 * @param out_num_attrs size of out_list
1511 * @param out_list contains a list of attributes to be updated
1515 int update_attrs(igd_display_port_t *port)
1520 igd_param_attr_list_t *in_list = port->attr_list;
1521 igd_param_fp_info_t *fp_info = port->fp_info;
1523 /* Initial 5 attributes are for fp_info,
1524 * Note: If both igd_param_fp_info_t and fp_info attributes
1525 * were specified then fp_info values takes the precedence */
1526 unsigned long out_num_attrs = 5;
1527 pd_attr_t *out_list;
1531 /* if: there's something in in_list */
1533 out_num_attrs += in_list->num_attrs;
1536 out_list = OS_ALLOC(sizeof(pd_attr_t) * out_num_attrs);
1538 EMGD_DEBUG("No memory to make attr_list.");
1541 OS_MEMSET(out_list, 0, sizeof(pd_attr_t) * out_num_attrs);
1543 /* Pass user specified attributes */
1545 /* For every incoming attr, make a pd_attr_t */
1546 for (i = 0; i < in_list->num_attrs; i++) {
1547 /* This will work for all kinds of attributes:
1548 * in_list->attr[i].value =
1549 * actual value for range attributes
1550 * index for list attributes
1551 * value for boolean attributes.
1552 * This works because
1553 * pd_attr_t, pd_range_attr_t, pd_list_attr_t,
1554 * pd_boolean_attr_t all have save offsets for
1555 * default values. */
1556 out_list[i].id = in_list->attr[i].id;
1557 out_list[i].flags = PD_ATTR_FLAG_VALUE_CHANGED;
1558 out_list[i].current_value = in_list->attr[i].value;
1560 } /* if: there's something in in_list */
1562 /* Pass flat panel attributes to the port driver, if necessary */
1564 /* Initialize flat panel attributes */
1565 /* Update FP attributes */
1566 if (fp_info->fp_pwr_method == IGD_PARAM_FP_PWR_METHOD_PD) {
1567 /* The only thing remaining is the FP_PWR_Tx, so check
1568 * to ensure it is for an FP_PWR_METHOD_PD */
1569 out_list[i].id = PD_ATTR_ID_FP_PWR_T1;
1570 out_list[i].flags = PD_ATTR_FLAG_VALUE_CHANGED;
1571 out_list[i++].current_value = fp_info->fp_pwr_t1;
1573 out_list[i].id = PD_ATTR_ID_FP_PWR_T2;
1574 out_list[i].flags = PD_ATTR_FLAG_VALUE_CHANGED;
1575 out_list[i++].current_value = fp_info->fp_pwr_t2;
1577 out_list[i].id = PD_ATTR_ID_FP_PWR_T3;
1578 out_list[i].flags = PD_ATTR_FLAG_VALUE_CHANGED;
1579 out_list[i++].current_value = fp_info->fp_pwr_t3;
1581 out_list[i].id = PD_ATTR_ID_FP_PWR_T4;
1582 out_list[i].flags = PD_ATTR_FLAG_VALUE_CHANGED;
1583 out_list[i++].current_value = fp_info->fp_pwr_t4;
1585 out_list[i].id = PD_ATTR_ID_FP_PWR_T5;
1586 out_list[i].flags = PD_ATTR_FLAG_VALUE_CHANGED;
1587 out_list[i++].current_value = fp_info->fp_pwr_t5;
1591 #ifndef CONFIG_NO_DISPLAYID
1592 /* Based on our architecture, any user-defined config option will override
1593 * firmware options. i.e., First send the DisplayID attributes
1594 * then send the config attributes to port drivers. */
1595 if (port->firmware_type == PI_FIRMWARE_DISPLAYID) {
1596 ret = port->pd_driver->set_attrs(port->pd_context,
1597 port->displayid->num_attrs,
1598 port->displayid->attr_list);
1601 ret = port->pd_driver->set_attrs(port->pd_context, i, out_list);
1603 EMGD_DEBUG("Attribute update failed. ret = %d.", ret);
1609 } /* update_attrs */
1611 /* Add user defined timings to big timing table */
1612 pd_timing_t *get_user_timings(igd_param_dtd_list_t *in_list)
1614 pd_timing_t *t = NULL, *timing = NULL;
1615 igd_display_info_t *dtd;
1621 if (!in_list || !(in_list->num_dtds) || !(in_list->dtd)) {
1625 t = (pd_timing_t *)OS_ALLOC((in_list->num_dtds + 1)
1626 * sizeof(pd_timing_t));
1631 OS_MEMSET(t, 0, (in_list->num_dtds + 1) * sizeof(pd_timing_t));
1636 * OPTIMIZEME: When igd_display_info_t goes away there will be no reason
1637 * to copy this data. A Rule can be imposed that anything passed to
1638 * the HAL during init must remain in scope until the HAL is shut
1639 * down. The HAL can then just use this directly.
1641 for (i = 0; i < in_list->num_dtds; i++) {
1642 OS_MEMCPY(t, dtd, sizeof(igd_display_info_t));
1643 t->mode_info_flags = dtd->flags | PD_MODE_DTD_USER | PD_MODE_SUPPORTED;
1645 /* Assume there is no border, then htotal and vtotal are the same as
1646 * hblank_end and vblank_end */
1647 t->htotal = t->hblank_end;
1648 t->vtotal = t->vblank_end;
1650 t->refresh = (unsigned short)dtd->refresh;
1651 } else if (t->htotal && t->vtotal) {
1652 t->refresh = (unsigned short)
1653 ((unsigned long)((unsigned long)(t->dclk) * 1000) /
1654 ((unsigned long)(t->htotal) *
1655 (unsigned long)(t->vtotal)));
1659 #ifndef CONFIG_MICRO
1661 * If the VESA flag is set, set the mode mode number to VESA.
1662 * DTD may not contain mode number but the VESA flag is set
1663 * This will cause program pipe VGA to be executed and fail
1664 * Need to make sure that if USER wants to use VGA mode, that the
1665 * mode_number is entered in the user DTD
1667 if((t->mode_info_flags & PD_MODE_VESA) && (!t->mode_number)){
1668 t->mode_number = VGA_MODE_NUM_MAX + 1;
1672 * Handle the corner case where user DTD is derived from std timing.
1673 * Two std timings have border (htotal != h_blank_end).
1674 * Compare the timing attribute with the std timing and use the
1675 * total and refresh rate from std timing.
1676 * Only happens when using Harmonic tool so the change is limited
1677 * to Atom E6xx through the dispatch function
1679 if(pi_context->igd_context->mod_dispatch.get_refresh_in_border){
1680 /* returns 1 if a refresh was obtained */
1681 ret = pi_context->igd_context->mod_dispatch.get_refresh_in_border(t);
1685 /* Assume there is no border, then htotal and vtotal are the same as
1686 * hblank_end and vblank_end */
1687 t->htotal = t->hblank_end;
1688 t->vtotal = t->vblank_end;
1690 t->refresh = (unsigned short)dtd->refresh;
1691 } else if (t->htotal && t->vtotal) {
1693 * Refresh is used mainly for esthetic, mainly in GUI.
1694 * The compiler will truncate the decimals, not rounding
1695 * UP the value (in this case, 59.7 will be 59Hz and not 60Hz
1696 * Need to manually handle the rounding.
1698 * We multiply the dclk by 10, therefore shifting the final
1699 * decimal place by one, then check if the last digit is
1700 * >4 to round up the refresh by 1 after dividing by 10.
1702 unsigned short temp_refresh = (unsigned short)
1703 ((unsigned long)((unsigned long)(t->dclk) * 10000) /
1704 ((unsigned long)(t->htotal) *
1705 (unsigned long)(t->vtotal)));
1706 if((temp_refresh % 10) > 4){
1707 t->refresh = (temp_refresh / 10 ) + 1;
1709 t->refresh = (temp_refresh / 10);
1714 /* t->pd_extn_ptr = NULL; */
1721 /* End the table with end marker */
1722 t->width = IGD_TIMING_TABLE_END;
1730 * Assign dynamic VBE numbers to the modes that do not already have
1731 * VESA defined numbers.
1733 * @param timing_table
1737 #define FIRST_DYNAMIC_MODE_NUMBER 0x120
1738 void assign_dynamic_numbers(igd_timing_info_t *timing_table)
1740 unsigned short next_number = FIRST_DYNAMIC_MODE_NUMBER;
1742 unsigned short vesa_mode_table[] = {
1747 0xffff, 0xffff, 0xffff,
1752 while(timing_table->width != IGD_TIMING_TABLE_END) {
1753 if((timing_table->mode_info_flags & IGD_MODE_SUPPORTED) &&
1754 !(timing_table->mode_info_flags & IGD_MODE_VESA)) {
1756 for (i=0; vesa_mode_table[i] != 0xffff; i+=3) {
1757 if ((timing_table->width == vesa_mode_table[i]) &&
1758 (timing_table->height == vesa_mode_table[i+1])) {
1759 /* This is a VESA Standard mode, so assign it to the
1760 * correct VESA mode number. This can occur with
1761 * modes added either through User Defined DTDs or
1762 * potentially EDID. */
1763 timing_table->mode_number = vesa_mode_table[i+2];
1764 timing_table->mode_info_flags |= IGD_MODE_VESA;
1768 if (vesa_mode_table[i] == 0xffff) {
1769 /* Assign this mode a Dynamic number, if it is not
1770 * a VESA Standard mode. */
1771 timing_table->mode_number = next_number;
1772 /* VBE modes use lower 2 bits for depth so next mode is += 4 */
1774 timing_table->mode_info_flags |= IGD_MODE_VESA;
1779 /* If reached the first table END,
1780 * then check for the added modes */
1781 if (timing_table->width == IGD_TIMING_TABLE_END &&
1782 timing_table->extn_ptr) {
1783 timing_table = timing_table->extn_ptr;
1792 * This is a utility function that can be used througout the HAL.
1793 * It can be used to get a ptr to an attr structure and/or the
1794 * actual current_value of that attribute.
1795 * According to usage modal at time of creation of this function:
1796 * - the *caller_pd_attr must be NULL if the attr was not found.
1797 * - the *attr_value is only changed if the attr was found
1802 * @param caller_pd_attr
1805 * @return 0 on success
1806 * @return -IGD_ERROR_INVAL on failure
1808 int pi_pd_find_attr_and_value(igd_display_port_t *port,
1809 unsigned long attr_id,
1811 pd_attr_t **caller_pd_attr,
1812 unsigned long *attr_value)
1814 unsigned long pd_attr_length = 0;
1815 pd_attr_t *pd_attr_list = NULL;
1816 pd_attr_t *found_pd_attr = NULL;
1820 if(!port || !(port->pd_driver)) {
1821 return -IGD_ERROR_INVAL;
1824 if(flag == PD_ATTR_FLAG_GENERAL){
1825 pd_attr_length = PD_QUERY_GENERAL_ATTR;
1827 port->pd_driver->get_attrs(port->pd_context, &pd_attr_length,
1829 if(!pd_attr_length) {
1830 return -IGD_ERROR_INVAL;
1833 found_pd_attr = pd_get_attr(pd_attr_list, pd_attr_length, attr_id, flag);
1835 if (!found_pd_attr) {
1836 if(caller_pd_attr) {
1837 *caller_pd_attr = NULL;
1841 if(caller_pd_attr) {
1842 *caller_pd_attr = found_pd_attr;
1845 *attr_value = found_pd_attr->current_value;
1858 * @return 0 on success
1859 * @return -IGD_ERROR_INVAL on failure
1861 int pi_get_port_init_attr(igd_display_port_t *port,
1863 unsigned long *value)
1869 if (!port || !port->attr_list) {
1870 return -IGD_ERROR_INVAL;
1873 for (i = 0; i < (unsigned short) port->attr_list->num_attrs; i++) {
1874 if (port->attr_list->attr[i].id == id) {
1875 *value = port->attr_list->attr[i].value;
1881 EMGD_DEBUG("Attribute (0x%ld) Not Found", id);
1883 return -IGD_ERROR_INVAL;
1888 int pi_save_mode_state(igd_display_port_t *port, reg_state_id_t reg_state_id)
1890 int ret = PD_SUCCESS;
1891 mode_state_t *mstate = NULL;
1892 if(pi_context->igd_context->mod_dispatch.reg_get_mod_state) {
1893 module_state_h *state = NULL;
1894 unsigned long *flags = NULL;
1895 pi_context->igd_context->mod_dispatch.reg_get_mod_state(
1901 mstate = (mode_state_t *)(*state);
1905 /* If mode state is present in register context,
1906 * then call save() function to save the port driver's state */
1908 ret = port->pd_driver->pd_save(port->pd_context,
1909 &(mstate->pd_state[pi_context->num_pi_drivers].state), 0);
1911 EMGD_ERROR_EXIT("port driver: reg saving error. ret = %d", ret);
1914 mstate->pd_state[pi_context->num_pi_drivers].port = port;