fff675683be0d6b554f152eb013110fef92b5ca2
[profile/ivi/intel-emgd-kmod.git] / emgd / pal / lvds / lvds.c
1 /*
2  *-----------------------------------------------------------------------------
3  * Filename: lvds.c
4  * $Revision: 1.18 $
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 is contains all necessary functions for Internal
29  *  LVDS PORT DRIVER.
30  *  This is written according to the port interface defined in pd.h.
31  *-----------------------------------------------------------------------------
32  */
33 #include <linux/kernel.h>
34
35 #include <linux/version.h>
36 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
37 #include <linux/bug.h>
38 #endif
39 #include <config.h>
40 #include <igd_pd.h>
41 #include <pd.h>
42 #include <pd_print.h>
43
44 #include "lvds.h"
45
46 /* One space between the #define and the backslash,else compilers complain */
47 #define PTR_OFFSET_UCHAR(ptr,offset)   (*((unsigned char *)ptr + offset))
48 #define PTR_OFFSET_USHORT(ptr, offset) (*(unsigned short *)((unsigned char *)ptr + offset))
49
50 #define PTR_OFFSET_ULONG(ptr, offset) (*(unsigned long *)((unsigned char *)ptr + offset))
51 /* END OF OPTIMIZATION MACROS */
52
53 /* This constant = 10,000,000.  The value is used to
54  * get effective results from the integer math, and
55  * to not divide by 0. */
56 #define PWM_FREQ_CALC_CONSTANT_1        0x00989680
57 /* This constant is 1,000,000 - to multiply to get
58  * the Display Clock Frequency to the order of Mhz */
59 #define PWM_FREQ_CALC_CONSTANT_2        0x000F4240
60
61
62 #ifndef ARRAY_SIZE
63 #define ARRAY_SIZE(p) (sizeof(p)/sizeof((p)[0]))
64 #endif
65
66 static pd_version_t  lvds_version = {11, 0, 0, 0}; /* driver version */
67 static unsigned long lvds_dab_list[] = {
68         PD_DAB_LIST_END
69 }; /* dab list */
70
71 static unsigned long supported_chipset[] =
72 {
73 #ifdef CONFIG_855
74         PCI_DEVICE_ID_VGA_855,
75 #endif
76 #ifdef CONFIG_915AL
77         PCI_DEVICE_ID_VGA_915AL,
78 #endif
79 #ifdef CONFIG_945GM
80         PCI_DEVICE_ID_VGA_945GM,
81         PCI_DEVICE_ID_VGA_945GME,
82 #endif
83 #ifdef CONFIG_965GM
84         PCI_DEVICE_ID_VGA_GM965,
85         PCI_DEVICE_ID_VGA_GME965,
86 #endif
87 #ifdef CONFIG_CTG
88         PCI_DEVICE_ID_VGA_CTG,
89 #endif
90 #ifdef CONFIG_PLB
91         PCI_DEVICE_ID_VGA_PLB,
92 #endif
93 #ifdef CONFIG_TNC
94         PCI_DEVICE_ID_VGA_TNC,
95         PCI_DEVICE_ID_VGA_TNC_A0,
96         PCI_DEVICE_ID_VGA_LNC,
97 #endif
98 };
99
100 static pd_driver_t  lvds_driver  = {
101         PD_SDK_VERSION,
102         "Internal LVDS Port Driver",
103         0,
104         &lvds_version,
105         PD_DISPLAY_LVDS_INT,
106         PD_FLAG_UP_SCALING,
107         lvds_dab_list,
108         100,
109         lvds_validate,
110         lvds_open,
111         lvds_init_device,
112         lvds_close,
113         lvds_set_mode,
114         lvds_post_set_mode,
115         lvds_set_attrs,
116         lvds_get_attrs,
117         lvds_get_timing_list,
118         lvds_set_power,
119         lvds_get_power,
120         lvds_save,
121         lvds_restore,
122         lvds_get_port_status
123 };
124
125 /* This is a common attribute table for all chipsets. At the end of the table
126  * there are multiple end entries to add chipset specific attributes.
127  * Chipset specific attributes:
128  *     965GM/GM45- Maintain aspect ratio
129  * Note:
130  *    1. Make sure to update the chipset_attr_index whenever adding a
131  *       chipset specific new attr.
132  */
133 static pd_attr_t lvds_attrs[] =
134 {
135         /* Range attributes */
136
137         /*<-------ID----------->              <----TYPE-------->  <---NAME----->  <----flag---->               <---DEF_VAL---->       <--CURR_VALUE-->      min max  st */
138         PD_MAKE_ATTR (PD_ATTR_ID_FP_PWR_T1,   PD_ATTR_TYPE_RANGE, "FP Power T1",  PD_ATTR_FLAG_USER_INVISIBLE, 0,                     0,                    0,  819,  1),
139         PD_MAKE_ATTR (PD_ATTR_ID_FP_PWR_T2,   PD_ATTR_TYPE_RANGE, "FP Power T2",  PD_ATTR_FLAG_USER_INVISIBLE, 0,                     0,                    0,  819,  1),
140         PD_MAKE_ATTR (PD_ATTR_ID_FP_PWR_T3,   PD_ATTR_TYPE_RANGE, "FP Power T3",  PD_ATTR_FLAG_USER_INVISIBLE, 0,                     0,                    0,  819,  1),
141         PD_MAKE_ATTR (PD_ATTR_ID_FP_PWR_T4,   PD_ATTR_TYPE_RANGE, "FP Power T4",  PD_ATTR_FLAG_USER_INVISIBLE, 0,                     0,                    0,  819,  1),
142         PD_MAKE_ATTR (PD_ATTR_ID_FP_PWR_T5,   PD_ATTR_TYPE_RANGE, "FP Power T5",  PD_ATTR_FLAG_USER_INVISIBLE, 400,                 400,                    0,  3000, 1),
143         PD_MAKE_ATTR (PD_ATTR_ID_PANEL_DEPTH, PD_ATTR_TYPE_RANGE, "Panel Depth",  PD_ATTR_FLAG_USER_INVISIBLE, LVDS_DEF_PANEL_DEPTH,  LVDS_DEF_PANEL_DEPTH, 18, 24,   6),
144
145         PD_MAKE_ATTR (PD_ATTR_ID_PWM_INTENSITY,   PD_ATTR_TYPE_RANGE, "PWM cycle",                        PD_ATTR_FLAG_USER_INVISIBLE,          100,            0,                                0,  100,  0),
146         PD_MAKE_ATTR (PD_ATTR_ID_INVERTER_FREQ,   PD_ATTR_TYPE_RANGE, "Inverter Frequency",       PD_ATTR_FLAG_USER_INVISIBLE,          100,            0,                                0,  0,  0),
147         PD_MAKE_ATTR (PD_ATTR_ID_BLM_LEGACY_MODE, PD_ATTR_TYPE_BOOL,  "Backlight Legacy mode",    PD_ATTR_FLAG_USER_INVISIBLE,          0,              0,                                        0,  0,  0),
148
149         /*<-------ID------------>                 <----TYPE--------> <---NAME----->        <------flag--------------->  <---DEF_VAL---->   <--CURR_VALUE-->   <---pad--> */
150         PD_MAKE_ATTR (PD_ATTR_ID_2_CHANNEL_PANEL, PD_ATTR_TYPE_BOOL, "Dual-channel panel", PD_ATTR_FLAG_USER_INVISIBLE, 0,                 0,                 0, 0, 0),
151         PD_MAKE_ATTR (PD_ATTR_ID_LVDS_PANEL_TYPE, PD_ATTR_TYPE_BOOL, "Panel Type",         PD_ATTR_FLAG_USER_INVISIBLE, 0,                 0,                 0, 0, 0),
152         PD_MAKE_ATTR (PD_ATTR_ID_PANEL_FIT,       PD_ATTR_TYPE_BOOL, "Panel Upscale",      PD_ATTR_FLAG_USER_INVISIBLE, LVDS_DEF_PANEL_FIT,LVDS_DEF_PANEL_FIT,0, 0, 0),
153         PD_MAKE_ATTR (PD_ATTR_ID_DITHER,          PD_ATTR_TYPE_BOOL, "Dither",             PD_ATTR_FLAG_USER_INVISIBLE, LVDS_DEF_DITHER,   LVDS_DEF_DITHER,   0, 0, 0),
154         PD_MAKE_ATTR (LVDS_ATTR_ID_TC_LVDS_CLK,   PD_ATTR_TYPE_BOOL, "TC LVDS CLK 110MHz", PD_ATTR_FLAG_USER_INVISIBLE, 0,                 0,                 0, 0, 0),
155
156         /* Start of chipset specific attributes */
157         /* Maintain aspect ratio */
158         PD_MAKE_ATTR (PD_ATTR_LIST_END,       0,                   "",            0,                           0,                0,               0,     0, 0),
159         /* Text tuning */
160         PD_MAKE_ATTR (PD_ATTR_LIST_END,       0,                   "",            0,                           0,                0,               0,     0, 0),
161
162         /* Attribute list end */
163         PD_MAKE_ATTR (PD_ATTR_LIST_END,       0,                   "",            0,                           0,                0,               0,     0, 0)
164 };
165
166 /* Rightnow it is -3 to reach starting of chipset specific attributes */
167 static unsigned short chipset_attr_index = (unsigned short)
168         sizeof(lvds_attrs)/sizeof(pd_attr_t) - 3;
169
170 static pd_attr_t lvds_965gm_attrs[] = {
171         PD_MAKE_ATTR (PD_ATTR_ID_MAINTAIN_ASPECT_RATIO,PD_ATTR_TYPE_BOOL,      "Maintain Aspect Ratio",0,             0,               0,               0,     0, 0),
172         PD_MAKE_ATTR (PD_ATTR_ID_TEXT_TUNING,          PD_ATTR_TYPE_RANGE,     "Text Enhancement",     0,             0,               0,               0,     2, 1),
173 };
174
175 static void lvds_write_reg(lvds_context_t *pd_context, unsigned long reg,
176                 unsigned long value, unsigned long change_bits, unsigned long reg_type);
177
178 static unsigned long lvds_read_reg(lvds_context_t *pd_context,
179                 unsigned long reg, unsigned long reg_type);
180 static void lvds_panel_fit(lvds_context_t *pd_context);
181
182 static void lvds_get_dclk(lvds_context_t *pd_context, pd_dvo_info_t *lvds_info);
183
184 /*----------------------------------------------------------------------------
185  *
186  * Function: PD_MODULE_INIT(lvds_init)
187  *
188  * Description:
189  *    This is the entry function into LVDS port driver when
190  *    it first loads. This will call pd_register() to register
191  *    with Display driver.  Only the driver object is initialized in this
192  *    function, similar to DrverEntry() in a WDM driver.
193  *
194  * Parameters:
195  *    [OUT] *handle:  Not used.  Place holder for supporting dynamic pd
196  *
197  * Return:
198  *    PD_SUCCESS(0)  success
199  *    PD_ERR_XXXXXX  otherwise
200  *
201  *----------------------------------------------------------------------------
202  */
203
204 int PD_MODULE_INIT(lvds_init, (void *handle))
205 {
206         /* register the LVDS driver */
207         return pd_register(handle, &lvds_driver);
208 }
209
210 /*----------------------------------------------------------------------------
211  *
212  * Function: PD_MODULE_EXIT(lvds_exit, (void))
213  *
214  * Description:
215  *    This function cleans up resources used by the LVDS driver
216  *
217  * Parameters:
218  *    None
219  *
220  * Return:
221  *    PD_SUCCESS(0):  always returns this
222  *
223  *----------------------------------------------------------------------------
224  */
225
226 int PD_MODULE_EXIT(lvds_exit, (void))
227 {
228         return PD_SUCCESS;
229 }
230
231 /*----------------------------------------------------------------------------
232  *
233  * Function: lvds_validate
234  *
235  * Description:
236  *    Place holder for a future function
237  *
238  * Parameters:
239  *    TBD
240  *
241  * Return:
242  *    TBD
243  *
244  *----------------------------------------------------------------------------
245  */
246
247 unsigned long lvds_validate (unsigned long cookie)
248 {                                                          /* lvds_validate */
249         /* Validate magic cookie */
250         /* TODO: Implement the magic cookie algorithm */
251         return cookie;
252 }                                                          /* lvds_validate */
253
254 /*----------------------------------------------------------------------------
255  *
256  * Function: lvds_open
257  *
258  * Description:
259  *    This function creates an LVDS context and intialize it with LVDS
260  *    attributes.
261  *
262  *    Internal LVDS port is available only on MGM platform, this port driver
263  *    reads the GMCH device ID with pd_read_regs(PD_REG_PCI) to verify that
264  *    it is supported on the current platform.
265  *
266  * Parameters:
267  *    [IN] callback:    callback context
268  *    [INOUT] context:  Device context.  This function will set the attributes
269  *                      for this context, provided it is already allocated,
270  *                      i.e. not NULL.
271  *
272  * Return:
273  *    PD_ERR_NULL_PTR:  if either of the parameters is NULL
274  *    PD_ERR_NODEV:     if an LVDS device is already up and running
275  *    PD_ERR_NOMEM:     if a memory allocation failed
276  *    PD_SUCCESS:       if successful
277  *
278  *----------------------------------------------------------------------------
279  */
280
281 /* lvds context structure being declared and initialized */
282
283 static lvds_context_t lvds_context = {  /* lvds context structure */
284         0,                   /* fp_width     */
285         0,                   /* fp_height    */
286         0,                   /* dual_channel: Default single channel */
287         0,                   /* panel_type : 0-SPWG 1-OpenLDI*/
288         LVDS_DEF_PANEL_FIT,  /* panel_fit    */
289         LVDS_DEF_PANEL_DEPTH,/* panel_depth  */
290         0xFFFF,              /* dither       */
291         0,                   /* Main aspect ratio, default no */
292         0,                   /* panel filter: Default fuzzy filtering */
293         100,                 /* PWM Intensity */
294         0xFFFF,              /* Inverter Frequency*/
295         0,                   /* BLM Legacy Mode */
296
297         PD_POWER_MODE_D0,    /* power_state   */
298         0,                   /* chipset       */
299         0,                   /* init_done     */
300         0,                   /* num_attrs */
301         0,                   /* PIPE flags    */
302         0,                   /* Graphics Frequency */
303         0,                   /* is gn4 based LVDS controller? */
304         0,                   /* is pwm_done? */
305         0,                   /* is tc_110MHz_clk? i.e., TC max LVDS to 110MHz*/
306
307         NULL,                /* ptr to callback       */
308         NULL,                /* ptr to timing table   */
309         lvds_attrs,          /* ptr to attribute list */
310         NULL,                /* ptr to native timing  */
311         NULL,                /* current mode */
312 };
313
314 int lvds_open(pd_callback_t *callback, void **context)
315 {                                                              /* lvds_open */
316         lvds_context_t *pd_context = (lvds_context_t*) &(lvds_context); /* static Global */
317         pd_reg_t reg_list[2];
318         int ret, i, valid_chipset = 0;
319         unsigned short chipset;
320
321         PD_TRACE_ENTER;
322
323
324
325         /* make sure parameters are valid */
326         if (!callback || !context) {
327                 PD_ERROR("invalid parameter");
328                 return (PD_ERR_NULL_PTR);
329         }
330         /* GMCH cannot support more than one device */
331         if (lvds_driver.num_devices > 0) {
332                 return (PD_ERR_NODEV);
333         }
334         /* Verify that this is an GMCH with Internal LVDS available */
335         reg_list[0].reg = 2;
336         reg_list[1].reg = PD_REG_LIST_END;
337         ret = callback->read_regs(callback->callback_context, reg_list, PD_REG_PCI);
338         if(ret != PD_SUCCESS) {
339                 return ret;
340         }
341         chipset = (unsigned short)(reg_list[0].value & 0xffff);
342         for (i = 0; i < ARRAY_SIZE(supported_chipset); i++) {
343                 if (chipset == supported_chipset[i]){
344                         valid_chipset = 1;
345                         break;
346                 }
347         }
348         if(!valid_chipset){
349                 return PD_ERR_NODEV;
350         }
351
352         /* Special handling for gn4 and beyond chipsets */
353         if (chipset == PCI_DEVICE_ID_VGA_GM965 ||
354                 chipset == PCI_DEVICE_ID_VGA_GME965 ||
355                 chipset == PCI_DEVICE_ID_VGA_CTG ||
356                 chipset == PCI_DEVICE_ID_VGA_TNC ||
357                 chipset == PCI_DEVICE_ID_VGA_TNC_A0 ||
358                 chipset == PCI_DEVICE_ID_VGA_LNC) {
359                 lvds_context.gn4_plus = 1;
360         }
361
362         /* Initialize number of attributes */
363         /* +1 is to include the end attribute */
364         lvds_context.num_attrs = (unsigned char)chipset_attr_index + 1;
365
366         /* Add chipset specific attrbutes.
367          * This can be expanded into a switch statement in future if required. */
368         if (lvds_context.gn4_plus) {
369                 lvds_context.num_attrs += sizeof(lvds_965gm_attrs)/sizeof(pd_attr_t);
370                 for (i=0; i < sizeof(lvds_965gm_attrs)/sizeof(pd_attr_t); i++) {
371                         lvds_attrs[chipset_attr_index+i] = lvds_965gm_attrs[i];
372                 }
373         }
374         /* Make this a compile time so that size of vBIOS doesn't become > 64KB */
375 #if defined(CONFIG_PLB) || defined(CONFIG_TNC)
376         /* pwm backlight control needs graphics frequency. we currently implement
377          * pwm backlight control for pouslbo only to limit the vbios lvds size. Each
378          * chipset have a different method of getting this value and chipset has a
379          * different multiplier. */
380         if (chipset == PCI_DEVICE_ID_VGA_PLB ||
381             chipset == PCI_DEVICE_ID_VGA_TNC ||
382             chipset == PCI_DEVICE_ID_VGA_TNC_A0 ||
383             chipset == PCI_DEVICE_ID_VGA_LNC) {
384
385                 /* For plb/tnc, graphics frequency is obtained by sending an opcode to
386                  * port 5 in the SCH Message Network. We call the read_regs with
387                  * PD_REG_BRIDGE_OPCODE specifically for this purpose only.
388                  *
389                  * The input for this read_reg is the opcode that register data that
390                  * we send into the Message control register*/
391                 reg_list[1].reg = PD_REG_LIST_END;
392                 ret = callback->read_regs(callback->callback_context,
393                         reg_list, PD_REG_BRIDGE_OPCODE);
394                 if(ret != PD_SUCCESS) {
395                         return ret;
396                 }
397
398                 /*set the graphics frequency*/
399                 pd_context->gfx_freq = (unsigned short) reg_list[0].value;
400         }
401 #endif
402
403         pd_context->callback = callback;           /* Save callback context */
404         pd_context->chipset = chipset;            /* save the chipset ID   */
405         *context = (void *) pd_context;
406
407         PD_TRACE_EXIT;
408         return PD_SUCCESS;
409 }                                                              /* lvds_open */
410
411 /*----------------------------------------------------------------------------
412  *
413  * Function: lvds_init_device
414  *
415  * Description:
416  *    Initializes the LVDS device, using the device context from the parameter
417  *
418  * Parameters:
419  *    [INOUT] context:  device context
420  *
421  * Return:
422  *    PD_ERR_NULL_PTR:  if parameter is invalid
423  *    PD_SUCCESS:       if successful
424  *
425  *----------------------------------------------------------------------------
426  */
427
428 int lvds_init_device (void *context)
429 {                                                       /* lvds_init_device */
430         if (!context) {
431                 return (PD_ERR_NULL_PTR);
432         }
433
434         /* Don't need to do much to initialize this device */
435         ((lvds_context_t *)context)->init_done = 1;
436         lvds_driver.num_devices++;
437
438         return (PD_SUCCESS);
439 }                                                       /* lvds_init_device */
440
441
442 /*----------------------------------------------------------------------------
443  *
444  * Function: lvds_close
445  *
446  * Description:
447  *    Releases resources allocated during lvds_open().  This function
448  *    essentially frees a device object.
449  *
450  * Parameters:
451  *    [INOUT] device_context:  device to be freed
452  *
453  * Return:
454  *    PD_SUCCESS: always returns this
455  *
456  *----------------------------------------------------------------------------
457  */
458
459 int lvds_close(void *device_context)
460 {
461 #ifndef CONFIG_MICRO
462
463         lvds_context_t *pd_context = (lvds_context_t *)device_context;
464
465         /* lvds_close */
466
467         PD_TRACE_ENTER;
468
469         /* Deallocate memory occupied by this device */
470         if (device_context) {
471                 if ( NULL != pd_context->timing_table) {
472                         pd_free(pd_context->timing_table);
473                         pd_context->timing_table = NULL;
474                 }
475
476                 /* Free attribute list, if necessary */
477                 /* FIXME -- The following test will never call pd_free(), because the
478                  * expression "!lvds_driver.num_devices" will yield 0 or 1, and that
479                  * will never be greater than 1.  This is a potentially small memory
480                  * leak, unless some other code frees it.
481                  */
482                 if (!lvds_driver.num_devices > 1) {
483                         pd_free(pd_context->attr_list);
484                 }
485                 /* This allocated statically no need to free it */
486                 /* pd_free(device_context); */
487                 lvds_driver.num_devices--;
488                 pd_context->init_done = 0;
489         }
490
491         PD_TRACE_EXIT;
492 #endif
493         return (PD_SUCCESS);
494 }                                                             /* lvds_close */
495
496 /*----------------------------------------------------------------------------
497  *
498  * Function: lvds_set_mode
499  *
500  * Description:
501  *    Sets LVDS to a new mode, specified by "mode".
502  *
503  * Parameters:
504  *    [INOUT] context:  device context
505  *    [IN]    mode:     information about the mode to switch to
506  *    [IN]    flags:    can contain the following value
507  *                PD_SET_MODE_FLAG_TEST:  only testing to see if mode is supported
508  *
509  * Return:
510  *    PD_ERR_NULL_PTR:     if invalid parameter detected
511  *    PD_ERR_MODE_NOTSUPP: if mode specified is not supported
512  *    PD_SUCCESS:          if successful
513  *
514  *----------------------------------------------------------------------------
515  */
516 int lvds_set_mode(void *context, pd_timing_t *mode, unsigned long flags)
517 {
518         lvds_context_t *pd_context  = NULL;
519
520         PD_DEBUG("lvds_set_mode)\n");
521         PD_TRACE_ENTER;
522
523         pd_context = (lvds_context_t *)context;
524
525         /* Make sure these parameters are valid */
526         if (!pd_context || !mode) {
527                 return (PD_ERR_NULL_PTR);
528         }
529         PD_DEBUG("lvds_set_mode: %ux%u", mode->width, mode->height);
530
531         /* Make sure specified mode is supported */
532         if ((pd_context->fp_width && (mode->width > pd_context->fp_width)) ||
533                 (pd_context->fp_height && (mode->height > pd_context->fp_height))) {
534                 return PD_ERR_MODE_NOTSUPP;
535         }
536
537         /* Do nothing if we are only want to know if a mode is supported */
538         if (flags & PD_SET_MODE_FLAG_TEST) {
539                 return PD_SUCCESS;
540         }
541
542         pd_context->current_mode = mode;
543         pd_context->pipe = flags;
544         /* Enable panel fitting and return */
545         lvds_panel_fit(pd_context);
546
547         PD_TRACE_EXIT;
548
549         return PD_SUCCESS;
550 }
551
552 int lvds_post_set_mode(void *context, pd_timing_t *mode, unsigned long flags)
553 {                                                          /* lvds_set_mode */
554         lvds_context_t *pd_context  = NULL;
555         unsigned long  port_control = 0;
556         unsigned long  preserve     = 0;
557         int            ret          = 0;
558
559         PD_TRACE_ENTER;
560         pd_context = (lvds_context_t *)context;
561
562         PD_DEBUG("lvds_post_set_mode)\n");
563         /* Make sure these parameters are valide */
564         if (!pd_context || !mode) {
565                 return (PD_ERR_NULL_PTR);
566         }
567
568         /* Before enabling the LVDS port, make sure that display PLL for this pipe
569          * is enabled and the port is power sequenced on using the panel power
570          * sequencing logic. */
571
572         preserve = 0x3E007803;
573         port_control = preserve & lvds_read_reg(pd_context, 0x61180, PD_REG_MIO);
574         port_control |= BIT(31);          /* enable LVDS port */
575         if (flags & PD_SET_MODE_PIPE_B) {
576                 port_control |= BIT(30);
577         }
578         port_control |= (BIT(9)|BIT(8));  /* power up */
579         port_control &= ~(BIT(21)|BIT(20)); /* Default sync polarites active high */
580
581         /* For gn4+, dither moved to port_control from panel_fit reg */
582         if (pd_context->gn4_plus) {
583                 if (pd_context->panel_depth == 18) {
584                         port_control |= BIT(25);
585                 }
586
587                 if (pd_context->dither != 0xFFFF) {
588                         if (pd_context->dither) {
589                                 port_control |= BIT(25);
590                         } else {
591                                 port_control &= ~BIT(25);
592                         }
593                 }
594         }
595
596         if((!pd_context->panel_fit) &&
597            ( mode->width < pd_context->fp_width ||
598              mode->height < pd_context->fp_height ) ){
599                 port_control |= BIT(15); /* enable border in active for centering */
600         }
601
602         /*
603          * Bit 24 for OpenLDI should be set to a 0 (1x18.0, 2x18.0, 1x24.0, 2x24.0).
604          * From (B-Spec, Ref# 22316, section 1.15.3.8.3)
605          *
606          * Bit 24 for SPWG should be set to a 1 (1x24.1 or 2x24.1).
607          *
608          * This was verified by comparing the timing diagram for 1x24.0 in
609          * OpenLDI spec (5.4.2.2 24-bit Single Pixel Mode, Unbalanced) with the
610          * same diagram in the Display BSpec for Napa or Gen4.
611          * A0 \96 A3 signals match the 1x24.0.
612          *
613          * From the OpenLDI spec (bit mappings are different):
614          *
615          * Table 5-2, Bit Number Mappings
616          * 18 bpp bit# 24 bpp bit# OpenLDI bit#
617          * 5           7           5
618          * 4           6           4
619          * 3           5           3
620          * 2           4           2
621          * 1           3           1
622          * 0           2           0
623          *             1           7
624          *             0           6
625          */
626
627         /* Attribute panel_type description:
628          *  Attr ID    Attr Value        IntLVDS dataformat
629          *  =======    ===============   ==================
630          *    49       0  (SPWG)           1 (value of Bit 24)
631          *    49       1  (OpenLDI)        0 (value of Bit 24)
632          */
633         if (pd_context->panel_type == 0) {
634                 port_control |= BIT(24); /* Dataformat 0 = SPWG, 1 = OpenLDI */
635         }
636
637         /* If the dual-channel is required, then power up second channel
638          * ClkB and B0, B1, B2, (B3) */
639         if (pd_context->dual_channel) {
640                 port_control |= (BIT(5)|BIT(4));  /* ClkB */
641                 port_control |= (BIT(3)|BIT(2));  /* B0, B1, B2, (B3) */
642         }
643
644         /* Check for 18 or 24 bit panel */
645         if (pd_context->panel_depth == 24) {
646                 /* If the panel is 24-bit (8-bpp), enable A3, (B3) pair. */
647                 port_control |= (BIT(7)|BIT(6));
648         }
649
650         /* Set the sync polarities correctly if there is a native dtd */
651         if (pd_context->native_dtd) {
652                 /* Set bit 20 for hsync active low */
653                 if ((pd_context->native_dtd->mode_info_flags & PD_HSYNC_HIGH) == 0) {
654                         port_control |= BIT(20);
655                 }
656                 /* Set bit 21 for vsync active low */
657                 if ((pd_context->native_dtd->mode_info_flags & PD_VSYNC_HIGH) == 0) {
658                         port_control |= BIT(21);
659                 }
660         }
661
662     lvds_write_reg(pd_context, 0x61204, 0xABCD0000, 0xFFFFFFFF, PD_REG_MIO);
663
664         lvds_write_reg(pd_context, 0x61180, port_control, 0xFFFFFFFF, PD_REG_MIO);
665         ret = lvds_set_power(pd_context, PD_POWER_MODE_D0);
666         if (ret) {
667                 PD_ERROR("PD set_power (D0) returned: 0x%x", ret);
668                 return ret;
669         }
670
671     lvds_write_reg(pd_context, 0x61204, BIT(1), BIT(1), PD_REG_MIO);
672
673
674         PD_TRACE_EXIT;
675         /* Set the mode as per given timings */
676         return PD_SUCCESS;
677 }                                                          /* lvds_set_mode */
678
679 /*----------------------------------------------------------------------------
680  *
681  * Function: lvds_set_attrs
682  *
683  * Description:
684  *    Incorporate attributes in "list" into the device context.  This function
685  *    will override the initial attributes set by init_attrs.
686  *
687  * Parameters:
688  *    [INOUT] context:  device context
689  *    [IN] num:         not used, but must not be 0.
690  *    [IN] list:        list of attributes to incorporate into device context
691  *
692  * Return:
693  *    PD_ERR_NULL_PTR:          if one of the parameters is invalid
694  *    PD_ERR_ATTR_CANT_CHANGE:  attributes cannot be modified
695  *    PD_SUCCESS: if successful
696  *
697  *----------------------------------------------------------------------------
698  */
699 /* Tables required by Optimization Code. lvds_set_attrs() */
700 typedef struct _opt_table_data {
701         unsigned long id;
702         unsigned short block;
703         unsigned short offset;
704 } lvds_opt_table_data_t;
705 static lvds_opt_table_data_t table_opt_data1[] = {
706
707         /*<--- id ---------->  <---block---> <------ offset -------------------> */
708         {PD_ATTR_ID_PANEL_DEPTH,     1, PD_OFFSETOF(lvds_context_t, panel_depth) },
709
710         {PD_ATTR_ID_2_CHANNEL_PANEL, 1, PD_OFFSETOF(lvds_context_t, dual_channel)},
711         {PD_ATTR_ID_LVDS_PANEL_TYPE, 1, PD_OFFSETOF(lvds_context_t, panel_type) },
712         {PD_ATTR_ID_PANEL_FIT,       1, PD_OFFSETOF(lvds_context_t, panel_fit)   },
713         {PD_ATTR_ID_DITHER,          1, PD_OFFSETOF(lvds_context_t, dither)      },
714         {PD_ATTR_ID_MAINTAIN_ASPECT_RATIO,1,PD_OFFSETOF(lvds_context_t,aspect_ratio)},
715         {PD_ATTR_ID_TEXT_TUNING,     1, PD_OFFSETOF(lvds_context_t, text_tune)},
716         {PD_ATTR_ID_PWM_INTENSITY,   1, PD_OFFSETOF(lvds_context_t, pwm_intensity)},
717         {PD_ATTR_ID_INVERTER_FREQ,   1, PD_OFFSETOF(lvds_context_t, inverter_freq)},
718         {PD_ATTR_ID_BLM_LEGACY_MODE, 1, PD_OFFSETOF(lvds_context_t, blm_legacy_mode)},
719         {LVDS_ATTR_ID_TC_LVDS_CLK,   1, PD_OFFSETOF(lvds_context_t, tc_110MHz_clk)},
720
721         /*<--- id ---------->  <---block---> <------ offset -------------------> */
722         {PD_ATTR_ID_FP_PWR_T1,       2,     0 }, /* 6 */
723         {PD_ATTR_ID_FP_PWR_T2,       2,     0 }, /* 7 */
724         {PD_ATTR_ID_FP_PWR_T3,       2,     0 }, /* 8 */
725         {PD_ATTR_ID_FP_PWR_T4,       2,     0 }, /* 9 */
726         {PD_ATTR_ID_FP_PWR_T5,       2,     0 }  /* 10 */
727 };
728 /* End of Tables required by Optimization Code. lvds_set_attrs() */
729
730 int lvds_set_attrs (void *context, unsigned long num, pd_attr_t *list)
731 {
732         lvds_context_t *pd_context = (lvds_context_t *) context;
733         pd_attr_t      *attr       = NULL;
734         unsigned short i           = 0;
735         unsigned short j           = 0;
736         int            ret         = PD_SUCCESS;
737         /* no of case IDs in the global table */
738         int num_case_ids = sizeof(table_opt_data1)/sizeof(lvds_opt_table_data_t);
739
740         /* basic parameter check */
741         if (!context || !num || !list) {
742                 return PD_ERR_NULL_PTR;
743         }
744
745         PD_DEBUG("lvds_set_attrs()\n");
746         for (i = 0; i < num; i++, list++) {
747                 /* do nothing if the attribute has not been changed */
748                 if (!(list->flags & PD_ATTR_FLAG_VALUE_CHANGED)) {
749                         continue;
750                 }
751
752                 /* attributes can't be changed after init has been completed */
753                 if (list->flags & PD_ATTR_FLAG_USER_INVISIBLE &&
754                         pd_context->init_done) {
755                         return PD_ERR_ATTR_CANT_CHANGE;
756                 }
757
758                 /* Set the internal attributes' list.  Note that although get_attr() can
759                  * return NULL theortically, it will not do so here because all the
760                  * attribute IDs in this switch statement comes from lvds_attrs[],
761                  * a list that is automatically initialized into pd_context.  This is
762                  * why we are not checking for NULL after calling get_attr().
763                  */
764 #if 0   /* ORIGINAL SWITCH STATEMENT */
765                 switch (list->id) {
766                         case PD_ATTR_ID_FP_PWR_T1:
767                         case PD_ATTR_ID_FP_PWR_T2:
768                         case PD_ATTR_ID_FP_PWR_T3:
769                         case PD_ATTR_ID_FP_PWR_T4:
770                         case PD_ATTR_ID_FP_PWR_T5:
771                                 /* current_value should not exceed the predefined max value */
772                                 attr = pd_get_attr(pd_context->attr_list, pd_context->num_attrs,
773                                         list->id, 0);
774                                 attr->current_value = LVDS_MIN(
775                                                 ((pd_range_attr_t *)list)->current_value,
776                                                 attr->_pad1);
777                                 break;
778
779                         case PD_ATTR_ID_PANEL_DEPTH:
780                                 attr = pd_get_attr(pd_context->attr_list, pd_context->num_attrs,
781                                         list->id, 0);
782                                 attr->current_value = list->current_value;
783                                 pd_context->panel_depth = (unsigned char) attr->current_value;
784                                 break;
785
786                         case PD_ATTR_ID_2_CHANNEL_PANEL:
787                                 attr = pd_get_attr(pd_context->attr_list, pd_context->num_attrs,
788                                         list->id, 0);
789                                 attr->current_value = ((pd_bool_attr_t *)list)->current_value;
790                                 pd_context->dual_channel = (attr->current_value?1:0);
791                                 break;
792
793                         case PD_ATTR_ID_LVDS_PANEL_TYPE:
794                                 attr = pd_get_attr(pd_context->attr_list, pd_context->num_attrs,
795                                         list->id, 0);
796                                 attr->current_value = ((pd_bool_attr_t *)list)->current_value;
797                                 pd_context->panel_type = (attr->current_value?1:0);
798                                 break;
799
800                         case PD_ATTR_ID_PANEL_FIT:
801                                 attr = pd_get_attr(pd_context->attr_list, pd_context->num_attrs,
802                                         list->id, 0);
803                                 attr->current_value = ((pd_bool_attr_t *)list)->current_value;
804                                 pd_context->panel_fit = (attr->current_value?1:0);
805                                 break;
806
807                         default:
808                                 /* do nothing if we have an unknown ID */
809                                 break;
810                 }
811 #endif
812                 /* OPTIMIZATION CODE BEGINS FOR THE ABOVE SWITCH
813                  *----------------------------------------------
814                  * Step 1: First identify the code common to all case blocks.
815                  *         This we call it "common code block" Since this is to be
816                  *         executed by all the case blocks.
817                  *
818                  * Step 2: Group the cases into blocks based on how we can combine them
819                  *
820                  *         Eg: case 0: ptr->x = 1; break; // similar code
821                  *        case 1: ptr->y = 1; break; // similar code
822                  *  ------Combined block ----
823                  *        case 0:
824                  *        case 1: PTR_OFFSET_TYPE(ptr, table[i].offset) = 1; break;
825                  *        This is an important step because we save code space by
826                  *        mapping many cases to smaller number of blocks. In the above
827                  *        we use index to get the right offset of the ptr.
828                  *
829                  * Step 3: Assign block IDs to each block. Put the case ID, block ID
830                  *         and other information such as offsets of ptr in a global
831                  *         table.
832                  *
833                  * Step 4: During run-time , search through the global table, find the
834                  *         matching case ID, and execute the common code. Next get the
835                  *         block ID and execute the block specific code. For the index,
836                  *         retrieve it from the table for the corresponding case ID.
837                  *
838                  * Step 5: If no matching case ID is found, error it out.
839                  *
840                  * Let's look at the optimization code for the above switch.
841                  * The code below searches for the list->id in a global table where
842                  * we store all the case values along with block numbers and other
843                  * information. After we find a valid id in the table , we execute the
844                  * common code for all cases first and then we retrieve the block id.
845                  * The block id is necesary to determine which block does the id belong
846                  * to. This is used to execute block specific code. Similar to switch
847                  * cases ONLY here we try to minimize the no of blocks.
848                  *
849                  * In this example , we store the offsets of field names of a ptr in the
850                  * global table.This is necessary to combine cases with "similar" but
851                  * not "same" codes.
852                  *
853                  * Eg: case 0: ptr->x = 1; break; // similar code
854                  *     case 1: ptr->y = 1; break; // similar code
855                  *  -- Combined block ----
856                  *    case 0:
857                  *    case 1: PTR_OFFSET_TYPE(ptr, table[i].offset) = 1; break;
858                  *
859                  * By reducing the number of blocks we save on Code space. After we
860                  * finish our work , we exit the for loop and check for invalid ID
861                  * passed by the upper layer. This is akin to default in the
862                  * switch block
863                  *
864                  * CAUTION: If there is any change in the switch above, this code
865                  * along with the tables have to be re-written and changed according
866                  * to the new behaviour of the switch. Examples include adding a new
867                  * case in the switch. The reason for all this mumbo-jumbo is to
868                  * reduce code size in VBIOS, where we are running out of code space.
869                  */
870                 for(j = 0; j < num_case_ids; j++) {
871                         /* Search for the attribute ID in the global table */
872                         if(list->id == table_opt_data1[j].id) {
873                                 /* Run the common code for all the blocks */
874                                 attr = pd_get_attr(pd_context->attr_list, pd_context->num_attrs,
875                                         list->id, 0);
876                                 /* Once we get a valid ID, need to find out which block it
877                                  *  belongs so we can execute block specific code.
878                                  */
879                                 if(table_opt_data1[j].block == 1) { /* block 1 */
880                                         /* Got the block. Need the offset to the struct for that ID
881                                         * so we can store value at corresponding offset to get the
882                                         * desired behaviour for that ID.This is the code that makes
883                                         * the whole optimization work because we are combining the
884                                         * case IDs into a single block which saves code.
885                                         */
886                                         attr->current_value = list->current_value;
887                                         PTR_OFFSET_USHORT(pd_context, table_opt_data1[j].offset) =
888                                         (unsigned short) attr->current_value;
889
890                                 } else { /* block 2. We only have two blocks. */
891                                         attr->current_value = LVDS_MIN(
892                                                 list->current_value, ((pd_range_attr_t *)attr)->max);
893                                 }
894                                 break; /* We found a valid ID, so break inner for loop */
895                         }
896                 }
897         }
898         /* panel_type 0 (SPWG) isn't available for 18-bit depth */
899         PD_DEBUG("in LVDS_set_attributes()\n");
900         if (pd_context->panel_depth == 18) {
901                 pd_context->panel_type = 1;
902         }
903         PD_DEBUG("IntLVDS: dual_channel=%u", pd_context->dual_channel);
904         PD_DEBUG("IntLVDS: panel_type=%u panel_fit=%u panel_dep=%u dither=%u",
905                 pd_context->panel_type, pd_context->panel_fit,
906                 pd_context->panel_depth, pd_context->dither);
907         PD_DEBUG("IntLVDS: keep_aspect_ratio=%u text_tune=%lu",
908                 pd_context->aspect_ratio, pd_context->text_tune);
909         PD_DEBUG("IntLVDS: PWM Intensity=%u Inverter Freq=%u, BLM legacy mode =%u",
910                 pd_context->pwm_intensity, pd_context->inverter_freq,
911                 pd_context->blm_legacy_mode);
912         PD_DEBUG("IntLVDS: tc_110MHz_clk = %u", pd_context->tc_110MHz_clk);
913
914         if (pd_context->init_done) {
915                 /* When emgd_driver_pre_init() pokes new attrs into this port driver,
916                  * pd_context->current_mode must be set before calling
917                  * lvds_panel_fit(), so set it to the first entry in the timing table:
918                  */
919                 if (pd_context->current_mode == NULL) {
920                         pd_context->current_mode = pd_context->timing_table;
921                 }
922                 lvds_panel_fit(pd_context);
923         }
924
925         return ret;
926 } /* lvds_set_attrs */
927
928 /*----------------------------------------------------------------------------
929  *
930  * Function: lvds_get_attrs
931  *
932  * Description:
933  *    Extracts the attribute list and the number of elements in the list
934  *    from the device context.
935  *
936  * Parameters:
937  *    [IN] context: device context to extract information from
938  *    [OUT] num:    number of elements in list
939  *    [OUT] list:   list of attributes from the device context
940  *
941  * Return:
942  *    PD_ERR_NULL_PTR: if one of the parameters is invalid
943  *    PD_SUCCESS:      if successful
944  *
945  *----------------------------------------------------------------------------
946  */
947 int lvds_get_attrs (void *context, unsigned long *num, pd_attr_t **list)
948 {                                                         /* lvds_get_attrs */
949         /* basic parameter check */
950         if (!context || !num || !list) {
951                 return PD_ERR_NULL_PTR;
952         }
953
954         PD_DEBUG("lvds_get_attrs()\n");
955         /* Nothing fancy, just extracting the elements from the list */
956         *list = ((lvds_context_t *)context)->attr_list;
957         *num  = ((lvds_context_t *)context)->num_attrs;
958
959         return PD_SUCCESS;
960 }                                                         /* lvds_get_attrs */
961
962 /*----------------------------------------------------------------------------
963  *
964  * Function: lvds_get_timing_list
965  *
966  * Description:
967  *
968  *
969  * Parameters:
970  *    [IN] context: device context to extract information from
971  *    [OUT] in_list:
972  *    [OUT] list:
973  *
974  * Return:
975  *    PD_ERR_NULL_PTR: if one of the parameters is invalid
976  *    PD_ERR_NOMEM:    if internal memory allocate failed
977  *    PD_SUCCESS:      if successful
978  *
979  *----------------------------------------------------------------------------
980  */
981 int lvds_get_timing_list (void *context, pd_timing_t *in_list,
982         pd_timing_t **list)
983 {                                                   /* lvds_get_timing_list */
984         lvds_context_t *pd_context = (lvds_context_t *)context;
985         pd_dvo_info_t lvds_info = {0, 0, 1, 0, 0, 0, 0, 0};
986         pd_display_info_t lvds_display_info = {0, 0, 0, 0, NULL};
987         int ret;
988
989         PD_DEBUG("lvds_get_timing_list()\n");
990         lvds_get_dclk( pd_context, &lvds_info );
991
992         PD_DEBUG("chipset = 0x%x", pd_context->chipset);
993         lvds_display_info.panel_fit = (unsigned char) pd_context->panel_fit;
994         ret = pd_filter_timings(pd_context->callback->callback_context,
995                 in_list, &pd_context->timing_table, &lvds_info, &lvds_display_info);
996
997         /* Helper function will return the below values */
998         pd_context->native_dtd = lvds_display_info.native_dtd;
999         pd_context->fp_width = lvds_display_info.width;
1000         pd_context->fp_height = lvds_display_info.height;
1001
1002         *list = pd_context->timing_table;
1003         return ret;
1004 }                                                   /* lvds_get_timing_list */
1005
1006 /*----------------------------------------------------------------------------
1007  *
1008  * Function: lvds_set_power
1009  *
1010  * Description:
1011  *  Sets LVDS to the specified power state
1012  *
1013  *  Conversion between IEGD timer values to LVDS port timer values
1014  *
1015  *  SEPG(?) IEGD    LVDS Port    Program bits     min     max
1016  *  ----    ------- ------------ ---------------- ------ ---------
1017  *  T1+T2   T1 ms   T1+T2 100us  0x61208 [28:16]  0 ms   819.2 ms
1018  *  T5      T2 ms   T5    100us  0x61208 [12:00]  0 ms   819.2 ms
1019  *  T6      T3 ms   Tx    100us  0x6120C [12:00]  0 ms   819.2 ms
1020  *  T3      T4 ms   T3    100us  0x6120C [28:16]  0 ms   819.2 ms
1021  *  T4      T5 ms   T4    100ms  0x61210 [04:00]  0 ms   3200  ms
1022  *
1023  *  Reg     = Value
1024  *  ------    -------
1025  *  0x61208 = [T1 T2]
1026  *  0x6120C = [T4 T3]
1027  *  0x61210 = [   T5]
1028  *
1029  * Parameters:
1030  *    [IN] context: device context to extract information from
1031  *    [OUT] in_list:
1032  *    [OUT] list:
1033  *
1034  * Return:
1035  *    PD_ERR_NULL_PTR:      if context is NULL
1036  *    PD_ERR_INVALID_POWER: if "state" is invalid
1037  *    PD_SUCCESS:           if successful
1038  *
1039  *----------------------------------------------------------------------------
1040  */
1041 /* Tables required by the optimization codes in lvds_set_power() */
1042 typedef struct {
1043         unsigned char id1;
1044         unsigned char id2;
1045         unsigned char bit;
1046         unsigned long reg;
1047 } opt_set_power_t;
1048
1049 static opt_set_power_t table_set_power[] = {
1050         /* id1                  id2                   bit    reg */
1051         { PD_ATTR_ID_FP_PWR_T1, PD_ATTR_ID_FP_PWR_T2, 1,     0x61208 },  /* D0 */
1052         { PD_ATTR_ID_FP_PWR_T4, PD_ATTR_ID_FP_PWR_T3, 0,     0x6120C },  /* Dx */
1053 };
1054
1055 int lvds_set_power(void *context, unsigned long state)
1056 {                                                         /* lvds_set_power */
1057         unsigned long  i           = 0;
1058         lvds_context_t *pd_context = (lvds_context_t *)context;
1059         pd_attr_t      *tattr      = NULL;  /* holds time delay b/ pwr transition */
1060         unsigned long            delay = 0, delay1;
1061
1062         PD_DEBUG("state = %lu", state);
1063
1064         PD_DEBUG("lvds_set_power() to state = %lu\n",state);
1065         /* Basic parameter check */
1066         if (!context) {
1067                 PD_DEBUG("No context");
1068                 return PD_ERR_NULL_PTR;
1069         }
1070         PD_DEBUG("pd_context=0x%lx", (unsigned long)pd_context);
1071
1072         /* Check for invalid state */
1073         if (state > PD_POWER_MODE_D3) {
1074                 PD_DEBUG("Invalid power state");
1075                 return PD_ERR_INVALID_POWER;
1076         }
1077
1078         /* Get the index into above table */
1079         if (state == PD_POWER_MODE_D0) {
1080                 i = 0;
1081         } else {
1082                 i = 1;
1083         }
1084
1085         lvds_write_reg(pd_context, 0x61204, 0xABCD0000, 0xFFFFFFFF, PD_REG_MIO);
1086
1087         /* Program panel power up/down delays: Either T1/T2 or T3/T4*/
1088         tattr = pd_get_attr(pd_context->attr_list,
1089                 pd_context->num_attrs, table_set_power[i].id1, 0);
1090         /* Convert ms to 100us */
1091         delay1 = tattr->current_value;
1092         delay = (tattr->current_value * 10) << 16;
1093         tattr = pd_get_attr(pd_context->attr_list,
1094                 pd_context->num_attrs, table_set_power[i].id2, 0);
1095         delay1 += tattr->current_value;
1096         delay |= tattr->current_value * 10;
1097
1098         lvds_write_reg(pd_context, table_set_power[i].reg, delay, 0x1FFF1FFF, PD_REG_MIO);
1099
1100         /* Program power cycle delay: convert ms to 100ms */
1101         delay = pd_get_attr(pd_context->attr_list,
1102                 pd_context->num_attrs, PD_ATTR_ID_FP_PWR_T5, 0)->current_value;
1103         delay1 += delay;
1104         /* TODO: Write reference divider [31:8] */
1105         delay = ((delay/100+1) & 0xFF) | ((pd_context->gfx_freq*100/2-1)<<8);
1106         lvds_write_reg(pd_context, 0x61210, delay, 0xFFFFFFFF, PD_REG_MIO);
1107
1108         /* Power state target */
1109         lvds_write_reg(pd_context, 0x61204, table_set_power[i].bit, BIT(0), PD_REG_MIO);
1110
1111         /* Power down on reset available on crestline onwards */
1112         lvds_write_reg(pd_context, 0x61204, BIT(1), BIT(1), PD_REG_MIO);
1113
1114 /* Make this a compile time so that size of vBIOS doesn't become > 64KB */
1115 #if defined(CONFIG_PLB) || defined(CONFIG_TNC)
1116         /* PWM is a method of controlling the backlight intensity.
1117          * It is not method to turn on baclkight.
1118          * We still need the PD method to turn on the backlight.
1119          *
1120          * This feature is for Pouslbo Only. We check that the user has set the
1121          * inverter frequency. Default intensity, if not set, is 100%
1122          *
1123          * Due to the high amount of calculation, we want to only set this register
1124          * if it has not been ser previously. The register could be
1125          * "brought forward" from VBIOS.
1126          */
1127         if(pd_context->inverter_freq != 0xFFFF &&  /* Overwritten by set_attr */
1128                 (pd_context->chipset == PCI_DEVICE_ID_VGA_PLB ||
1129                  pd_context->chipset == PCI_DEVICE_ID_VGA_TNC ||
1130                  pd_context->chipset == PCI_DEVICE_ID_VGA_TNC_A0 ||
1131                  pd_context->chipset == PCI_DEVICE_ID_VGA_LNC) &&
1132                  !pd_context->pwm_done) {
1133                 unsigned long reg_value = 0;
1134                 unsigned long percentage = 0;
1135                 unsigned long calculation = 0;
1136                 unsigned long blc_pwm_ctl2 = 0;
1137
1138                 /* We first need to get the graphics frequency, which will be used to
1139                  * calculate Backlight Modulation Frequency[BMF]. BMF will be used to
1140                  * fill up the 15 MSB in the 0x61254 register
1141                  *
1142                  * The calculation for the Modulation Frequency field in the
1143                  * BLC_PWM_CTL Register is:
1144                  *
1145          *     Reference Clock Freq               1
1146          *     -----------------------   x    ------------------
1147          *            Divider                   PWM Freq in Hz
1148                  *
1149                  */
1150 #if 0
1151                 /* GMA accurate calculation that requires "calculation" to be an
1152                  * unsigned long long typedef */
1153                 calculation = pd_context->gfx_freq * PWM_FREQ_CALC_CONSTANT_2;
1154                 calculation = calculation / 0x20; /*pouslbo specific divider*/
1155                 calculation = calculation * PWM_FREQ_CALC_CONSTANT_1;
1156                 calculation = calculation / pd_context->inverter_freq;
1157                 calculation = calculation / PWM_FREQ_CALC_CONSTANT_1;
1158 #endif
1159                 /* Some system bios cannot take 64 bit data type. Using a more
1160                  * simplified calculation that is not too accurate if the inputs
1161                  * are not round numbers */
1162                 calculation = pd_context->inverter_freq * 0x20; /* plb/tnc divider */
1163                 calculation = (pd_context->gfx_freq * PWM_FREQ_CALC_CONSTANT_2) /
1164                         calculation;
1165
1166                 /* Writing the register: 15 MSB is the max lvds clock / 32.
1167                 * Bit 16 can either be legacy or non legacy depending upon Attr #72. */
1168                 if (pd_context->gn4_plus) {
1169                         blc_pwm_ctl2 = (1L << 31) |
1170                                 (pd_context->blm_legacy_mode << 30) |
1171                                 ((pd_context->pipe == PD_SET_MODE_PIPE_B)?1L:0L << 29);
1172                         lvds_write_reg(pd_context, 0x61250, blc_pwm_ctl2, 0xFFFFFFFF, PD_REG_MIO);
1173                         reg_value = (calculation & 0xFFFF)<<16;
1174                 } else {
1175                         reg_value = ((calculation & 0xFFFE) |
1176                                 pd_context->blm_legacy_mode)<<16;
1177                 }
1178
1179                 /* The 16 LSB is a value that the user sets in configuration.
1180                  * user sets the value in percentage.
1181                  * We convert it into the clock speed */
1182                 percentage = ( pd_context->pwm_intensity * (unsigned long)calculation);
1183                 reg_value |= (unsigned long)( percentage / (int)100 ) & 0xFFFE;
1184                 lvds_write_reg(pd_context, 0x61254, reg_value, 0xFFFFFFFF, PD_REG_MIO);
1185
1186                 /* set the flag so that we only do this function once */
1187                 pd_context->pwm_done = 1;
1188         }
1189 #endif
1190
1191         if (state != PD_POWER_MODE_D0) {
1192                 /* Wait until the current power up/down sequence is complete */
1193                 i = 0;
1194                 while(lvds_read_reg(pd_context, 0x61200, PD_REG_MIO) & 0x80000000L) {
1195                         i++;
1196                         if(i > 0x100000L) {
1197                                 break;
1198                         }
1199                 }
1200                 lvds_write_reg(pd_context, 0x61180, 0, BIT(31), PD_REG_MIO);
1201         }
1202
1203 #ifdef CONFIG_TNC
1204 #if 0
1205
1206 /*-----------------------------------------------------------------------------
1207  * LPC Register Offsets. Used for LVDS BKLT control. Registers are part
1208  * Atom E6xx [D31:F0]
1209  ----------------------------------------------------------------------------*/
1210 #define RGEN    0x20
1211 #define RGIO    0x24
1212 #define RGLVL   0x28
1213 #define TNC_LVDS_VDDEN   BIT(0)
1214 #define TNC_LVDS_BKLTEN  BIT(1)
1215 #define TNC_LVDS_BKLTCTL BIT(2)
1216
1217         if (pd_context->chipset == PCI_DEVICE_ID_VGA_TNC ||
1218                 pd_context->chipset == PCI_DEVICE_ID_VGA_TNC_A0 ||
1219                 pd_context->chipset == PCI_DEVICE_ID_VGA_LNC) {
1220                 unsigned long value;
1221
1222                 /* Enable backlight for LVDS: based on observed si behavior:
1223                  * Subject to change based on si DE feedback */
1224                 if (state == PD_POWER_MODE_D0) {
1225                         value = TNC_LVDS_BKLTCTL|TNC_LVDS_BKLTEN|TNC_LVDS_BKLTCTL;
1226                 } else {
1227                         value = 0;
1228                 }
1229                 lvds_write_reg(pd_context, RGEN, value,
1230                         TNC_LVDS_BKLTCTL|TNC_LVDS_BKLTEN|TNC_LVDS_BKLTCTL, PD_REG_LPC);
1231                 lvds_write_reg(pd_context, RGIO, value,
1232                         TNC_LVDS_BKLTCTL|TNC_LVDS_BKLTEN|TNC_LVDS_BKLTCTL, PD_REG_LPC);
1233         }
1234 #endif
1235 #endif
1236
1237         /* update power state */
1238         pd_context->power_state = state;
1239         return PD_SUCCESS;
1240 }                                                         /* lvds_set_power */
1241
1242 /*----------------------------------------------------------------------------
1243  *
1244  * Function: lvds_get_power
1245  *
1246  * Description:
1247  *   Returns the current LVDS power state back to the caller.
1248  *
1249  * Parameters:
1250  *    [IN] context: device context to extract information from
1251  *    [OUT] state:  current power state
1252  *
1253  * Return:
1254  *    PD_ERR_NULL_PTR:      if one of the parameters is invalid
1255  *    PD_SUCCESS:           if successful
1256  *
1257  *----------------------------------------------------------------------------
1258  */
1259
1260 int lvds_get_power (void *context, unsigned long *state)
1261 {                                                         /* lvds_get_power */
1262         if ((NULL == context) || (NULL == state)) {
1263                 return PD_ERR_NULL_PTR;
1264         }
1265         PD_DEBUG("lvds_get_power()\n");
1266         /* The caller should be able to do this himself, but whatever */
1267         *state = ((lvds_context_t *) context)->power_state;
1268         return PD_SUCCESS;
1269 }                                                         /* lvds_get_power */
1270
1271 int lvds_save(void *context, void **state, unsigned long flags)
1272 {
1273         *state = NULL;
1274         return PD_SUCCESS;
1275 }
1276
1277 int lvds_restore(void *context, void *state, unsigned long flags)
1278 {
1279         int ret = PD_SUCCESS;
1280         return ret;
1281 }
1282
1283 /*----------------------------------------------------------------------
1284  * Function: lvds_get_port_status()
1285  *
1286  * Description:  It is called to get the information about the display
1287  *
1288  * Parameters:  context - Port driver's context
1289  *                              port_status - Returns the display type and connection state
1290  *
1291  * Return:      PD_SUCCESS(0)  success
1292  *              PD_ERR_XXXXXX  otherwise
1293  *----------------------------------------------------------------------*/
1294 int lvds_get_port_status(void *context, pd_port_status_t *port_status)
1295 {
1296         /* Display connection cannot be determined */
1297         port_status->display_type = PD_DISPLAY_LVDS_INT;
1298         port_status->connected    = PD_DISP_STATUS_UNKNOWN;
1299         return PD_SUCCESS;
1300 }
1301
1302 static unsigned long lvds_read_reg(lvds_context_t *pd_context,unsigned long reg,
1303         unsigned long reg_type)
1304 {
1305         pd_reg_t list[2];
1306         int ret;
1307
1308         list[0].reg = reg;
1309         list[0].value = 0;
1310         list[1].reg = PD_REG_LIST_END;
1311         ret = pd_context->callback->read_regs(
1312                 pd_context->callback->callback_context, list, reg_type);
1313         if (ret) {
1314                 PD_ERROR("LVDS read regs: Failed.");
1315         }
1316         return list[0].value;
1317 }
1318
1319 /*----------------------------------------------------------------------------
1320  *
1321  * Function: lvds_write_reg
1322  *
1323  * Description:
1324  *    Writes bits in "value" into a register.  Bits written are dictated by
1325  *    the "change_bits" mask.
1326  *
1327  * Parameters:
1328  *    [IN] pd_context:  device context, dispatcher to the actual write_reg
1329  *                      function
1330  *    [IN] reg:  register to write value to
1331  *    [IN] value:  value to change the register to
1332  *    [IN] change_bits:  bit mask, the bits set to "1" will be modified by
1333  *                       the corresponding bits in "value"
1334  *
1335  * Return:
1336  *    None
1337  *
1338  *----------------------------------------------------------------------------
1339  */
1340 static void lvds_write_reg(lvds_context_t *pd_context, unsigned long reg,
1341                 unsigned long value,
1342                 unsigned long change_bits,
1343                 unsigned long reg_type)
1344 {                                                         /* lvds_write_reg */
1345         pd_reg_t list[2];
1346         int ret;
1347
1348         PD_DEBUG("ENTER");
1349
1350         list[0].reg = reg;
1351         list[0].value = (lvds_read_reg(pd_context, reg, PD_REG_MIO) & ~change_bits) | value;
1352         list[1].reg = PD_REG_LIST_END;
1353         ret = pd_context->callback->write_regs(
1354                 pd_context->callback->callback_context, list, reg_type);
1355         if (ret) {
1356                 PD_ERROR("LVDS write regs: Failed.");
1357         }
1358         PD_DEBUG("EXIT");
1359         return;
1360 }                                                         /* lvds_write_reg */
1361
1362 /*----------------------------------------------------------------------------
1363  *
1364  * Function: lvds_panel_fit
1365  *
1366  * Description:
1367  *    Enables panel fitting
1368  *
1369  * Parameters:
1370  *    [IN] pd_context:  device context
1371  *
1372  * Return:
1373  *    None
1374  *
1375  *----------------------------------------------------------------------------
1376  */
1377 static void lvds_panel_fit(lvds_context_t *pd_context)
1378 {
1379         /* enable auto vertical ratio */
1380         /* enable auto horizantal ratio */
1381         /* no dither */
1382         unsigned long panel_fit_reg = 0x00000220;
1383         PD_DEBUG("lvds_panel_fit() \n");
1384
1385         PD_TRACE_ENTER;
1386
1387         if (pd_context->current_mode->width != pd_context->fp_width ||
1388                 pd_context->current_mode->height != pd_context->fp_height) {
1389                 /* Enable panel fitting */
1390                 /* vertical interpolation = bilinear */
1391                 /* horizontal interpolation = bilinear */
1392                 panel_fit_reg |= 0x80000440;
1393         }
1394         /* Enable dither based on default/user-set value:
1395          *   By default
1396          *        dither = 1 for 18-bit panels
1397          *               = 0 for 24-bit panels.
1398          *   But this behavior can be changed by setting the DITHER attribute.
1399          *        When user sets the attribute, dither will be updated
1400          *        as part of attribute processing in set attributes. */
1401         /* For gn4 based chipsets dither is controlled in port_control register */
1402         if (!pd_context->gn4_plus) {
1403                 /* Default behavior */
1404                 if (pd_context->panel_depth == 18) {
1405                         panel_fit_reg |= BIT(3);
1406                 }
1407
1408                 /* Overwritten by set attribute */
1409                 if (pd_context->dither != 0xFFFF) {
1410                         if (pd_context->dither) {
1411                                 panel_fit_reg |= BIT(3);
1412                         } else {
1413                                 panel_fit_reg &= ~BIT(3);
1414                         }
1415                 }
1416         }
1417
1418         if (pd_context->gn4_plus) {
1419                 unsigned long src_ratio, dest_ratio;
1420                 panel_fit_reg = 0;
1421                 if (pd_context->native_dtd &&
1422                         (pd_context->current_mode->width != pd_context->native_dtd->width ||
1423                         pd_context->current_mode->height !=
1424                                 pd_context->native_dtd->height)) {
1425                         /* Enable panel fitter */
1426                         panel_fit_reg = 0x80000000;
1427
1428                         /* Select the pipe */
1429                         if (pd_context->pipe & PD_SET_MODE_PIPE_B) {
1430                                 panel_fit_reg |= BIT(29);   /* bits[30:29] = 01 for pipe B */
1431                         }
1432
1433                         /* Scaling mode:
1434                          *    Default - Auto scaling src_ratio == dest_ratio
1435                          *    Piller box scaling - src_ratio < dest_ratio
1436                          *    Letter box scaling - src_ratio > dest_ratio */
1437
1438                         /* To make this work correctly, port driver shall know the
1439                          * size of the framebuffer, not the src mode. Most of the
1440                          * times the src mode is fb, but not all the cases.
1441                          * User has an attribute to change
1442                          *    1. Between Pillerbox and auto, and vice versa
1443                          *                and
1444                          *    2. Between Letterbox and auto, and vice versa.
1445                          */
1446                         if (pd_context->aspect_ratio) {
1447                                 src_ratio = (pd_context->current_mode->width << 10)/
1448                                         (pd_context->current_mode->height);
1449                                 dest_ratio = (pd_context->native_dtd->width << 10)/
1450                                         (pd_context->native_dtd->height);
1451
1452                                 if (dest_ratio > src_ratio) {
1453                                         /* Pillarbox scaling */
1454                                         panel_fit_reg |= BIT(27);
1455                                 } else if (dest_ratio < src_ratio) {
1456                                         /* Letterbox scaling */
1457                                         panel_fit_reg |= BIT(27) | BIT(26);
1458                                 }
1459                         }
1460
1461                         /* Filter coefficient select: pd_context->text_tune = 0,1,2 */
1462                         panel_fit_reg |= (pd_context->text_tune << 24);
1463                 }
1464         }
1465
1466         lvds_write_reg(pd_context, 0x61230, panel_fit_reg, 0xFFFFFFFF, PD_REG_MIO);
1467         PD_DEBUG("panel_fit_reg 0x61230 = 0x%lx", panel_fit_reg);
1468 }
1469
1470
1471 /*----------------------------------------------------------------------------
1472  *
1473  * Function: lvds_get_dclk
1474  *
1475  * Description:
1476  *    Gets the Dclk for LVDS
1477  *
1478  * Parameters:
1479  *    [IN] pd_context:  device context
1480  *        [OUT]lvds_info:   Structure that contains the min and max dclk
1481  *
1482  * Return:
1483  *    None
1484  *
1485  *----------------------------------------------------------------------------
1486  */
1487 static void lvds_get_dclk(lvds_context_t *pd_context, pd_dvo_info_t *lvds_info )
1488 {
1489         PD_DEBUG("lvds_get_dclk()\n");
1490         /* Get the min and max dclks for lvds */
1491         if (pd_context->dual_channel) {
1492                 lvds_info->min_dclk = LVDS_MIN_DCLK * 2 ;
1493                 lvds_info->max_dclk = LVDS_MAX_DCLK * 2;
1494         } else {
1495                 lvds_info->min_dclk = LVDS_MIN_DCLK;
1496                 lvds_info->max_dclk = LVDS_MAX_DCLK;
1497         }
1498 /* This #define is the result of code size reduction effort. */
1499 #ifdef CONFIG_CTG
1500         /* Set dclk for GM965 */
1501         if(pd_context->chipset==PCI_DEVICE_ID_VGA_CTG){
1502                 /* Set dclk for GM965/CTG */
1503                 if (pd_context->dual_channel) {
1504                         lvds_info->min_dclk = LVDS_GM965_DUAL_MIN_DCLK ;
1505                         lvds_info->max_dclk = LVDS_GM965_DUAL_MAX_DCLK;
1506                 } else {
1507                         lvds_info->min_dclk = LVDS_GM965_SINGLE_MIN_DCLK;
1508                         lvds_info->max_dclk = LVDS_GM965_SINGLE_MAX_DCLK;
1509                 }
1510         }
1511 #else
1512
1513         /* Set dclk for 915GM */
1514         if(pd_context->chipset==PCI_DEVICE_ID_VGA_915AL){
1515                 if (pd_context->dual_channel) {
1516                         lvds_info->min_dclk = LVDS_915GM_DUAL_MIN_DCLK ;
1517                         lvds_info->max_dclk = LVDS_915GM_DUAL_MAX_DCLK;
1518                 } else {
1519                         lvds_info->min_dclk = LVDS_915GM_SINGLE_MIN_DCLK;
1520                         lvds_info->max_dclk = LVDS_915GM_SINGLE_MAX_DCLK;
1521                 }
1522         } else if(pd_context->chipset==PCI_DEVICE_ID_VGA_945GM ||
1523                                 pd_context->chipset==PCI_DEVICE_ID_VGA_945GME){
1524                 /* Set dclk for 945GM */
1525                 if (pd_context->dual_channel) {
1526                         lvds_info->min_dclk = LVDS_945GM_DUAL_MIN_DCLK ;
1527                         lvds_info->max_dclk = LVDS_945GM_DUAL_MAX_DCLK;
1528                 } else {
1529                         lvds_info->min_dclk = LVDS_945GM_SINGLE_MIN_DCLK;
1530                         lvds_info->max_dclk = LVDS_945GM_SINGLE_MAX_DCLK;
1531                 }
1532         } else if(pd_context->chipset==PCI_DEVICE_ID_VGA_GM965 ||
1533                                 pd_context->chipset==PCI_DEVICE_ID_VGA_GME965){
1534                 /* Set dclk for GM965 */
1535                 if (pd_context->dual_channel) {
1536                         lvds_info->min_dclk = LVDS_GM965_DUAL_MIN_DCLK ;
1537                         lvds_info->max_dclk = LVDS_GM965_DUAL_MAX_DCLK;
1538                 } else {
1539                         lvds_info->min_dclk = LVDS_GM965_SINGLE_MIN_DCLK;
1540                         lvds_info->max_dclk = LVDS_GM965_SINGLE_MAX_DCLK;
1541                 }
1542         }
1543 #endif
1544
1545 #ifdef CONFIG_TNC
1546         /* Get the min and max dclks for Atom E6xx lvds */
1547         if ((pd_context->chipset == PCI_DEVICE_ID_VGA_TNC) ||
1548             (pd_context->chipset == PCI_DEVICE_ID_VGA_TNC_A0) ||
1549             (pd_context->chipset == PCI_DEVICE_ID_VGA_LNC)) {
1550                 lvds_info->min_dclk = LVDS_TNC_SINGLE_MIN_DCLK;
1551                 /* Experimental feature to raise TC LVDS clk to 110MHz. */
1552                 if (pd_context->tc_110MHz_clk) {
1553                         lvds_info->max_dclk = 110000L;
1554                 } else {
1555                         lvds_info->max_dclk = LVDS_TNC_SINGLE_MAX_DCLK;
1556                 }
1557         }
1558 #endif
1559 }