Move the drivers to a separate sub-directory
[profile/ivi/intel-emgd-kmod.git] / drivers / emgd / display / pi / cmn / pi.c
1 /*
2  *-----------------------------------------------------------------------------
3  * Filename: pi.c
4  * $Revision: 1.25 $
5  *-----------------------------------------------------------------------------
6  * Copyright (c) 2002-2010, Intel Corporation.
7  *
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:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
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
24  * THE SOFTWARE.
25  *
26  *-----------------------------------------------------------------------------
27  * Description:
28  *  This file contains all the necessary functions for port interface
29  *  module. This module abstracts all hardware port interfaces and
30  *  manages them.
31  *-----------------------------------------------------------------------------
32  */
33
34 #define MODULE_NAME hal.dpd
35
36 #include <config.h>
37 #include <igd.h>
38 #include <igd_errno.h>
39 #include <igd_init.h>
40 #include <igd_pwr.h>
41
42 #include <io.h>
43 #include <pci.h>
44 #include <sched.h>
45 #include <memory.h>
46
47 #include <context.h>
48 #include <mode.h>
49 #include <utils.h>
50 #include <dsp.h>
51 #include <debug.h>
52 #include <pi.h>
53 #include <pd.h>
54 #include <pd_init.h>
55 #include <intelpci.h>
56 #include <dispatch.h>
57 #include <mode_access.h>
58 #include <edid.h>
59 #include <displayid.h>
60 #include <emgd_drv.h>
61
62 #include "i2c_dispatch.h"
63 #include <igd_vga.h>
64 #include <context.h>
65
66 /*!
67  * @addtogroup display_group
68  * @{
69  */
70
71 typedef struct _pi_context {
72         igd_context_t *igd_context;
73         i2c_dispatch_t *i2c_dispatch;
74         unsigned long num_pi_drivers;
75 } pi_context_t;
76
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);
80
81 int pi_pd_init(igd_display_port_t *port, unsigned long port_feature,
82         unsigned long second_port_feature, int drm_load_time);
83 #ifndef CONFIG_MICRO
84 unsigned long get_magic_cookie(pd_driver_t *pd_driver);
85 #endif
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);
89
90
91 extern int pi_init_all(void *handle);
92
93 extern emgd_drm_config_t config_drm;
94 extern i2c_dispatch_t i2c_dispatch_plb;
95 extern i2c_dispatch_t i2c_dispatch_tnc;
96
97 int null_func( void )
98 {
99         return -IGD_ERROR_NODEV;
100 }
101 /* Not currently used
102 static i2c_dispatch_t i2c_dispatch_null = {
103         (void *)null_func,
104         (void *)null_func,
105         (void *)null_func,
106         (void *)null_func
107 }; */
108
109
110 static dispatch_table_t i2c_dispatch_list[] = {
111
112 #ifdef CONFIG_PLB
113         {PCI_DEVICE_ID_VGA_PLB, &i2c_dispatch_plb},
114 #endif
115 #ifdef CONFIG_TNC
116         {PCI_DEVICE_ID_VGA_TNC, &i2c_dispatch_tnc},
117 #endif
118
119         {0, NULL}
120 };
121
122 static unsigned char firmware_data[256];
123
124 static pi_context_t pi_context[1];
125
126 /*----------------------------------------------------------------------
127  *                        FUNCTION DEFINITIONS
128  *----------------------------------------------------------------------*/
129 #ifndef CONFIG_MICRO
130 /*!
131  *
132  * @param context
133  *
134  * @return void
135  */
136 static void pi_shutdown(igd_context_t *context)
137 {
138         igd_display_port_t *port;
139
140         EMGD_TRACE_ENTER;
141
142         if (pi_context->igd_context == NULL) {
143                 return;
144         }
145
146         /* Close the port drivers */
147         port = NULL;
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;
157                         if (port->fp_info) {
158                                 OS_FREE(port->fp_info);
159                                 port->fp_info = NULL;
160                         }
161                         if (port->callback) {
162                                 OS_FREE(port->callback);
163                                 port->callback = NULL;
164                         }
165                 }
166         }
167
168         EMGD_TRACE_EXIT;
169         return;
170 }
171
172 /*!
173  *
174  * @param context
175  *
176  * @return 0
177  */
178 int pi_full_init(igd_context_t *context)
179 {
180         /* Optional Inter-module interfaces */
181         context->mod_dispatch.pi_shutdown = pi_shutdown;
182         return 0;
183 }
184
185 #endif
186
187 /*!
188  *
189  * @param context
190  * @param config_info
191  *
192  * @return 0
193  */
194 static int pi_get_config_info(igd_context_t *context,
195         igd_config_info_t *config_info)
196 {
197
198         igd_display_port_t   *port = NULL;
199         igd_param_t          *init_params = NULL;
200         igd_display_params_t *display_params = NULL;
201         int                   i;
202
203         EMGD_TRACE_ENTER;
204
205         EMGD_ASSERT(context, "Null context", -IGD_ERROR_INVAL);
206         EMGD_ASSERT(config_info, "Null config_info", -IGD_ERROR_INVAL);
207
208         config_info->num_act_dsp_ports = pi_context->num_pi_drivers;
209
210         init_params = pi_context->igd_context->mod_dispatch.init_params;
211
212         while ((port = pi_context->igd_context->mod_dispatch.
213                 dsp_get_next_port(pi_context->igd_context, port, 0)) != NULL) {
214
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];
219                                 break;
220                         }
221                 }
222
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)) {
228
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;
233
234                 } else {
235                         config_info->displayid_rotation[port->port_number - 1].rotation = 0;
236                         config_info->displayid_rotation[port->port_number - 1].flip = 0;
237                 }
238         }
239
240         EMGD_TRACE_EXIT;
241         return 0;
242 }
243
244 /*!
245  *
246  * @param context
247  *
248  * @return 0
249  */
250 int pi_init(igd_context_t *context)
251 {
252         i2c_dispatch_t *i2c_dispatch;
253
254         EMGD_TRACE_ENTER;
255
256         OS_MEMSET(pi_context, 0, sizeof(pi_context_t));
257
258         /* Save igd_context in local_igd_context. */
259         pi_context->igd_context = context;
260
261         /* Get I2C dispatch table */
262         i2c_dispatch = (i2c_dispatch_t *)dispatch_acquire(context,
263                 i2c_dispatch_list);
264         if(!i2c_dispatch) {
265                 EMGD_DEBUG("No i2c Dispatch available for PI module");
266         }
267         pi_context->i2c_dispatch = i2c_dispatch;
268
269         /*
270          * If Dynamic Port drivers are not used then init the static drivers
271          * now.
272          */
273 #ifndef IGD_DPD_ENABLED
274         {
275                 void *handle = NULL;
276                 int ret;
277                 ret = pi_init_all(handle);
278         }
279 #endif
280
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;
286
287         OPT_MICRO_CALL(pi_full_init(context));
288
289         EMGD_TRACE_EXIT;
290         return 0;
291 }
292
293 /*!
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.
296  *
297  * @param feature
298  * @param last
299  *
300  * @return port on success
301  * @return NULL on failure
302  */
303 igd_display_port_t *pi_get_feature_port(unsigned long feature,
304         igd_display_port_t *last)
305 {
306         igd_display_port_t *port;
307         inter_module_dispatch_t *md = &pi_context->igd_context->mod_dispatch;
308
309         while ((port = md->dsp_get_next_port(pi_context->igd_context, last, 0))) {
310                 if (!port->inuse) {
311                         if (feature) {
312                                 if (port->port_features & feature) {
313                                         return port;
314                                 }
315                         } else {
316                                 return port;
317                         }
318                 }
319                 last = port;
320         }
321
322         return NULL;
323 }
324
325 /*!
326  * Function to register port driver with display driver
327  *
328  * @param pd_driver
329  *
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
333  */
334 int pi_pd_register(pd_driver_t *pd_driver)
335 {
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;
345
346         EMGD_TRACE_ENTER;
347
348         if (!pd_driver) {
349                 EMGD_ERROR_EXIT("Null pd_driver received.");
350                 return PD_ERR_NULL_PTR;
351         }
352
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;
364         }
365
366         /* Do magic cookie hand shaking */
367 #ifndef CONFIG_MICRO
368         cookie_sent = get_magic_cookie(pd_driver);
369 #else
370         cookie_sent = 0;
371 #endif
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. */
375                 /*
376                 EMGD_ERROR("Error, magic cookie handshaking failed.");
377                 return PD_ERR_HAND_SHAKE;
378                 */
379         }
380
381         init_params = pi_context->igd_context->mod_dispatch.init_params;
382
383         port_feature = 0;
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|
397                          PD_DISPLAY_DRGB)) {
398
399                 /* Allocate DVO port which is the only kind of port exported to
400                  * 3rd party encoders */
401                 port_type = IGD_PORT_DIGITAL;
402
403                 if (pd_driver->flags & PD_FLAG_GANG_MODE) {
404                         igd_display_port_t *portb;
405                         unsigned long user_gang = 0;
406                         /* Get DVO Port B */
407                         pi_context->igd_context->mod_dispatch.dsp_get_display(2,
408                                 NULL, &portb, 0);
409                         if(portb) {
410                                 if (portb->attr_list && portb->attr_list->num_attrs != 0) {
411                                         unsigned long i;
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;
415                                                 }
416                                         }
417                                 }
418                         }
419                         /* If both user attribute and port driver flag are set to GANG MODE,
420                          * then allocate a gang display port */
421                         if (user_gang) {
422                                 port_feature = IGD_PORT_GANG;
423                                 second_port_feature = IGD_PORT_GANG;
424                         }
425                 }
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;
430         } else {
431                 EMGD_ERROR_EXIT("Invalid display type.");
432                 return PD_ERR_DISPLAY_TYPE;
433         }
434
435         /* Get the port entry */
436         port = NULL;
437         while((port = pi_get_feature_port(port_feature, port))) {
438                 dab_index = 0;
439
440
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)) {
444                         continue;
445                 }
446
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.");
451                         return PD_ERR_NOMEM;
452                 }
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 */
458
459                 /*      SDVO port driver needs the port number */
460                 port->callback->port_num = port->port_number;
461
462                 /* now save the pd_driver in port entry */
463                 port->pd_driver = pd_driver;
464
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:
470                                 I2C_DEFAULT_SPEED;
471                 }
472
473                 /* Try detecting the encoder by calling port driver open() */
474                 if (port->dab ||
475                         ((port->dab == 0) && (pd_driver->dab_list[0] == PD_DAB_LIST_END))) {
476
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
485                                  * details. */
486                                 EMGD_DEBUG("1+ encoders have same I2C bus and DAB");
487                                 ret = -1;
488                         } else {
489                                 /* Call open() only once if either user provides a DAB
490                                  *                      or
491                                  * no required to open an encoder. ex: analog, rgba, lvds etc.
492                                  */
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));
496                         }
497                 } else {
498
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" );
504                 } else {
505                                         port->dab = pd_driver->dab_list[dab_index];
506                 }
507
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.
515                                          * Example,
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
519                                          */
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.
525                                                  *
526                                                  * In this case open the port driver again. */
527                                         } else {
528                                                 ret = -1;
529                                                 port->pd_context = NULL;
530                                                 dab_index++;
531                                                 continue;
532                                         }
533                                 }
534
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));
538                                 if (ret == 0) {
539                                         break;
540                                 } else {
541
542                                         dab_index++;
543                                 }
544                         }
545                 }
546 #ifndef CONFIG_MICRO
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);
549                 }
550 #endif
551                 if (ret == 0) {
552
553                         /* Initialize our port entry */
554                         ret = pi_pd_init(port, port_feature, second_port_feature, TRUE);
555                         if (ret) {
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;
566                                 }
567                         } else {
568                                 EMGD_DEBUG("Device found on %s port for \"%s\"", port->port_name,
569                                         pd_driver->name);
570                                 num_instances++;
571                                 prev_instance_dab = port->dab;
572                                 prev_instance_i2c_reg = port->i2c_reg;
573                         }
574
575                         /* If Multi-DVO support is enabled then detect next encoder of
576                          * same kind */
577                         if (init_params->display_flags & IGD_DISPLAY_MULTI_DVO){
578                                 /* Continue to find next encoder */
579                                 continue;
580                         } else {
581                                 /* Found one encoder and return to port driver */
582                                 break;
583                         }
584                 } else {
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;
592                         }
593                 }
594         } /* end while(port == feature_port()) */
595
596         if (num_instances == 0) {
597                 EMGD_DEBUG("No device found for \"%s\"", pd_driver->name);
598                 return PD_ERR_NOPORT_AVAIL;
599         }
600
601         EMGD_TRACE_EXIT;
602         return PD_SUCCESS;
603 } /* end pi_pd_register() */
604
605 /* Function to replace common timings in 1st list with 2nd list, 2nd list
606  * is unchanged. */
607 void replace_common_dtds(igd_timing_info_t *dtds1,
608         igd_timing_info_t *dtds2)
609 {
610         igd_timing_info_t *temp;
611         int index;
612
613         if (!dtds2 || !dtds1) {
614                 return;
615         }
616
617         while (dtds1->width != IGD_TIMING_TABLE_END) {
618                 temp = dtds2;
619                 index = 0;
620
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
627                            and refresh rate.
628                         */
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;
635                         }
636                         temp++;
637                         index++;
638                 }
639                 dtds1++;
640         }
641 }
642
643 /*!
644  *
645  * @param port
646  *
647  * @return 0
648  */
649 int check_port_attrs(igd_display_port_t *port)
650 {
651         int          ret;
652         unsigned long         attr_value = 0;
653 #ifndef CONFIG_MICRO
654         pd_attr_t             out_list,*temp_list;
655         temp_list = &out_list;
656 #endif
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
661           number as well*/
662         ret = pi_pd_find_attr_and_value(port, PD_ATTR_ID_PORT_DDC_REG,
663                 PD_ATTR_FLAG_GENERAL, NULL, &attr_value);
664         if(!ret){
665                 EMGD_DEBUG("ddr_reg value unique = %ld.", attr_value);
666                 port->ddc_reg = attr_value;
667         }
668 #ifndef CONFIG_MICRO
669         ret = pi_pd_find_attr_and_value(port, PD_ATTR_ID_PORT_NAME,
670                 PD_ATTR_FLAG_GENERAL, &(temp_list), &attr_value);
671         if(!ret){
672                 EMGD_DEBUG("ddr_reg value unique = %ld.", attr_value);
673                 pd_strcpy(port->port_name, temp_list->name);
674         }
675 #endif
676         return 0;
677
678 }
679
680 /*!
681  * Function to initialize port driver related members in port table entry
682  *
683  * @param port
684  * @param port_feature
685  * @param second_port_feature
686  * @param drm_load_time
687  *
688  * @return PD_SUCCESS on success
689  * @return 1 on failure
690  */
691 int pi_pd_init(igd_display_port_t *port,
692         unsigned long port_feature,
693         unsigned long second_port_feature,
694         int drm_load_time)
695 {
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;
708
709         EMGD_TRACE_ENTER;
710
711         mstate = NULL;
712
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);
717
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;
723                 }
724                 /* now link second port to first one */
725                 port->mult_port = second_port;
726         }
727
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
732          *          EDID DTDS
733          *          USER DTDS
734          *          STD TIMINGS
735          *   based on edid_flags.
736          *
737          * If there are no flags, then it defaults to use STD TIMINGS + EDID DTDs
738          */
739
740         /* Get the display params for this port */
741         init_params = pi_context->igd_context->mod_dispatch.init_params;
742
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];
746                         break;
747                 }
748         }
749
750         /* Start with STD TIMINGS */
751         edid_flags = IGD_DISPLAY_USE_STD_TIMINGS;
752
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*/
761                         0,                  /* Register */
762                         firmware_data,      /* Values */
763                         128,               /* Num bytes to read */
764                         0);
765
766                 /* If EDID is present then use EDID.
767                  * edid_flags will be corrected later if display_params are present */
768                 if (ret == 0) {
769                         edid_flags |= IGD_DISPLAY_USE_EDID;
770                 }
771         }
772
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);
781                         }
782                 } else {
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) {
786                                 edid_flags =
787                                         display_params->edid_not_avail & ~IGD_DISPLAY_USE_EDID;
788                                 EMGD_DEBUG("EDID_Not_Avail: 0x%lx", edid_flags);
789                         }
790                 }
791         }
792
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);
797
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;
802         }
803
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);
808
809                 if (user_timings) {
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;
813                 }
814         }
815
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;
826                 }
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;
832                 }
833         }
834
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);
839
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.
842          */
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);
847         }
848
849         /* Update port driver attributes */
850         update_attrs(port);
851
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);
855
856         if (ret || !pd_timing_table) {
857                 EMGD_ERROR_EXIT("port driver: get timing list error.");
858                 return PD_ERR_NO_TIMINGS;
859         }
860
861         /* Delete temporary lists and buffers */
862         if (user_timings) {
863                 OS_FREE(user_timings);
864         }
865         if (std_timings) {
866                 OS_FREE(std_timings);
867         }
868
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);
872
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);
877
878         assign_dynamic_numbers(port->timing_table);
879
880 #ifdef DEBUG_FIRMWARE
881         {
882                 int ti;
883                 EMGD_DEBUG("Supported timings for \"%s\" (%lu)",
884                         port->pd_driver->name, port->num_timing);
885                 ti = 0;
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);
900                         }
901                         ti++;
902                 }
903         }
904 #endif
905
906
907         /*
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).
910          */
911         if (!drm_load_time) {
912                 EMGD_TRACE_EXIT;
913                 return PD_SUCCESS;
914         }
915
916
917 #ifndef CONFIG_MICRO
918         /*
919          * There is only two states that need to be saved; one is the regular state
920          * and the other is for the console.
921          */
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);
925         }
926 #endif
927
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);
932                 }
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);
937                 }
938                 */
939                 else{
940                         port->callback->eld = NULL;
941                 }
942         }
943         ret = port->pd_driver->init_device(port->pd_context);
944         if (ret) {
945 #ifndef CONFIG_MICRO
946                 /* TODO: Restore the pd state? */
947                 EMGD_ERROR_EXIT("port driver: init_device error. ret = %d", ret);
948                 if (mstate) {
949                         mstate->pd_state[pi_context->num_pi_drivers].port = NULL;
950                         mstate->pd_state[pi_context->num_pi_drivers].state = NULL;
951                 }
952 #endif
953                 return ret;
954         }
955
956         /* Increment the number of port drivers */
957         pi_context->num_pi_drivers++;
958
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;
963
964         EMGD_TRACE_EXIT;
965         return PD_SUCCESS;
966 } /* end pi_pd_init */
967
968 /*!
969  * Function to read registers
970  *
971  * @param context
972  * @param list
973  * @param type
974  *
975  * @return PD_SUCCESS on success
976  * @return PD_ERR_NULL_PTR, PD_ERR_I2C_READ, PD_ERR_UNSUCCESSFUL on failure
977  */
978 int pi_read_regs(void *callback_context, pd_reg_t *list, unsigned long type)
979 {
980         int ret;
981         igd_display_port_t *port = callback_context;
982         unsigned char      *mmio;
983
984         /*EMGD_TRACE_EXIT;*/
985
986         if (!port) {
987                 EMGD_ERROR_EXIT("Null callback context passed.");
988                 return PD_ERR_NULL_PTR;
989         }
990
991         if (!port->pd_driver) {
992                 EMGD_ERROR_EXIT("Null pd_driver in port entry.");
993                 return PD_ERR_NULL_PTR;
994         }
995
996         mmio = EMGD_MMIO(pi_context->igd_context->device_context.virt_mmadr);
997
998         /* Based on the port type either read GMCH registers or I2C registers */
999         switch (type) {
1000         case PD_REG_I2C:
1001                 ret = 0;
1002                 while (list->reg != PD_REG_LIST_END) {
1003                         ret = pi_context->i2c_dispatch->i2c_read_regs(
1004                                 pi_context->igd_context,
1005                                 port->i2c_reg,
1006                                 port->i2c_speed,
1007                                 port->dab,
1008                                 (unsigned char)list->reg,
1009                                 (unsigned char *)&list->value, 1, 0);
1010                         if (ret) {
1011                                 EMGD_DEBUG("i2c_read_reg: 0x%lx failed.", list->reg);
1012                                 break;
1013                         }
1014                         list++;
1015                 }
1016                 if (ret) {
1017                         return PD_ERR_I2C_READ;
1018                 }
1019                 break;
1020         case PD_REG_DDC_FW:
1021                 ret = 0;
1022                 while (list->reg != PD_REG_LIST_END) {
1023                         ret = pi_context->i2c_dispatch->i2c_read_regs(
1024                                 pi_context->igd_context,
1025                                 port->ddc_reg,
1026                                 port->ddc_speed,
1027                                 port->ddc_dab,
1028                                 (unsigned char)list->reg,
1029                                 (unsigned char *)&list->value, 1,
1030                                 IGD_I2C_WRITE_FW);
1031                         if (ret) {
1032                                 EMGD_DEBUG("i2c_read_reg: 0x%lx failed.", list->reg);
1033                                 break;
1034                         }
1035                         list++;
1036                 }
1037                 if (ret) {
1038                         return PD_ERR_I2C_READ;
1039                 }
1040                 break;
1041         case PD_REG_DDC:
1042                 ret = 0;
1043                 while (list->reg != PD_REG_LIST_END) {
1044                         ret = pi_context->i2c_dispatch->i2c_read_regs(
1045                                 pi_context->igd_context,
1046                                 port->ddc_reg,
1047                                 port->ddc_speed,
1048                                 port->ddc_dab,
1049                                 (unsigned char)list->reg,
1050                                 (unsigned char *)&list->value, 1,
1051                                 0);
1052                         if (ret) {
1053                                 EMGD_DEBUG("i2c_read_reg: 0x%lx failed.", list->reg);
1054                                 break;
1055                         }
1056                         list++;
1057                 }
1058                 if (ret) {
1059                         return PD_ERR_I2C_READ;
1060                 }
1061                 break;
1062         case PD_REG_PIO8:
1063                 while (list->reg != PD_REG_LIST_END) {
1064                         list->value = EMGD_READ_PORT8(list->reg);
1065                         list++;
1066                 }
1067                 break;
1068         case PD_REG_PIO16:
1069                 while (list->reg != PD_REG_LIST_END) {
1070                         list->value = EMGD_READ_PORT16(list->reg);
1071                         list++;
1072                 }
1073                 break;
1074         case PD_REG_PIO32:
1075                 while (list->reg != PD_REG_LIST_END) {
1076                         list->value = EMGD_READ_PORT32(list->reg);
1077                         list++;
1078                 }
1079                 break;
1080         case PD_REG_MIO :
1081         case PD_REG_MIO8 :
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) {
1089 #ifdef CONFIG_TNC
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,
1098                                                         list->reg);
1099 #endif
1100                                         } else {
1101                                                 list->value = EMGD_READ32(EMGD_MMIO(mmio) + list->reg);
1102                                         }
1103                                 } else {
1104                                         list->value = EMGD_READ8(EMGD_MMIO(mmio) + list->reg);
1105                                 }
1106                                 list++;
1107                         }
1108                 }
1109                 break;
1110 #ifdef CONFIG_TNC
1111         case PD_REG_LPC:
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);
1115                                 list++;
1116                         }
1117                 }
1118                 break;
1119 #endif
1120         case PD_REG_PCI:
1121                 /* Rightnow this is only to provide the device id */
1122                 while (list->reg != PD_REG_LIST_END) {
1123 #if 0
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));
1129 #endif
1130                         list->value = pi_context->igd_context->device_context.did;
1131                         list++;
1132                 }
1133                 break;
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;
1139                         list++;
1140                 }
1141
1142                 break;
1143         default:
1144                 EMGD_ERROR_EXIT("Unknown reg type (0x%lx).", type);
1145                 return PD_ERR_UNSUCCESSFUL;
1146                 break;
1147         }
1148
1149         /*EMGD_TRACE_EXIT;*/
1150         return PD_SUCCESS;
1151 } /* end pi_read_regs */
1152
1153 /*!
1154  * Function to write registers
1155  *
1156  * @param context
1157  * @param list
1158  * @param type
1159  *
1160  * @return 0 on success
1161  * @return PD_ERR_NULL_PTR, PD_ERR_I2C_WRITE, PD_ERR_UNSUCCESSFUL on failure
1162  */
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;
1167
1168 int pi_write_regs(void *callback_context, pd_reg_t *list, unsigned long type)
1169 {
1170         igd_display_port_t *port = callback_context;
1171         int           ret;
1172         unsigned char *mmio;
1173
1174         EMGD_TRACE_ENTER;
1175
1176         if (!port) {
1177                 EMGD_ERROR_EXIT("Null callback context passed.");
1178                 return PD_ERR_NULL_PTR;
1179         }
1180
1181         if (!port->pd_driver) {
1182                 EMGD_ERROR_EXIT("Null pd_driver.");
1183                 return PD_ERR_NULL_PTR;
1184         }
1185
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);
1189
1190         /* Based on the port type either write GMCH registers or I2C registers */
1191         switch (type) {
1192         case PD_REG_DDC_FW:
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,
1196                         port->ddc_reg,
1197                         port->ddc_speed,
1198                         port->ddc_dab,
1199                         list,
1200                         IGD_I2C_WRITE_FW);
1201                 if (ret) {
1202                 EMGD_DEBUG("i2c_write_reg: 0x%lx = 0x%lx failed.",
1203                 list->reg, list->value);
1204                 return PD_ERR_I2C_WRITE;
1205         }
1206         break;
1207         case PD_REG_DDC:
1208                 ret = pi_context->i2c_dispatch->i2c_write_reg_list(
1209                         pi_context->igd_context,
1210                         port->ddc_reg,
1211                         port->ddc_speed,
1212                         port->ddc_dab,
1213                         list,
1214                         0);
1215                 if (ret) {
1216                 EMGD_DEBUG("i2c_write_reg: 0x%lx = 0x%lx failed.",
1217                 list->reg, list->value);
1218                 return PD_ERR_I2C_WRITE;
1219         }
1220         break;
1221         case PD_REG_I2C:
1222                 ret = pi_context->i2c_dispatch->i2c_write_reg_list(
1223                         pi_context->igd_context,
1224                         port->i2c_reg,
1225                         port->i2c_speed,
1226                         port->dab,
1227                         list,
1228                         0);
1229                 if (ret) {
1230                         EMGD_DEBUG("i2c_write_reg: 0x%lx = 0x%lx failed.",
1231                                 list->reg, list->value);
1232                         return PD_ERR_I2C_WRITE;
1233                 }
1234                 EMGD_DEBUG("i2c_write_reg success");
1235                 break;
1236         case PD_REG_PIO8:
1237                 while (list->reg != PD_REG_LIST_END) {
1238                         EMGD_WRITE_PORT8(list->reg, list->value);
1239                         list++;
1240                 }
1241                 EMGD_DEBUG("EMGD_WRITE_PORT8 seemed successful");
1242                 break;
1243         case PD_REG_PIO16:
1244                 while (list->reg != PD_REG_LIST_END) {
1245                         EMGD_WRITE_PORT16(list->reg, list->value);
1246                         list++;
1247                 }
1248                 EMGD_DEBUG("EMGD_WRITE_PORT16 seemed successful");
1249                 break;
1250         case PD_REG_PIO32:
1251                 while (list->reg != PD_REG_LIST_END) {
1252                         EMGD_WRITE_PORT32(list->reg, list->value);
1253                         list++;
1254                 }
1255                 EMGD_DEBUG("EMGD_WRITE_PORT32 seemed successful");
1256                 break;
1257         case PD_REG_MIO :
1258         case PD_REG_MIO8 :
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) {
1266 #ifdef CONFIG_TNC
1267                                                 /* BIT31 indicates write to 0:3:0 SDVO device */
1268                                                 WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, list->reg,
1269                                                         list->value);
1270 #endif
1271                                         } else {
1272                                                 EMGD_WRITE32(list->value, EMGD_MMIO(mmio) + list->reg);
1273                                         }
1274                                 } else {
1275                                         EMGD_WRITE8(list->value, EMGD_MMIO(mmio) + list->reg);
1276                                 }
1277                                 list++;
1278                         }
1279                         EMGD_DEBUG("complicated write seemed successful");
1280                 }
1281                 break;
1282 #ifdef CONFIG_TNC
1283         case PD_REG_LPC:
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);
1287                                 list++;
1288                         }
1289                         EMGD_DEBUG("Write to IGD_PORT_LPC seemed successful");
1290                 }
1291                 break;
1292 #endif
1293         default:
1294                 EMGD_ERROR_EXIT("Unknown reg type (0x%lx).", type);
1295                 return PD_ERR_UNSUCCESSFUL;
1296                 break;
1297         }
1298
1299         EMGD_TRACE_EXIT;
1300         return 0;
1301 } /* end pi_write_regs */
1302
1303 /*!
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"
1308  * parameter.
1309  *
1310  * @param timing
1311  * @param flags
1312  * @param native_dtd
1313  * @param nflags
1314  *
1315  * @return 0 on failure
1316  * @return native dtd on success
1317  */
1318 unsigned long get_native_dtd(igd_timing_info_t *timing,
1319         unsigned long flags, pd_timing_t **native_dtd, unsigned long nflags)
1320 {
1321         unsigned long entries = 0;
1322
1323         EMGD_TRACE_EXIT;
1324
1325         if (!timing) {
1326                 return 0;
1327         }
1328         if (native_dtd) {
1329                 *native_dtd = NULL;
1330         }
1331         while (timing->width != IGD_TIMING_TABLE_END) {
1332                 if (flags & PI_SUPPORTED_TIMINGS) {
1333                         if (timing->mode_info_flags & PD_MODE_SUPPORTED) {
1334                                 entries++;
1335                         }
1336                         if ((native_dtd) &&
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)){
1346                                                 /* do nothing */
1347                                 } else {
1348                                         *native_dtd = timing;
1349                                 }
1350                         }
1351                 } else {
1352                         entries++;
1353                 }
1354
1355                 timing++;
1356                 if ((timing->width == PD_TIMING_LIST_END) && timing->extn_ptr) {
1357                         timing = timing->extn_ptr;
1358                 }
1359         }
1360
1361         EMGD_TRACE_EXIT;
1362         return entries;
1363 }
1364
1365 #ifndef CONFIG_MICRO
1366 unsigned long get_magic_cookie(pd_driver_t *pd_driver)
1367 {
1368         /* FIXME: Implement cookie checking */
1369         return 0;
1370 }
1371 #endif
1372
1373 /*!
1374  * Function to filter modes based on EDID or DisplayID
1375  *
1376  * @param port
1377  * @param firmware_data
1378  * @param timing_table
1379  *
1380  * @return 0 on success
1381  * @return -IGD_ERROR_EDID, -IGD_ERROR_NOMEM on failure
1382  */
1383 int get_firmware_timings(igd_display_port_t *port,
1384         unsigned char *firmware_data, igd_timing_info_t *timing_table)
1385 {
1386         edid_t         *edid;
1387         displayid_t    *displayid;
1388         int            ret = -1;
1389
1390         EMGD_TRACE_ENTER;
1391
1392         if (!firmware_data) {
1393                 return -IGD_ERROR_EDID;
1394         }
1395
1396         if (!port->displayid) {
1397                 /* EDID and DisplayID use same memory */
1398                 displayid = (displayid_t *) OS_ALLOC(sizeof(displayid_t));
1399                 if (!displayid) {
1400                         return -IGD_ERROR_NOMEM;
1401                 }
1402                 edid = (edid_t *) displayid;
1403         } else {
1404                 displayid = port->displayid;
1405                 edid = (edid_t *) displayid;
1406         }
1407         OS_MEMSET(displayid, 0, sizeof(displayid_t));
1408
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);
1418 #endif
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 */
1432                                         128,
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 */
1438                         }else{
1439                                 ret = 0;
1440                         }
1441                 } else if (ret) {
1442                         OS_FREE(edid);
1443                         return -IGD_ERROR_EDID;
1444                 }
1445
1446                 port->firmware_type = PI_FIRMWARE_EDID;
1447 #ifdef DEBUG_FIRMWARE
1448                 edid_print(edid);
1449 #endif
1450
1451 #ifndef CONFIG_NO_DISPLAYID
1452         } else {
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",
1458                                 displayid_size);
1459                         return -IGD_ERROR_EDID;
1460                 }
1461
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*/
1469                                 0,                  /* Register */
1470                                 firmware_data,      /* Values */
1471                                 displayid_size,    /* Num bytes to read */
1472                                 0);
1473                 }
1474
1475 #ifdef DEBUG_FIRMWARE
1476                 firmware_dump(firmware_data, 256);
1477 #endif
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));
1481                 if (!ret) {
1482                         port->firmware_type = PI_FIRMWARE_DISPLAYID;
1483                 } else {
1484                         OS_FREE(displayid);
1485                 }
1486 #ifdef DEBUG_FIRMWARE
1487                 displayid_print(firmware_data, displayid);
1488 #endif
1489 #else
1490         /* If DisplayID isn't enabled then print a debug message and return error */
1491         } else {
1492                 EMGD_ERROR_EXIT("EDID header is wrong! Will ignore");
1493                 return -IGD_ERROR_EDID;
1494 #endif
1495         }
1496
1497         port->edid = edid;
1498
1499         EMGD_TRACE_EXIT;
1500         return ret;
1501 } /* end get_firmware_timings() */
1502
1503 /*!
1504  * Update port driver attributes with incoming values from IAL
1505  *
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
1512  *
1513  * @return 0
1514  */
1515 int update_attrs(igd_display_port_t *port)
1516 {
1517         int          ret;
1518         unsigned int i = 0;
1519
1520         igd_param_attr_list_t *in_list = port->attr_list;
1521         igd_param_fp_info_t   *fp_info = port->fp_info;
1522
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;
1528
1529         EMGD_TRACE_ENTER;
1530
1531         /* if: there's something in in_list */
1532         if (in_list) {
1533                 out_num_attrs += in_list->num_attrs;
1534         }
1535
1536         out_list = OS_ALLOC(sizeof(pd_attr_t) * out_num_attrs);
1537         if (!out_list) {
1538                 EMGD_DEBUG("No memory to make attr_list.");
1539                 return 0;
1540         }
1541         OS_MEMSET(out_list, 0, sizeof(pd_attr_t) * out_num_attrs);
1542
1543         /* Pass user specified attributes */
1544         if (in_list) {
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;
1559                 }
1560         }  /* if: there's something in in_list */
1561
1562         /* Pass flat panel attributes to the port driver, if necessary */
1563         if (fp_info) {
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;
1572
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;
1576
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;
1580
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;
1584
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;
1588                 }
1589         }
1590
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);
1599         }
1600 #endif
1601         ret = port->pd_driver->set_attrs(port->pd_context, i, out_list);
1602         if (ret) {
1603                 EMGD_DEBUG("Attribute update failed. ret = %d.", ret);
1604         }
1605         OS_FREE(out_list);
1606
1607         EMGD_TRACE_EXIT;
1608         return 0;
1609 } /* update_attrs */
1610
1611 /* Add user defined timings to big timing table */
1612 pd_timing_t *get_user_timings(igd_param_dtd_list_t *in_list)
1613 {
1614         pd_timing_t        *t = NULL, *timing = NULL;
1615         igd_display_info_t *dtd;
1616         unsigned long i;
1617         int ret = 0;
1618
1619         EMGD_TRACE_ENTER;
1620
1621         if (!in_list || !(in_list->num_dtds) || !(in_list->dtd)) {
1622                 return NULL;
1623         }
1624
1625         t = (pd_timing_t *)OS_ALLOC((in_list->num_dtds + 1)
1626                         * sizeof(pd_timing_t));
1627         if (!t) {
1628                 return NULL;
1629         }
1630
1631         OS_MEMSET(t, 0, (in_list->num_dtds + 1) * sizeof(pd_timing_t));
1632         timing = t;
1633         dtd = in_list->dtd;
1634
1635         /*
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.
1640          */
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;
1644 #if 0
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;
1649                 if (dtd->refresh) {
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)));
1656                 }
1657 #endif
1658
1659 #ifndef CONFIG_MICRO
1660                /*
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
1666                 */
1667                if((t->mode_info_flags & PD_MODE_VESA) && (!t->mode_number)){
1668                        t->mode_number = VGA_MODE_NUM_MAX + 1;
1669                }
1670
1671                /*
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
1678                 */
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);
1682                }
1683 #endif
1684                if(!ret){
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;
1689                        if (dtd->refresh) {
1690                                t->refresh = (unsigned short)dtd->refresh;
1691                        } else if (t->htotal && t->vtotal) {
1692                                /*
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.
1697                                 *
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.
1701                                 */
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;
1708                                } else {
1709                                        t->refresh = (temp_refresh / 10);
1710                                }
1711                        }
1712                }
1713
1714                 /* t->pd_extn_ptr = NULL; */
1715                 t->extn_ptr = NULL;
1716
1717                 t++;
1718                 dtd++;
1719         }
1720
1721         /* End the table with end marker */
1722         t->width = IGD_TIMING_TABLE_END;
1723
1724         EMGD_TRACE_EXIT;
1725
1726         return timing;
1727 }
1728
1729 /*!
1730  * Assign dynamic VBE numbers to the modes that do not already have
1731  * VESA defined numbers.
1732  *
1733  * @param timing_table
1734  *
1735  * @return void
1736  */
1737 #define FIRST_DYNAMIC_MODE_NUMBER 0x120
1738 void assign_dynamic_numbers(igd_timing_info_t *timing_table)
1739 {
1740         unsigned short next_number = FIRST_DYNAMIC_MODE_NUMBER;
1741         unsigned int i;
1742         unsigned short vesa_mode_table[] = {
1743                 640, 480, 0x101,
1744                 800, 600, 0x103,
1745                 1024, 768, 0x105,
1746                 1280, 1024, 0x107,
1747                 0xffff, 0xffff, 0xffff,
1748         };
1749
1750         EMGD_TRACE_ENTER;
1751
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)) {
1755
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;
1765                                         break;
1766                                 }
1767                         }
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 */
1773                                 next_number += 4;
1774                                 timing_table->mode_info_flags |= IGD_MODE_VESA;
1775                         }
1776                 }
1777                 timing_table++;
1778
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;
1784                 }
1785         }
1786
1787         EMGD_TRACE_EXIT;
1788         return;
1789 }
1790
1791 /*!
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
1798  *
1799  * @param port
1800  * @param attr_id
1801  * @param flag
1802  * @param caller_pd_attr
1803  * @param attr_value
1804  *
1805  * @return 0 on success
1806  * @return -IGD_ERROR_INVAL on failure
1807  */
1808 int pi_pd_find_attr_and_value(igd_display_port_t *port,
1809                 unsigned long attr_id,
1810                 unsigned long flag,
1811                 pd_attr_t   **caller_pd_attr,
1812                 unsigned long *attr_value)
1813 {
1814         unsigned long pd_attr_length   = 0;
1815         pd_attr_t    *pd_attr_list     = NULL;
1816         pd_attr_t    *found_pd_attr    = NULL;
1817
1818         EMGD_TRACE_ENTER;
1819
1820         if(!port || !(port->pd_driver)) {
1821                 return -IGD_ERROR_INVAL;
1822         }
1823
1824         if(flag == PD_ATTR_FLAG_GENERAL){
1825                 pd_attr_length = PD_QUERY_GENERAL_ATTR;
1826         }
1827         port->pd_driver->get_attrs(port->pd_context, &pd_attr_length,
1828                 &pd_attr_list);
1829         if(!pd_attr_length) {
1830                 return -IGD_ERROR_INVAL;
1831         }
1832
1833         found_pd_attr = pd_get_attr(pd_attr_list, pd_attr_length, attr_id, flag);
1834
1835         if (!found_pd_attr) {
1836                 if(caller_pd_attr) {
1837                         *caller_pd_attr = NULL;
1838                 }
1839                 return -IGD_INVAL;
1840         }
1841         if(caller_pd_attr) {
1842                 *caller_pd_attr = found_pd_attr;
1843         }
1844         if(attr_value) {
1845                 *attr_value = found_pd_attr->current_value;
1846         }
1847
1848         EMGD_TRACE_EXIT;
1849         return 0;
1850 }
1851
1852 /*!
1853  *
1854  * @param port
1855  * @param id
1856  * @param value
1857  *
1858  * @return 0 on success
1859  * @return -IGD_ERROR_INVAL on failure
1860  */
1861 int pi_get_port_init_attr(igd_display_port_t *port,
1862                 unsigned long id,
1863                 unsigned long *value)
1864 {
1865         unsigned short i;
1866
1867         EMGD_TRACE_ENTER;
1868
1869         if (!port || !port->attr_list) {
1870                 return -IGD_ERROR_INVAL;
1871         }
1872
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;
1876                         EMGD_TRACE_EXIT;
1877                         return 0;
1878                 }
1879         }
1880
1881         EMGD_DEBUG("Attribute (0x%ld) Not Found", id);
1882         EMGD_TRACE_EXIT;
1883         return -IGD_ERROR_INVAL;
1884 }
1885
1886
1887
1888 int pi_save_mode_state(igd_display_port_t *port, reg_state_id_t reg_state_id)
1889 {
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(
1896                         reg_state_id,
1897                         &state,
1898                         &flags);
1899
1900                 if (state) {
1901                         mstate = (mode_state_t *)(*state);
1902                 }
1903         }
1904
1905         /* If mode state is present in register context,
1906          * then call save() function to save the port driver's state */
1907         if (mstate) {
1908                 ret = port->pd_driver->pd_save(port->pd_context,
1909                                 &(mstate->pd_state[pi_context->num_pi_drivers].state), 0);
1910                 if (ret) {
1911                         EMGD_ERROR_EXIT("port driver: reg saving error. ret = %d", ret);
1912                         return ret;
1913                 }
1914                 mstate->pd_state[pi_context->num_pi_drivers].port = port;
1915         }
1916
1917         return ret;
1918 }
1919