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