GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / video / fbdev / via / lcd.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
4  * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
5
6  */
7 #include <linux/via-core.h>
8 #include <linux/via_i2c.h>
9 #include "global.h"
10
11 #define viafb_compact_res(x, y) (((x)<<16)|(y))
12
13 /* CLE266 Software Power Sequence */
14 /* {Mask}, {Data}, {Delay} */
15 static const int PowerSequenceOn[3][3] = {
16         {0x10, 0x08, 0x06}, {0x10, 0x08, 0x06}, {0x19, 0x1FE, 0x01}
17 };
18 static const int PowerSequenceOff[3][3] = {
19         {0x06, 0x08, 0x10}, {0x00, 0x00, 0x00}, {0xD2, 0x19, 0x01}
20 };
21
22 static struct _lcd_scaling_factor lcd_scaling_factor = {
23         /* LCD Horizontal Scaling Factor Register */
24         {LCD_HOR_SCALING_FACTOR_REG_NUM,
25          {{CR9F, 0, 1}, {CR77, 0, 7}, {CR79, 4, 5} } },
26         /* LCD Vertical Scaling Factor Register */
27         {LCD_VER_SCALING_FACTOR_REG_NUM,
28          {{CR79, 3, 3}, {CR78, 0, 7}, {CR79, 6, 7} } }
29 };
30 static struct _lcd_scaling_factor lcd_scaling_factor_CLE = {
31         /* LCD Horizontal Scaling Factor Register */
32         {LCD_HOR_SCALING_FACTOR_REG_NUM_CLE, {{CR77, 0, 7}, {CR79, 4, 5} } },
33         /* LCD Vertical Scaling Factor Register */
34         {LCD_VER_SCALING_FACTOR_REG_NUM_CLE, {{CR78, 0, 7}, {CR79, 6, 7} } }
35 };
36
37 static bool lvds_identify_integratedlvds(void);
38 static void fp_id_to_vindex(int panel_id);
39 static int lvds_register_read(int index);
40 static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
41                       int panel_vres);
42 static void lcd_patch_skew_dvp0(struct lvds_setting_information
43                          *plvds_setting_info,
44                          struct lvds_chip_information *plvds_chip_info);
45 static void lcd_patch_skew_dvp1(struct lvds_setting_information
46                          *plvds_setting_info,
47                          struct lvds_chip_information *plvds_chip_info);
48 static void lcd_patch_skew(struct lvds_setting_information
49         *plvds_setting_info, struct lvds_chip_information *plvds_chip_info);
50
51 static void integrated_lvds_disable(struct lvds_setting_information
52                              *plvds_setting_info,
53                              struct lvds_chip_information *plvds_chip_info);
54 static void integrated_lvds_enable(struct lvds_setting_information
55                             *plvds_setting_info,
56                             struct lvds_chip_information *plvds_chip_info);
57 static void lcd_powersequence_off(void);
58 static void lcd_powersequence_on(void);
59 static void fill_lcd_format(void);
60 static void check_diport_of_integrated_lvds(
61         struct lvds_chip_information *plvds_chip_info,
62                                      struct lvds_setting_information
63                                      *plvds_setting_info);
64
65 static inline bool check_lvds_chip(int device_id_subaddr, int device_id)
66 {
67         return lvds_register_read(device_id_subaddr) == device_id;
68 }
69
70 void viafb_init_lcd_size(void)
71 {
72         DEBUG_MSG(KERN_INFO "viafb_init_lcd_size()\n");
73
74         fp_id_to_vindex(viafb_lcd_panel_id);
75         viaparinfo->lvds_setting_info2->lcd_panel_hres =
76                 viaparinfo->lvds_setting_info->lcd_panel_hres;
77         viaparinfo->lvds_setting_info2->lcd_panel_vres =
78                 viaparinfo->lvds_setting_info->lcd_panel_vres;
79         viaparinfo->lvds_setting_info2->device_lcd_dualedge =
80             viaparinfo->lvds_setting_info->device_lcd_dualedge;
81         viaparinfo->lvds_setting_info2->LCDDithering =
82                 viaparinfo->lvds_setting_info->LCDDithering;
83 }
84
85 static bool lvds_identify_integratedlvds(void)
86 {
87         if (viafb_display_hardware_layout == HW_LAYOUT_LCD_EXTERNAL_LCD2) {
88                 /* Two dual channel LCD (Internal LVDS + External LVDS): */
89                 /* If we have an external LVDS, such as VT1636, we should
90                    have its chip ID already. */
91                 if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
92                         viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name =
93                             INTEGRATED_LVDS;
94                         DEBUG_MSG(KERN_INFO "Support two dual channel LVDS! "
95                                   "(Internal LVDS + External LVDS)\n");
96                 } else {
97                         viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
98                             INTEGRATED_LVDS;
99                         DEBUG_MSG(KERN_INFO "Not found external LVDS, "
100                                   "so can't support two dual channel LVDS!\n");
101                 }
102         } else if (viafb_display_hardware_layout == HW_LAYOUT_LCD1_LCD2) {
103                 /* Two single channel LCD (Internal LVDS + Internal LVDS): */
104                 viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
105                 INTEGRATED_LVDS;
106                 viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name =
107                         INTEGRATED_LVDS;
108                 DEBUG_MSG(KERN_INFO "Support two single channel LVDS! "
109                           "(Internal LVDS + Internal LVDS)\n");
110         } else if (viafb_display_hardware_layout != HW_LAYOUT_DVI_ONLY) {
111                 /* If we have found external LVDS, just use it,
112                    otherwise, we will use internal LVDS as default. */
113                 if (!viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
114                         viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
115                             INTEGRATED_LVDS;
116                         DEBUG_MSG(KERN_INFO "Found Integrated LVDS!\n");
117                 }
118         } else {
119                 viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
120                         NON_LVDS_TRANSMITTER;
121                 DEBUG_MSG(KERN_INFO "Do not support LVDS!\n");
122                 return false;
123         }
124
125         return true;
126 }
127
128 bool viafb_lvds_trasmitter_identify(void)
129 {
130         if (viafb_lvds_identify_vt1636(VIA_PORT_31)) {
131                 viaparinfo->chip_info->lvds_chip_info.i2c_port = VIA_PORT_31;
132                 DEBUG_MSG(KERN_INFO
133                           "Found VIA VT1636 LVDS on port i2c 0x31\n");
134         } else {
135                 if (viafb_lvds_identify_vt1636(VIA_PORT_2C)) {
136                         viaparinfo->chip_info->lvds_chip_info.i2c_port =
137                                 VIA_PORT_2C;
138                         DEBUG_MSG(KERN_INFO
139                                   "Found VIA VT1636 LVDS on port gpio 0x2c\n");
140                 }
141         }
142
143         if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700)
144                 lvds_identify_integratedlvds();
145
146         if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name)
147                 return true;
148         /* Check for VT1631: */
149         viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = VT1631_LVDS;
150         viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr =
151                 VT1631_LVDS_I2C_ADDR;
152
153         if (check_lvds_chip(VT1631_DEVICE_ID_REG, VT1631_DEVICE_ID)) {
154                 DEBUG_MSG(KERN_INFO "\n VT1631 LVDS ! \n");
155                 DEBUG_MSG(KERN_INFO "\n %2d",
156                           viaparinfo->chip_info->lvds_chip_info.lvds_chip_name);
157                 DEBUG_MSG(KERN_INFO "\n %2d",
158                           viaparinfo->chip_info->lvds_chip_info.lvds_chip_name);
159                 return true;
160         }
161
162         viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
163                 NON_LVDS_TRANSMITTER;
164         viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr =
165                 VT1631_LVDS_I2C_ADDR;
166         return false;
167 }
168
169 static void fp_id_to_vindex(int panel_id)
170 {
171         DEBUG_MSG(KERN_INFO "fp_get_panel_id()\n");
172
173         if (panel_id > LCD_PANEL_ID_MAXIMUM)
174                 viafb_lcd_panel_id = panel_id =
175                 viafb_read_reg(VIACR, CR3F) & 0x0F;
176
177         switch (panel_id) {
178         case 0x0:
179                 viaparinfo->lvds_setting_info->lcd_panel_hres = 640;
180                 viaparinfo->lvds_setting_info->lcd_panel_vres = 480;
181                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
182                 viaparinfo->lvds_setting_info->LCDDithering = 1;
183                 break;
184         case 0x1:
185                 viaparinfo->lvds_setting_info->lcd_panel_hres = 800;
186                 viaparinfo->lvds_setting_info->lcd_panel_vres = 600;
187                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
188                 viaparinfo->lvds_setting_info->LCDDithering = 1;
189                 break;
190         case 0x2:
191                 viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
192                 viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
193                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
194                 viaparinfo->lvds_setting_info->LCDDithering = 1;
195                 break;
196         case 0x3:
197                 viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
198                 viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
199                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
200                 viaparinfo->lvds_setting_info->LCDDithering = 1;
201                 break;
202         case 0x4:
203                 viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
204                 viaparinfo->lvds_setting_info->lcd_panel_vres = 1024;
205                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
206                 viaparinfo->lvds_setting_info->LCDDithering = 1;
207                 break;
208         case 0x5:
209                 viaparinfo->lvds_setting_info->lcd_panel_hres = 1400;
210                 viaparinfo->lvds_setting_info->lcd_panel_vres = 1050;
211                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
212                 viaparinfo->lvds_setting_info->LCDDithering = 1;
213                 break;
214         case 0x6:
215                 viaparinfo->lvds_setting_info->lcd_panel_hres = 1600;
216                 viaparinfo->lvds_setting_info->lcd_panel_vres = 1200;
217                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
218                 viaparinfo->lvds_setting_info->LCDDithering = 1;
219                 break;
220         case 0x8:
221                 viaparinfo->lvds_setting_info->lcd_panel_hres = 800;
222                 viaparinfo->lvds_setting_info->lcd_panel_vres = 480;
223                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
224                 viaparinfo->lvds_setting_info->LCDDithering = 1;
225                 break;
226         case 0x9:
227                 viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
228                 viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
229                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
230                 viaparinfo->lvds_setting_info->LCDDithering = 1;
231                 break;
232         case 0xA:
233                 viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
234                 viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
235                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
236                 viaparinfo->lvds_setting_info->LCDDithering = 0;
237                 break;
238         case 0xB:
239                 viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
240                 viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
241                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
242                 viaparinfo->lvds_setting_info->LCDDithering = 0;
243                 break;
244         case 0xC:
245                 viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
246                 viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
247                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
248                 viaparinfo->lvds_setting_info->LCDDithering = 0;
249                 break;
250         case 0xD:
251                 viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
252                 viaparinfo->lvds_setting_info->lcd_panel_vres = 1024;
253                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
254                 viaparinfo->lvds_setting_info->LCDDithering = 0;
255                 break;
256         case 0xE:
257                 viaparinfo->lvds_setting_info->lcd_panel_hres = 1400;
258                 viaparinfo->lvds_setting_info->lcd_panel_vres = 1050;
259                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
260                 viaparinfo->lvds_setting_info->LCDDithering = 0;
261                 break;
262         case 0xF:
263                 viaparinfo->lvds_setting_info->lcd_panel_hres = 1600;
264                 viaparinfo->lvds_setting_info->lcd_panel_vres = 1200;
265                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
266                 viaparinfo->lvds_setting_info->LCDDithering = 0;
267                 break;
268         case 0x10:
269                 viaparinfo->lvds_setting_info->lcd_panel_hres = 1366;
270                 viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
271                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
272                 viaparinfo->lvds_setting_info->LCDDithering = 0;
273                 break;
274         case 0x11:
275                 viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
276                 viaparinfo->lvds_setting_info->lcd_panel_vres = 600;
277                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
278                 viaparinfo->lvds_setting_info->LCDDithering = 1;
279                 break;
280         case 0x12:
281                 viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
282                 viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
283                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
284                 viaparinfo->lvds_setting_info->LCDDithering = 1;
285                 break;
286         case 0x13:
287                 viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
288                 viaparinfo->lvds_setting_info->lcd_panel_vres = 800;
289                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
290                 viaparinfo->lvds_setting_info->LCDDithering = 1;
291                 break;
292         case 0x14:
293                 viaparinfo->lvds_setting_info->lcd_panel_hres = 1360;
294                 viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
295                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
296                 viaparinfo->lvds_setting_info->LCDDithering = 0;
297                 break;
298         case 0x15:
299                 viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
300                 viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
301                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
302                 viaparinfo->lvds_setting_info->LCDDithering = 0;
303                 break;
304         case 0x16:
305                 viaparinfo->lvds_setting_info->lcd_panel_hres = 480;
306                 viaparinfo->lvds_setting_info->lcd_panel_vres = 640;
307                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
308                 viaparinfo->lvds_setting_info->LCDDithering = 1;
309                 break;
310         case 0x17:
311                 /* OLPC XO-1.5 panel */
312                 viaparinfo->lvds_setting_info->lcd_panel_hres = 1200;
313                 viaparinfo->lvds_setting_info->lcd_panel_vres = 900;
314                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
315                 viaparinfo->lvds_setting_info->LCDDithering = 0;
316                 break;
317         default:
318                 viaparinfo->lvds_setting_info->lcd_panel_hres = 800;
319                 viaparinfo->lvds_setting_info->lcd_panel_vres = 600;
320                 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
321                 viaparinfo->lvds_setting_info->LCDDithering = 1;
322         }
323 }
324
325 static int lvds_register_read(int index)
326 {
327         u8 data;
328
329         viafb_i2c_readbyte(VIA_PORT_2C,
330                         (u8) viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr,
331                         (u8) index, &data);
332         return data;
333 }
334
335 static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
336                       int panel_vres)
337 {
338         int reg_value = 0;
339         int viafb_load_reg_num;
340         struct io_register *reg = NULL;
341
342         DEBUG_MSG(KERN_INFO "load_lcd_scaling()!!\n");
343
344         /* LCD Scaling Enable */
345         viafb_write_reg_mask(CR79, VIACR, 0x07, BIT0 + BIT1 + BIT2);
346
347         /* Check if expansion for horizontal */
348         if (set_hres < panel_hres) {
349                 /* Load Horizontal Scaling Factor */
350                 switch (viaparinfo->chip_info->gfx_chip_name) {
351                 case UNICHROME_CLE266:
352                 case UNICHROME_K400:
353                         reg_value =
354                             CLE266_LCD_HOR_SCF_FORMULA(set_hres, panel_hres);
355                         viafb_load_reg_num =
356                             lcd_scaling_factor_CLE.lcd_hor_scaling_factor.
357                             reg_num;
358                         reg = lcd_scaling_factor_CLE.lcd_hor_scaling_factor.reg;
359                         viafb_load_reg(reg_value,
360                                 viafb_load_reg_num, reg, VIACR);
361                         break;
362                 case UNICHROME_K800:
363                 case UNICHROME_PM800:
364                 case UNICHROME_CN700:
365                 case UNICHROME_CX700:
366                 case UNICHROME_K8M890:
367                 case UNICHROME_P4M890:
368                 case UNICHROME_P4M900:
369                 case UNICHROME_CN750:
370                 case UNICHROME_VX800:
371                 case UNICHROME_VX855:
372                 case UNICHROME_VX900:
373                         reg_value =
374                             K800_LCD_HOR_SCF_FORMULA(set_hres, panel_hres);
375                         /* Horizontal scaling enabled */
376                         viafb_write_reg_mask(CRA2, VIACR, 0xC0, BIT7 + BIT6);
377                         viafb_load_reg_num =
378                             lcd_scaling_factor.lcd_hor_scaling_factor.reg_num;
379                         reg = lcd_scaling_factor.lcd_hor_scaling_factor.reg;
380                         viafb_load_reg(reg_value,
381                                 viafb_load_reg_num, reg, VIACR);
382                         break;
383                 }
384
385                 DEBUG_MSG(KERN_INFO "Horizontal Scaling value = %d", reg_value);
386         } else {
387                 /* Horizontal scaling disabled */
388                 viafb_write_reg_mask(CRA2, VIACR, 0x00, BIT7);
389         }
390
391         /* Check if expansion for vertical */
392         if (set_vres < panel_vres) {
393                 /* Load Vertical Scaling Factor */
394                 switch (viaparinfo->chip_info->gfx_chip_name) {
395                 case UNICHROME_CLE266:
396                 case UNICHROME_K400:
397                         reg_value =
398                             CLE266_LCD_VER_SCF_FORMULA(set_vres, panel_vres);
399                         viafb_load_reg_num =
400                             lcd_scaling_factor_CLE.lcd_ver_scaling_factor.
401                             reg_num;
402                         reg = lcd_scaling_factor_CLE.lcd_ver_scaling_factor.reg;
403                         viafb_load_reg(reg_value,
404                                 viafb_load_reg_num, reg, VIACR);
405                         break;
406                 case UNICHROME_K800:
407                 case UNICHROME_PM800:
408                 case UNICHROME_CN700:
409                 case UNICHROME_CX700:
410                 case UNICHROME_K8M890:
411                 case UNICHROME_P4M890:
412                 case UNICHROME_P4M900:
413                 case UNICHROME_CN750:
414                 case UNICHROME_VX800:
415                 case UNICHROME_VX855:
416                 case UNICHROME_VX900:
417                         reg_value =
418                             K800_LCD_VER_SCF_FORMULA(set_vres, panel_vres);
419                         /* Vertical scaling enabled */
420                         viafb_write_reg_mask(CRA2, VIACR, 0x08, BIT3);
421                         viafb_load_reg_num =
422                             lcd_scaling_factor.lcd_ver_scaling_factor.reg_num;
423                         reg = lcd_scaling_factor.lcd_ver_scaling_factor.reg;
424                         viafb_load_reg(reg_value,
425                                 viafb_load_reg_num, reg, VIACR);
426                         break;
427                 }
428
429                 DEBUG_MSG(KERN_INFO "Vertical Scaling value = %d", reg_value);
430         } else {
431                 /* Vertical scaling disabled */
432                 viafb_write_reg_mask(CRA2, VIACR, 0x00, BIT3);
433         }
434 }
435
436 static void via_pitch_alignment_patch_lcd(int iga_path, int hres, int bpp)
437 {
438         unsigned char cr13, cr35, cr65, cr66, cr67;
439         unsigned long dwScreenPitch = 0;
440         unsigned long dwPitch;
441
442         dwPitch = hres * (bpp >> 3);
443         if (dwPitch & 0x1F) {
444                 dwScreenPitch = ((dwPitch + 31) & ~31) >> 3;
445                 if (iga_path == IGA2) {
446                         if (bpp > 8) {
447                                 cr66 = (unsigned char)(dwScreenPitch & 0xFF);
448                                 viafb_write_reg(CR66, VIACR, cr66);
449                                 cr67 = viafb_read_reg(VIACR, CR67) & 0xFC;
450                                 cr67 |=
451                                     (unsigned
452                                      char)((dwScreenPitch & 0x300) >> 8);
453                                 viafb_write_reg(CR67, VIACR, cr67);
454                         }
455
456                         /* Fetch Count */
457                         cr67 = viafb_read_reg(VIACR, CR67) & 0xF3;
458                         cr67 |= (unsigned char)((dwScreenPitch & 0x600) >> 7);
459                         viafb_write_reg(CR67, VIACR, cr67);
460                         cr65 = (unsigned char)((dwScreenPitch >> 1) & 0xFF);
461                         cr65 += 2;
462                         viafb_write_reg(CR65, VIACR, cr65);
463                 } else {
464                         if (bpp > 8) {
465                                 cr13 = (unsigned char)(dwScreenPitch & 0xFF);
466                                 viafb_write_reg(CR13, VIACR, cr13);
467                                 cr35 = viafb_read_reg(VIACR, CR35) & 0x1F;
468                                 cr35 |=
469                                     (unsigned
470                                      char)((dwScreenPitch & 0x700) >> 3);
471                                 viafb_write_reg(CR35, VIACR, cr35);
472                         }
473                 }
474         }
475 }
476 static void lcd_patch_skew_dvp0(struct lvds_setting_information
477                          *plvds_setting_info,
478                          struct lvds_chip_information *plvds_chip_info)
479 {
480         if (VT1636_LVDS == plvds_chip_info->lvds_chip_name) {
481                 switch (viaparinfo->chip_info->gfx_chip_name) {
482                 case UNICHROME_P4M900:
483                         viafb_vt1636_patch_skew_on_vt3364(plvds_setting_info,
484                                                     plvds_chip_info);
485                         break;
486                 case UNICHROME_P4M890:
487                         viafb_vt1636_patch_skew_on_vt3327(plvds_setting_info,
488                                                     plvds_chip_info);
489                         break;
490                 }
491         }
492 }
493 static void lcd_patch_skew_dvp1(struct lvds_setting_information
494                          *plvds_setting_info,
495                          struct lvds_chip_information *plvds_chip_info)
496 {
497         if (VT1636_LVDS == plvds_chip_info->lvds_chip_name) {
498                 switch (viaparinfo->chip_info->gfx_chip_name) {
499                 case UNICHROME_CX700:
500                         viafb_vt1636_patch_skew_on_vt3324(plvds_setting_info,
501                                                     plvds_chip_info);
502                         break;
503                 }
504         }
505 }
506 static void lcd_patch_skew(struct lvds_setting_information
507         *plvds_setting_info, struct lvds_chip_information *plvds_chip_info)
508 {
509         DEBUG_MSG(KERN_INFO "lcd_patch_skew\n");
510         switch (plvds_chip_info->output_interface) {
511         case INTERFACE_DVP0:
512                 lcd_patch_skew_dvp0(plvds_setting_info, plvds_chip_info);
513                 break;
514         case INTERFACE_DVP1:
515                 lcd_patch_skew_dvp1(plvds_setting_info, plvds_chip_info);
516                 break;
517         case INTERFACE_DFP_LOW:
518                 if (UNICHROME_P4M900 == viaparinfo->chip_info->gfx_chip_name) {
519                         viafb_write_reg_mask(CR99, VIACR, 0x08,
520                                        BIT0 + BIT1 + BIT2 + BIT3);
521                 }
522                 break;
523         }
524 }
525
526 /* LCD Set Mode */
527 void viafb_lcd_set_mode(const struct fb_var_screeninfo *var, u16 cxres,
528         u16 cyres, struct lvds_setting_information *plvds_setting_info,
529         struct lvds_chip_information *plvds_chip_info)
530 {
531         int set_iga = plvds_setting_info->iga_path;
532         int mode_bpp = var->bits_per_pixel;
533         int set_hres = cxres ? cxres : var->xres;
534         int set_vres = cyres ? cyres : var->yres;
535         int panel_hres = plvds_setting_info->lcd_panel_hres;
536         int panel_vres = plvds_setting_info->lcd_panel_vres;
537         u32 clock;
538         struct via_display_timing timing;
539         struct fb_var_screeninfo panel_var;
540         const struct fb_videomode *panel_crt_table;
541
542         DEBUG_MSG(KERN_INFO "viafb_lcd_set_mode!!\n");
543         /* Get panel table Pointer */
544         panel_crt_table = viafb_get_best_mode(panel_hres, panel_vres, 60);
545         viafb_fill_var_timing_info(&panel_var, panel_crt_table);
546         DEBUG_MSG(KERN_INFO "below viafb_lcd_set_mode!!\n");
547         if (VT1636_LVDS == plvds_chip_info->lvds_chip_name)
548                 viafb_init_lvds_vt1636(plvds_setting_info, plvds_chip_info);
549         clock = PICOS2KHZ(panel_crt_table->pixclock) * 1000;
550         plvds_setting_info->vclk = clock;
551
552         if (set_iga == IGA2 && (set_hres < panel_hres || set_vres < panel_vres)
553                 && plvds_setting_info->display_method == LCD_EXPANDSION) {
554                 timing = var_to_timing(&panel_var, panel_hres, panel_vres);
555                 load_lcd_scaling(set_hres, set_vres, panel_hres, panel_vres);
556         } else {
557                 timing = var_to_timing(&panel_var, set_hres, set_vres);
558                 if (set_iga == IGA2)
559                         /* disable scaling */
560                         via_write_reg_mask(VIACR, 0x79, 0x00,
561                                 BIT0 + BIT1 + BIT2);
562         }
563
564         if (set_iga == IGA1)
565                 via_set_primary_timing(&timing);
566         else if (set_iga == IGA2)
567                 via_set_secondary_timing(&timing);
568
569         /* Fetch count for IGA2 only */
570         viafb_load_fetch_count_reg(set_hres, mode_bpp / 8, set_iga);
571
572         if ((viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266)
573                 && (viaparinfo->chip_info->gfx_chip_name != UNICHROME_K400))
574                 viafb_load_FIFO_reg(set_iga, set_hres, set_vres);
575
576         fill_lcd_format();
577         viafb_set_vclock(clock, set_iga);
578         lcd_patch_skew(plvds_setting_info, plvds_chip_info);
579
580         /* If K8M800, enable LCD Prefetch Mode. */
581         if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800)
582             || (UNICHROME_K8M890 == viaparinfo->chip_info->gfx_chip_name))
583                 viafb_write_reg_mask(CR6A, VIACR, 0x01, BIT0);
584
585         /* Patch for non 32bit alignment mode */
586         via_pitch_alignment_patch_lcd(plvds_setting_info->iga_path, set_hres,
587                 var->bits_per_pixel);
588 }
589
590 static void integrated_lvds_disable(struct lvds_setting_information
591                              *plvds_setting_info,
592                              struct lvds_chip_information *plvds_chip_info)
593 {
594         bool turn_off_first_powersequence = false;
595         bool turn_off_second_powersequence = false;
596         if (INTERFACE_LVDS0LVDS1 == plvds_chip_info->output_interface)
597                 turn_off_first_powersequence = true;
598         if (INTERFACE_LVDS0 == plvds_chip_info->output_interface)
599                 turn_off_first_powersequence = true;
600         if (INTERFACE_LVDS1 == plvds_chip_info->output_interface)
601                 turn_off_second_powersequence = true;
602         if (turn_off_second_powersequence) {
603                 /* Use second power sequence control: */
604
605                 /* Turn off power sequence. */
606                 viafb_write_reg_mask(CRD4, VIACR, 0, BIT1);
607
608                 /* Turn off back light. */
609                 viafb_write_reg_mask(CRD3, VIACR, 0xC0, BIT6 + BIT7);
610         }
611         if (turn_off_first_powersequence) {
612                 /* Use first power sequence control: */
613
614                 /* Turn off power sequence. */
615                 viafb_write_reg_mask(CR6A, VIACR, 0, BIT3);
616
617                 /* Turn off back light. */
618                 viafb_write_reg_mask(CR91, VIACR, 0xC0, BIT6 + BIT7);
619         }
620
621         /* Power off LVDS channel. */
622         switch (plvds_chip_info->output_interface) {
623         case INTERFACE_LVDS0:
624                 {
625                         viafb_write_reg_mask(CRD2, VIACR, 0x80, BIT7);
626                         break;
627                 }
628
629         case INTERFACE_LVDS1:
630                 {
631                         viafb_write_reg_mask(CRD2, VIACR, 0x40, BIT6);
632                         break;
633                 }
634
635         case INTERFACE_LVDS0LVDS1:
636                 {
637                         viafb_write_reg_mask(CRD2, VIACR, 0xC0, BIT6 + BIT7);
638                         break;
639                 }
640         }
641 }
642
643 static void integrated_lvds_enable(struct lvds_setting_information
644                             *plvds_setting_info,
645                             struct lvds_chip_information *plvds_chip_info)
646 {
647         DEBUG_MSG(KERN_INFO "integrated_lvds_enable, out_interface:%d\n",
648                   plvds_chip_info->output_interface);
649         if (plvds_setting_info->lcd_mode == LCD_SPWG)
650                 viafb_write_reg_mask(CRD2, VIACR, 0x00, BIT0 + BIT1);
651         else
652                 viafb_write_reg_mask(CRD2, VIACR, 0x03, BIT0 + BIT1);
653
654         switch (plvds_chip_info->output_interface) {
655         case INTERFACE_LVDS0LVDS1:
656         case INTERFACE_LVDS0:
657                 /* Use first power sequence control: */
658                 /* Use hardware control power sequence. */
659                 viafb_write_reg_mask(CR91, VIACR, 0, BIT0);
660                 /* Turn on back light. */
661                 viafb_write_reg_mask(CR91, VIACR, 0, BIT6 + BIT7);
662                 /* Turn on hardware power sequence. */
663                 viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3);
664                 break;
665         case INTERFACE_LVDS1:
666                 /* Use second power sequence control: */
667                 /* Use hardware control power sequence. */
668                 viafb_write_reg_mask(CRD3, VIACR, 0, BIT0);
669                 /* Turn on back light. */
670                 viafb_write_reg_mask(CRD3, VIACR, 0, BIT6 + BIT7);
671                 /* Turn on hardware power sequence. */
672                 viafb_write_reg_mask(CRD4, VIACR, 0x02, BIT1);
673                 break;
674         }
675
676         /* Power on LVDS channel. */
677         switch (plvds_chip_info->output_interface) {
678         case INTERFACE_LVDS0:
679                 {
680                         viafb_write_reg_mask(CRD2, VIACR, 0, BIT7);
681                         break;
682                 }
683
684         case INTERFACE_LVDS1:
685                 {
686                         viafb_write_reg_mask(CRD2, VIACR, 0, BIT6);
687                         break;
688                 }
689
690         case INTERFACE_LVDS0LVDS1:
691                 {
692                         viafb_write_reg_mask(CRD2, VIACR, 0, BIT6 + BIT7);
693                         break;
694                 }
695         }
696 }
697
698 void viafb_lcd_disable(void)
699 {
700
701         if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
702                 lcd_powersequence_off();
703                 /* DI1 pad off */
704                 viafb_write_reg_mask(SR1E, VIASR, 0x00, 0x30);
705         } else if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) {
706                 if (viafb_LCD2_ON
707                     && (INTEGRATED_LVDS ==
708                         viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name))
709                         integrated_lvds_disable(viaparinfo->lvds_setting_info,
710                                 &viaparinfo->chip_info->lvds_chip_info2);
711                 if (INTEGRATED_LVDS ==
712                         viaparinfo->chip_info->lvds_chip_info.lvds_chip_name)
713                         integrated_lvds_disable(viaparinfo->lvds_setting_info,
714                                 &viaparinfo->chip_info->lvds_chip_info);
715                 if (VT1636_LVDS == viaparinfo->chip_info->
716                         lvds_chip_info.lvds_chip_name)
717                         viafb_disable_lvds_vt1636(viaparinfo->lvds_setting_info,
718                                 &viaparinfo->chip_info->lvds_chip_info);
719         } else if (VT1636_LVDS ==
720         viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
721                 viafb_disable_lvds_vt1636(viaparinfo->lvds_setting_info,
722                                     &viaparinfo->chip_info->lvds_chip_info);
723         } else {
724                 /* Backlight off           */
725                 viafb_write_reg_mask(SR3D, VIASR, 0x00, 0x20);
726                 /* 24 bit DI data paht off */
727                 viafb_write_reg_mask(CR91, VIACR, 0x80, 0x80);
728         }
729
730         /* Disable expansion bit   */
731         viafb_write_reg_mask(CR79, VIACR, 0x00, 0x01);
732         /* Simultaneout disabled   */
733         viafb_write_reg_mask(CR6B, VIACR, 0x00, 0x08);
734 }
735
736 static void set_lcd_output_path(int set_iga, int output_interface)
737 {
738         switch (output_interface) {
739         case INTERFACE_DFP:
740                 if ((UNICHROME_K8M890 == viaparinfo->chip_info->gfx_chip_name)
741                     || (UNICHROME_P4M890 ==
742                     viaparinfo->chip_info->gfx_chip_name))
743                         viafb_write_reg_mask(CR97, VIACR, 0x84,
744                                        BIT7 + BIT2 + BIT1 + BIT0);
745                 fallthrough;
746         case INTERFACE_DVP0:
747         case INTERFACE_DVP1:
748         case INTERFACE_DFP_HIGH:
749         case INTERFACE_DFP_LOW:
750                 if (set_iga == IGA2)
751                         viafb_write_reg(CR91, VIACR, 0x00);
752                 break;
753         }
754 }
755
756 void viafb_lcd_enable(void)
757 {
758         viafb_write_reg_mask(CR6B, VIACR, 0x00, BIT3);
759         viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3);
760         set_lcd_output_path(viaparinfo->lvds_setting_info->iga_path,
761                 viaparinfo->chip_info->lvds_chip_info.output_interface);
762         if (viafb_LCD2_ON)
763                 set_lcd_output_path(viaparinfo->lvds_setting_info2->iga_path,
764                         viaparinfo->chip_info->
765                         lvds_chip_info2.output_interface);
766
767         if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
768                 /* DI1 pad on */
769                 viafb_write_reg_mask(SR1E, VIASR, 0x30, 0x30);
770                 lcd_powersequence_on();
771         } else if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) {
772                 if (viafb_LCD2_ON && (INTEGRATED_LVDS ==
773                         viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name))
774                         integrated_lvds_enable(viaparinfo->lvds_setting_info2, \
775                                 &viaparinfo->chip_info->lvds_chip_info2);
776                 if (INTEGRATED_LVDS ==
777                         viaparinfo->chip_info->lvds_chip_info.lvds_chip_name)
778                         integrated_lvds_enable(viaparinfo->lvds_setting_info,
779                                 &viaparinfo->chip_info->lvds_chip_info);
780                 if (VT1636_LVDS == viaparinfo->chip_info->
781                         lvds_chip_info.lvds_chip_name)
782                         viafb_enable_lvds_vt1636(viaparinfo->
783                         lvds_setting_info, &viaparinfo->chip_info->
784                         lvds_chip_info);
785         } else if (VT1636_LVDS ==
786         viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
787                 viafb_enable_lvds_vt1636(viaparinfo->lvds_setting_info,
788                                    &viaparinfo->chip_info->lvds_chip_info);
789         } else {
790                 /* Backlight on            */
791                 viafb_write_reg_mask(SR3D, VIASR, 0x20, 0x20);
792                 /* 24 bit DI data paht on  */
793                 viafb_write_reg_mask(CR91, VIACR, 0x00, 0x80);
794                 /* LCD enabled             */
795                 viafb_write_reg_mask(CR6A, VIACR, 0x48, 0x48);
796         }
797 }
798
799 static void lcd_powersequence_off(void)
800 {
801         int i, mask, data;
802
803         /* Software control power sequence */
804         viafb_write_reg_mask(CR91, VIACR, 0x11, 0x11);
805
806         for (i = 0; i < 3; i++) {
807                 mask = PowerSequenceOff[0][i];
808                 data = PowerSequenceOff[1][i] & mask;
809                 viafb_write_reg_mask(CR91, VIACR, (u8) data, (u8) mask);
810                 udelay(PowerSequenceOff[2][i]);
811         }
812
813         /* Disable LCD */
814         viafb_write_reg_mask(CR6A, VIACR, 0x00, 0x08);
815 }
816
817 static void lcd_powersequence_on(void)
818 {
819         int i, mask, data;
820
821         /* Software control power sequence */
822         viafb_write_reg_mask(CR91, VIACR, 0x11, 0x11);
823
824         /* Enable LCD */
825         viafb_write_reg_mask(CR6A, VIACR, 0x08, 0x08);
826
827         for (i = 0; i < 3; i++) {
828                 mask = PowerSequenceOn[0][i];
829                 data = PowerSequenceOn[1][i] & mask;
830                 viafb_write_reg_mask(CR91, VIACR, (u8) data, (u8) mask);
831                 udelay(PowerSequenceOn[2][i]);
832         }
833
834         udelay(1);
835 }
836
837 static void fill_lcd_format(void)
838 {
839         u8 bdithering = 0, bdual = 0;
840
841         if (viaparinfo->lvds_setting_info->device_lcd_dualedge)
842                 bdual = BIT4;
843         if (viaparinfo->lvds_setting_info->LCDDithering)
844                 bdithering = BIT0;
845         /* Dual & Dithering */
846         viafb_write_reg_mask(CR88, VIACR, (bdithering | bdual), BIT4 + BIT0);
847 }
848
849 static void check_diport_of_integrated_lvds(
850         struct lvds_chip_information *plvds_chip_info,
851                                      struct lvds_setting_information
852                                      *plvds_setting_info)
853 {
854         /* Determine LCD DI Port by hardware layout. */
855         switch (viafb_display_hardware_layout) {
856         case HW_LAYOUT_LCD_ONLY:
857                 {
858                         if (plvds_setting_info->device_lcd_dualedge) {
859                                 plvds_chip_info->output_interface =
860                                     INTERFACE_LVDS0LVDS1;
861                         } else {
862                                 plvds_chip_info->output_interface =
863                                     INTERFACE_LVDS0;
864                         }
865
866                         break;
867                 }
868
869         case HW_LAYOUT_DVI_ONLY:
870                 {
871                         plvds_chip_info->output_interface = INTERFACE_NONE;
872                         break;
873                 }
874
875         case HW_LAYOUT_LCD1_LCD2:
876         case HW_LAYOUT_LCD_EXTERNAL_LCD2:
877                 {
878                         plvds_chip_info->output_interface =
879                             INTERFACE_LVDS0LVDS1;
880                         break;
881                 }
882
883         case HW_LAYOUT_LCD_DVI:
884                 {
885                         plvds_chip_info->output_interface = INTERFACE_LVDS1;
886                         break;
887                 }
888
889         default:
890                 {
891                         plvds_chip_info->output_interface = INTERFACE_LVDS1;
892                         break;
893                 }
894         }
895
896         DEBUG_MSG(KERN_INFO
897                   "Display Hardware Layout: 0x%x, LCD DI Port: 0x%x\n",
898                   viafb_display_hardware_layout,
899                   plvds_chip_info->output_interface);
900 }
901
902 void viafb_init_lvds_output_interface(struct lvds_chip_information
903                                 *plvds_chip_info,
904                                 struct lvds_setting_information
905                                 *plvds_setting_info)
906 {
907         if (INTERFACE_NONE != plvds_chip_info->output_interface) {
908                 /*Do nothing, lcd port is specified by module parameter */
909                 return;
910         }
911
912         switch (plvds_chip_info->lvds_chip_name) {
913
914         case VT1636_LVDS:
915                 switch (viaparinfo->chip_info->gfx_chip_name) {
916                 case UNICHROME_CX700:
917                         plvds_chip_info->output_interface = INTERFACE_DVP1;
918                         break;
919                 case UNICHROME_CN700:
920                         plvds_chip_info->output_interface = INTERFACE_DFP_LOW;
921                         break;
922                 default:
923                         plvds_chip_info->output_interface = INTERFACE_DVP0;
924                         break;
925                 }
926                 break;
927
928         case INTEGRATED_LVDS:
929                 check_diport_of_integrated_lvds(plvds_chip_info,
930                                                 plvds_setting_info);
931                 break;
932
933         default:
934                 switch (viaparinfo->chip_info->gfx_chip_name) {
935                 case UNICHROME_K8M890:
936                 case UNICHROME_P4M900:
937                 case UNICHROME_P4M890:
938                         plvds_chip_info->output_interface = INTERFACE_DFP_LOW;
939                         break;
940                 default:
941                         plvds_chip_info->output_interface = INTERFACE_DFP;
942                         break;
943                 }
944                 break;
945         }
946 }
947
948 bool viafb_lcd_get_mobile_state(bool *mobile)
949 {
950         unsigned char __iomem *romptr, *tableptr, *biosptr;
951         u8 core_base;
952         /* Rom address */
953         const u32 romaddr = 0x000C0000;
954         u16 start_pattern;
955
956         biosptr = ioremap(romaddr, 0x10000);
957         start_pattern = readw(biosptr);
958
959         /* Compare pattern */
960         if (start_pattern == 0xAA55) {
961                 /* Get the start of Table */
962                 /* 0x1B means BIOS offset position */
963                 romptr = biosptr + 0x1B;
964                 tableptr = biosptr + readw(romptr);
965
966                 /* Get the start of biosver structure */
967                 /* 18 means BIOS version position. */
968                 romptr = tableptr + 18;
969                 romptr = biosptr + readw(romptr);
970
971                 /* The offset should be 44, but the
972                    actual image is less three char. */
973                 /* pRom += 44; */
974                 romptr += 41;
975
976                 core_base = readb(romptr);
977
978                 if (core_base & 0x8)
979                         *mobile = false;
980                 else
981                         *mobile = true;
982                 /* release memory */
983                 iounmap(biosptr);
984
985                 return true;
986         } else {
987                 iounmap(biosptr);
988                 return false;
989         }
990 }