blob: 02cfdc8d7edd78e12fbd111443bd020344ecdba9 [file] [log] [blame]
Joseph Chanac6c97e2008-10-15 22:03:25 -07001/*
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 */
Jonathan Corbetec668412010-05-05 14:44:55 -060021#include <linux/via-core.h>
22#include <linux/via_i2c.h>
Joseph Chanac6c97e2008-10-15 22:03:25 -070023#include "global.h"
Joseph Chanac6c97e2008-10-15 22:03:25 -070024
Florian Tobias Schandinatdd73d682010-03-10 15:21:28 -080025#define viafb_compact_res(x, y) (((x)<<16)|(y))
26
Florian Tobias Schandinat91336712010-08-07 18:47:01 +000027/* CLE266 Software Power Sequence */
28/* {Mask}, {Data}, {Delay} */
Stephen Hemminger23e5abd2011-03-03 10:00:08 -080029static 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};
Florian Tobias Schandinat91336712010-08-07 18:47:01 +000035
Joseph Chanac6c97e2008-10-15 22:03:25 -070036static 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
Joseph Chanac6c97e2008-10-15 22:03:25 -070051static bool lvds_identify_integratedlvds(void);
Florian Tobias Schandinatf4ab2f7a2010-08-09 01:34:27 +000052static void __devinit fp_id_to_vindex(int panel_id);
Joseph Chanac6c97e2008-10-15 22:03:25 -070053static int lvds_register_read(int index);
54static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
55 int panel_vres);
Joseph Chanac6c97e2008-10-15 22:03:25 -070056static void via_pitch_alignment_patch_lcd(
57 struct lvds_setting_information *plvds_setting_info,
Florian Tobias Schandinat4e5527c2012-02-12 20:08:41 +000058 struct lvds_chip_information *plvds_chip_info, int hres);
Joseph Chanac6c97e2008-10-15 22:03:25 -070059static void lcd_patch_skew_dvp0(struct lvds_setting_information
60 *plvds_setting_info,
61 struct lvds_chip_information *plvds_chip_info);
62static void lcd_patch_skew_dvp1(struct lvds_setting_information
63 *plvds_setting_info,
64 struct lvds_chip_information *plvds_chip_info);
65static void lcd_patch_skew(struct lvds_setting_information
66 *plvds_setting_info, struct lvds_chip_information *plvds_chip_info);
67
68static void integrated_lvds_disable(struct lvds_setting_information
69 *plvds_setting_info,
70 struct lvds_chip_information *plvds_chip_info);
71static void integrated_lvds_enable(struct lvds_setting_information
72 *plvds_setting_info,
73 struct lvds_chip_information *plvds_chip_info);
74static void lcd_powersequence_off(void);
75static void lcd_powersequence_on(void);
76static void fill_lcd_format(void);
77static void check_diport_of_integrated_lvds(
78 struct lvds_chip_information *plvds_chip_info,
79 struct lvds_setting_information
80 *plvds_setting_info);
81static struct display_timing lcd_centering_timging(struct display_timing
82 mode_crt_reg,
83 struct display_timing panel_crt_reg);
Joseph Chanac6c97e2008-10-15 22:03:25 -070084
Florian Tobias Schandinatcd00b112011-03-27 03:36:00 +000085static inline bool check_lvds_chip(int device_id_subaddr, int device_id)
Joseph Chanac6c97e2008-10-15 22:03:25 -070086{
Florian Tobias Schandinatcd00b112011-03-27 03:36:00 +000087 return lvds_register_read(device_id_subaddr) == device_id;
Joseph Chanac6c97e2008-10-15 22:03:25 -070088}
89
Florian Tobias Schandinatf4ab2f7a2010-08-09 01:34:27 +000090void __devinit viafb_init_lcd_size(void)
Joseph Chanac6c97e2008-10-15 22:03:25 -070091{
92 DEBUG_MSG(KERN_INFO "viafb_init_lcd_size()\n");
Joseph Chanac6c97e2008-10-15 22:03:25 -070093
Florian Tobias Schandinatcc3fd672010-06-02 19:41:23 +000094 fp_id_to_vindex(viafb_lcd_panel_id);
Joseph Chanac6c97e2008-10-15 22:03:25 -070095 viaparinfo->lvds_setting_info2->lcd_panel_hres =
96 viaparinfo->lvds_setting_info->lcd_panel_hres;
97 viaparinfo->lvds_setting_info2->lcd_panel_vres =
98 viaparinfo->lvds_setting_info->lcd_panel_vres;
99 viaparinfo->lvds_setting_info2->device_lcd_dualedge =
100 viaparinfo->lvds_setting_info->device_lcd_dualedge;
101 viaparinfo->lvds_setting_info2->LCDDithering =
102 viaparinfo->lvds_setting_info->LCDDithering;
103}
104
105static bool lvds_identify_integratedlvds(void)
106{
107 if (viafb_display_hardware_layout == HW_LAYOUT_LCD_EXTERNAL_LCD2) {
108 /* Two dual channel LCD (Internal LVDS + External LVDS): */
109 /* If we have an external LVDS, such as VT1636, we should
110 have its chip ID already. */
111 if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
112 viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name =
113 INTEGRATED_LVDS;
Joe Perches2c0e0c82010-03-10 15:21:48 -0800114 DEBUG_MSG(KERN_INFO "Support two dual channel LVDS! "
115 "(Internal LVDS + External LVDS)\n");
Joseph Chanac6c97e2008-10-15 22:03:25 -0700116 } else {
117 viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
118 INTEGRATED_LVDS;
Joe Perches2c0e0c82010-03-10 15:21:48 -0800119 DEBUG_MSG(KERN_INFO "Not found external LVDS, "
120 "so can't support two dual channel LVDS!\n");
Joseph Chanac6c97e2008-10-15 22:03:25 -0700121 }
122 } else if (viafb_display_hardware_layout == HW_LAYOUT_LCD1_LCD2) {
123 /* Two single channel LCD (Internal LVDS + Internal LVDS): */
124 viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
125 INTEGRATED_LVDS;
126 viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name =
127 INTEGRATED_LVDS;
Joe Perches2c0e0c82010-03-10 15:21:48 -0800128 DEBUG_MSG(KERN_INFO "Support two single channel LVDS! "
129 "(Internal LVDS + Internal LVDS)\n");
Joseph Chanac6c97e2008-10-15 22:03:25 -0700130 } else if (viafb_display_hardware_layout != HW_LAYOUT_DVI_ONLY) {
131 /* If we have found external LVDS, just use it,
132 otherwise, we will use internal LVDS as default. */
133 if (!viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
134 viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
135 INTEGRATED_LVDS;
136 DEBUG_MSG(KERN_INFO "Found Integrated LVDS!\n");
137 }
138 } else {
139 viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
140 NON_LVDS_TRANSMITTER;
141 DEBUG_MSG(KERN_INFO "Do not support LVDS!\n");
142 return false;
143 }
144
145 return true;
146}
147
Florian Tobias Schandinatcd00b112011-03-27 03:36:00 +0000148bool __devinit viafb_lvds_trasmitter_identify(void)
Joseph Chanac6c97e2008-10-15 22:03:25 -0700149{
Jonathan Corbetf045f772009-12-01 20:29:39 -0700150 if (viafb_lvds_identify_vt1636(VIA_PORT_31)) {
151 viaparinfo->chip_info->lvds_chip_info.i2c_port = VIA_PORT_31;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700152 DEBUG_MSG(KERN_INFO
Harald Welte277d32a2009-05-23 00:35:39 +0800153 "Found VIA VT1636 LVDS on port i2c 0x31\n");
Joseph Chanac6c97e2008-10-15 22:03:25 -0700154 } else {
Jonathan Corbetf045f772009-12-01 20:29:39 -0700155 if (viafb_lvds_identify_vt1636(VIA_PORT_2C)) {
Joseph Chanac6c97e2008-10-15 22:03:25 -0700156 viaparinfo->chip_info->lvds_chip_info.i2c_port =
Jonathan Corbetf045f772009-12-01 20:29:39 -0700157 VIA_PORT_2C;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700158 DEBUG_MSG(KERN_INFO
Harald Welte277d32a2009-05-23 00:35:39 +0800159 "Found VIA VT1636 LVDS on port gpio 0x2c\n");
Joseph Chanac6c97e2008-10-15 22:03:25 -0700160 }
161 }
162
163 if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700)
164 lvds_identify_integratedlvds();
165
166 if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name)
167 return true;
168 /* Check for VT1631: */
169 viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = VT1631_LVDS;
170 viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr =
171 VT1631_LVDS_I2C_ADDR;
172
Florian Tobias Schandinatcd00b112011-03-27 03:36:00 +0000173 if (check_lvds_chip(VT1631_DEVICE_ID_REG, VT1631_DEVICE_ID)) {
Joseph Chanac6c97e2008-10-15 22:03:25 -0700174 DEBUG_MSG(KERN_INFO "\n VT1631 LVDS ! \n");
175 DEBUG_MSG(KERN_INFO "\n %2d",
176 viaparinfo->chip_info->lvds_chip_info.lvds_chip_name);
177 DEBUG_MSG(KERN_INFO "\n %2d",
178 viaparinfo->chip_info->lvds_chip_info.lvds_chip_name);
Florian Tobias Schandinatcd00b112011-03-27 03:36:00 +0000179 return true;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700180 }
181
182 viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
183 NON_LVDS_TRANSMITTER;
184 viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr =
185 VT1631_LVDS_I2C_ADDR;
Florian Tobias Schandinatcd00b112011-03-27 03:36:00 +0000186 return false;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700187}
188
Florian Tobias Schandinatf4ab2f7a2010-08-09 01:34:27 +0000189static void __devinit fp_id_to_vindex(int panel_id)
Joseph Chanac6c97e2008-10-15 22:03:25 -0700190{
191 DEBUG_MSG(KERN_INFO "fp_get_panel_id()\n");
192
193 if (panel_id > LCD_PANEL_ID_MAXIMUM)
194 viafb_lcd_panel_id = panel_id =
195 viafb_read_reg(VIACR, CR3F) & 0x0F;
196
197 switch (panel_id) {
198 case 0x0:
199 viaparinfo->lvds_setting_info->lcd_panel_hres = 640;
200 viaparinfo->lvds_setting_info->lcd_panel_vres = 480;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700201 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
202 viaparinfo->lvds_setting_info->LCDDithering = 1;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700203 break;
204 case 0x1:
205 viaparinfo->lvds_setting_info->lcd_panel_hres = 800;
206 viaparinfo->lvds_setting_info->lcd_panel_vres = 600;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700207 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
208 viaparinfo->lvds_setting_info->LCDDithering = 1;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700209 break;
210 case 0x2:
211 viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
212 viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700213 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
214 viaparinfo->lvds_setting_info->LCDDithering = 1;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700215 break;
216 case 0x3:
217 viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
218 viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700219 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
220 viaparinfo->lvds_setting_info->LCDDithering = 1;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700221 break;
222 case 0x4:
223 viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
224 viaparinfo->lvds_setting_info->lcd_panel_vres = 1024;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700225 viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
226 viaparinfo->lvds_setting_info->LCDDithering = 1;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700227 break;
228 case 0x5:
229 viaparinfo->lvds_setting_info->lcd_panel_hres = 1400;
230 viaparinfo->lvds_setting_info->lcd_panel_vres = 1050;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700231 viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
232 viaparinfo->lvds_setting_info->LCDDithering = 1;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700233 break;
234 case 0x6:
235 viaparinfo->lvds_setting_info->lcd_panel_hres = 1600;
236 viaparinfo->lvds_setting_info->lcd_panel_vres = 1200;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700237 viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
238 viaparinfo->lvds_setting_info->LCDDithering = 1;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700239 break;
240 case 0x8:
241 viaparinfo->lvds_setting_info->lcd_panel_hres = 800;
242 viaparinfo->lvds_setting_info->lcd_panel_vres = 480;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700243 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
244 viaparinfo->lvds_setting_info->LCDDithering = 1;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700245 break;
246 case 0x9:
247 viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
248 viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700249 viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
250 viaparinfo->lvds_setting_info->LCDDithering = 1;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700251 break;
252 case 0xA:
253 viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
254 viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700255 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
256 viaparinfo->lvds_setting_info->LCDDithering = 0;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700257 break;
258 case 0xB:
259 viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
260 viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700261 viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
262 viaparinfo->lvds_setting_info->LCDDithering = 0;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700263 break;
264 case 0xC:
265 viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
266 viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700267 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
268 viaparinfo->lvds_setting_info->LCDDithering = 0;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700269 break;
270 case 0xD:
271 viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
272 viaparinfo->lvds_setting_info->lcd_panel_vres = 1024;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700273 viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
274 viaparinfo->lvds_setting_info->LCDDithering = 0;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700275 break;
276 case 0xE:
277 viaparinfo->lvds_setting_info->lcd_panel_hres = 1400;
278 viaparinfo->lvds_setting_info->lcd_panel_vres = 1050;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700279 viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
280 viaparinfo->lvds_setting_info->LCDDithering = 0;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700281 break;
282 case 0xF:
283 viaparinfo->lvds_setting_info->lcd_panel_hres = 1600;
284 viaparinfo->lvds_setting_info->lcd_panel_vres = 1200;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700285 viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
286 viaparinfo->lvds_setting_info->LCDDithering = 0;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700287 break;
288 case 0x10:
289 viaparinfo->lvds_setting_info->lcd_panel_hres = 1366;
290 viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700291 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
292 viaparinfo->lvds_setting_info->LCDDithering = 0;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700293 break;
294 case 0x11:
295 viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
296 viaparinfo->lvds_setting_info->lcd_panel_vres = 600;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700297 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
298 viaparinfo->lvds_setting_info->LCDDithering = 1;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700299 break;
300 case 0x12:
301 viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
302 viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700303 viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
304 viaparinfo->lvds_setting_info->LCDDithering = 1;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700305 break;
306 case 0x13:
307 viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
308 viaparinfo->lvds_setting_info->lcd_panel_vres = 800;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700309 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
310 viaparinfo->lvds_setting_info->LCDDithering = 1;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700311 break;
312 case 0x14:
313 viaparinfo->lvds_setting_info->lcd_panel_hres = 1360;
314 viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700315 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
316 viaparinfo->lvds_setting_info->LCDDithering = 0;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700317 break;
318 case 0x15:
319 viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
320 viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700321 viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
322 viaparinfo->lvds_setting_info->LCDDithering = 0;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700323 break;
324 case 0x16:
325 viaparinfo->lvds_setting_info->lcd_panel_hres = 480;
326 viaparinfo->lvds_setting_info->lcd_panel_vres = 640;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700327 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
328 viaparinfo->lvds_setting_info->LCDDithering = 1;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700329 break;
Chris Ballc205d932009-06-07 13:59:51 -0400330 case 0x17:
331 /* OLPC XO-1.5 panel */
332 viaparinfo->lvds_setting_info->lcd_panel_hres = 1200;
333 viaparinfo->lvds_setting_info->lcd_panel_vres = 900;
Chris Ballc205d932009-06-07 13:59:51 -0400334 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
335 viaparinfo->lvds_setting_info->LCDDithering = 0;
336 break;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700337 default:
338 viaparinfo->lvds_setting_info->lcd_panel_hres = 800;
339 viaparinfo->lvds_setting_info->lcd_panel_vres = 600;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700340 viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
341 viaparinfo->lvds_setting_info->LCDDithering = 1;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700342 }
343}
344
345static int lvds_register_read(int index)
346{
347 u8 data;
348
Jonathan Corbetf045f772009-12-01 20:29:39 -0700349 viafb_i2c_readbyte(VIA_PORT_2C,
Harald Welte277d32a2009-05-23 00:35:39 +0800350 (u8) viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr,
Joseph Chanac6c97e2008-10-15 22:03:25 -0700351 (u8) index, &data);
352 return data;
353}
354
355static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
356 int panel_vres)
357{
358 int reg_value = 0;
359 int viafb_load_reg_num;
360 struct io_register *reg = NULL;
361
362 DEBUG_MSG(KERN_INFO "load_lcd_scaling()!!\n");
363
364 /* LCD Scaling Enable */
365 viafb_write_reg_mask(CR79, VIACR, 0x07, BIT0 + BIT1 + BIT2);
Joseph Chanac6c97e2008-10-15 22:03:25 -0700366
367 /* Check if expansion for horizontal */
Florian Tobias Schandinat119b9532010-05-22 21:32:32 +0000368 if (set_hres < panel_hres) {
Joseph Chanac6c97e2008-10-15 22:03:25 -0700369 /* Load Horizontal Scaling Factor */
370 switch (viaparinfo->chip_info->gfx_chip_name) {
371 case UNICHROME_CLE266:
372 case UNICHROME_K400:
373 reg_value =
374 CLE266_LCD_HOR_SCF_FORMULA(set_hres, panel_hres);
375 viafb_load_reg_num =
376 lcd_scaling_factor_CLE.lcd_hor_scaling_factor.
377 reg_num;
378 reg = lcd_scaling_factor_CLE.lcd_hor_scaling_factor.reg;
379 viafb_load_reg(reg_value,
380 viafb_load_reg_num, reg, VIACR);
381 break;
382 case UNICHROME_K800:
383 case UNICHROME_PM800:
384 case UNICHROME_CN700:
385 case UNICHROME_CX700:
386 case UNICHROME_K8M890:
387 case UNICHROME_P4M890:
Florian Tobias Schandinat4a73d702010-05-22 21:22:36 +0000388 case UNICHROME_P4M900:
Florian Tobias Schandinatf1ad7522010-05-22 22:32:57 +0000389 case UNICHROME_CN750:
390 case UNICHROME_VX800:
391 case UNICHROME_VX855:
Florian Tobias Schandinat51f43322010-10-24 04:02:14 +0000392 case UNICHROME_VX900:
Joseph Chanac6c97e2008-10-15 22:03:25 -0700393 reg_value =
394 K800_LCD_HOR_SCF_FORMULA(set_hres, panel_hres);
395 /* Horizontal scaling enabled */
396 viafb_write_reg_mask(CRA2, VIACR, 0xC0, BIT7 + BIT6);
397 viafb_load_reg_num =
398 lcd_scaling_factor.lcd_hor_scaling_factor.reg_num;
399 reg = lcd_scaling_factor.lcd_hor_scaling_factor.reg;
400 viafb_load_reg(reg_value,
401 viafb_load_reg_num, reg, VIACR);
402 break;
403 }
404
405 DEBUG_MSG(KERN_INFO "Horizontal Scaling value = %d", reg_value);
406 } else {
407 /* Horizontal scaling disabled */
408 viafb_write_reg_mask(CRA2, VIACR, 0x00, BIT7);
409 }
410
411 /* Check if expansion for vertical */
Florian Tobias Schandinat119b9532010-05-22 21:32:32 +0000412 if (set_vres < panel_vres) {
Joseph Chanac6c97e2008-10-15 22:03:25 -0700413 /* Load Vertical Scaling Factor */
414 switch (viaparinfo->chip_info->gfx_chip_name) {
415 case UNICHROME_CLE266:
416 case UNICHROME_K400:
417 reg_value =
418 CLE266_LCD_VER_SCF_FORMULA(set_vres, panel_vres);
419 viafb_load_reg_num =
420 lcd_scaling_factor_CLE.lcd_ver_scaling_factor.
421 reg_num;
422 reg = lcd_scaling_factor_CLE.lcd_ver_scaling_factor.reg;
423 viafb_load_reg(reg_value,
424 viafb_load_reg_num, reg, VIACR);
425 break;
426 case UNICHROME_K800:
427 case UNICHROME_PM800:
428 case UNICHROME_CN700:
429 case UNICHROME_CX700:
430 case UNICHROME_K8M890:
431 case UNICHROME_P4M890:
Florian Tobias Schandinat4a73d702010-05-22 21:22:36 +0000432 case UNICHROME_P4M900:
Florian Tobias Schandinatf1ad7522010-05-22 22:32:57 +0000433 case UNICHROME_CN750:
434 case UNICHROME_VX800:
435 case UNICHROME_VX855:
Florian Tobias Schandinat51f43322010-10-24 04:02:14 +0000436 case UNICHROME_VX900:
Joseph Chanac6c97e2008-10-15 22:03:25 -0700437 reg_value =
438 K800_LCD_VER_SCF_FORMULA(set_vres, panel_vres);
439 /* Vertical scaling enabled */
440 viafb_write_reg_mask(CRA2, VIACR, 0x08, BIT3);
441 viafb_load_reg_num =
442 lcd_scaling_factor.lcd_ver_scaling_factor.reg_num;
443 reg = lcd_scaling_factor.lcd_ver_scaling_factor.reg;
444 viafb_load_reg(reg_value,
445 viafb_load_reg_num, reg, VIACR);
446 break;
447 }
448
449 DEBUG_MSG(KERN_INFO "Vertical Scaling value = %d", reg_value);
450 } else {
451 /* Vertical scaling disabled */
452 viafb_write_reg_mask(CRA2, VIACR, 0x00, BIT3);
453 }
454}
455
Joseph Chanac6c97e2008-10-15 22:03:25 -0700456static void via_pitch_alignment_patch_lcd(
457 struct lvds_setting_information *plvds_setting_info,
Florian Tobias Schandinat4e5527c2012-02-12 20:08:41 +0000458 struct lvds_chip_information *plvds_chip_info, int hres)
Joseph Chanac6c97e2008-10-15 22:03:25 -0700459{
460 unsigned char cr13, cr35, cr65, cr66, cr67;
461 unsigned long dwScreenPitch = 0;
462 unsigned long dwPitch;
463
Florian Tobias Schandinat4e5527c2012-02-12 20:08:41 +0000464 dwPitch = hres * (plvds_setting_info->bpp >> 3);
Joseph Chanac6c97e2008-10-15 22:03:25 -0700465 if (dwPitch & 0x1F) {
466 dwScreenPitch = ((dwPitch + 31) & ~31) >> 3;
467 if (plvds_setting_info->iga_path == IGA2) {
468 if (plvds_setting_info->bpp > 8) {
469 cr66 = (unsigned char)(dwScreenPitch & 0xFF);
470 viafb_write_reg(CR66, VIACR, cr66);
471 cr67 = viafb_read_reg(VIACR, CR67) & 0xFC;
472 cr67 |=
473 (unsigned
474 char)((dwScreenPitch & 0x300) >> 8);
475 viafb_write_reg(CR67, VIACR, cr67);
476 }
477
478 /* Fetch Count */
479 cr67 = viafb_read_reg(VIACR, CR67) & 0xF3;
480 cr67 |= (unsigned char)((dwScreenPitch & 0x600) >> 7);
481 viafb_write_reg(CR67, VIACR, cr67);
482 cr65 = (unsigned char)((dwScreenPitch >> 1) & 0xFF);
483 cr65 += 2;
484 viafb_write_reg(CR65, VIACR, cr65);
485 } else {
486 if (plvds_setting_info->bpp > 8) {
487 cr13 = (unsigned char)(dwScreenPitch & 0xFF);
488 viafb_write_reg(CR13, VIACR, cr13);
489 cr35 = viafb_read_reg(VIACR, CR35) & 0x1F;
490 cr35 |=
491 (unsigned
492 char)((dwScreenPitch & 0x700) >> 3);
493 viafb_write_reg(CR35, VIACR, cr35);
494 }
495 }
496 }
497}
498static void lcd_patch_skew_dvp0(struct lvds_setting_information
499 *plvds_setting_info,
500 struct lvds_chip_information *plvds_chip_info)
501{
502 if (VT1636_LVDS == plvds_chip_info->lvds_chip_name) {
503 switch (viaparinfo->chip_info->gfx_chip_name) {
504 case UNICHROME_P4M900:
505 viafb_vt1636_patch_skew_on_vt3364(plvds_setting_info,
506 plvds_chip_info);
507 break;
508 case UNICHROME_P4M890:
509 viafb_vt1636_patch_skew_on_vt3327(plvds_setting_info,
510 plvds_chip_info);
511 break;
512 }
513 }
514}
515static void lcd_patch_skew_dvp1(struct lvds_setting_information
516 *plvds_setting_info,
517 struct lvds_chip_information *plvds_chip_info)
518{
519 if (VT1636_LVDS == plvds_chip_info->lvds_chip_name) {
520 switch (viaparinfo->chip_info->gfx_chip_name) {
521 case UNICHROME_CX700:
522 viafb_vt1636_patch_skew_on_vt3324(plvds_setting_info,
523 plvds_chip_info);
524 break;
525 }
526 }
527}
528static void lcd_patch_skew(struct lvds_setting_information
529 *plvds_setting_info, struct lvds_chip_information *plvds_chip_info)
530{
531 DEBUG_MSG(KERN_INFO "lcd_patch_skew\n");
532 switch (plvds_chip_info->output_interface) {
533 case INTERFACE_DVP0:
534 lcd_patch_skew_dvp0(plvds_setting_info, plvds_chip_info);
535 break;
536 case INTERFACE_DVP1:
537 lcd_patch_skew_dvp1(plvds_setting_info, plvds_chip_info);
538 break;
539 case INTERFACE_DFP_LOW:
540 if (UNICHROME_P4M900 == viaparinfo->chip_info->gfx_chip_name) {
541 viafb_write_reg_mask(CR99, VIACR, 0x08,
542 BIT0 + BIT1 + BIT2 + BIT3);
543 }
544 break;
545 }
546}
547
548/* LCD Set Mode */
Florian Tobias Schandinat4e5527c2012-02-12 20:08:41 +0000549void viafb_lcd_set_mode(const struct fb_var_screeninfo *var, u16 cxres,
550 u16 cyres, struct lvds_setting_information *plvds_setting_info,
Florian Tobias Schandinatbfe7d5f2011-08-07 13:08:45 +0000551 struct lvds_chip_information *plvds_chip_info)
Joseph Chanac6c97e2008-10-15 22:03:25 -0700552{
Joseph Chanac6c97e2008-10-15 22:03:25 -0700553 int set_iga = plvds_setting_info->iga_path;
554 int mode_bpp = plvds_setting_info->bpp;
Florian Tobias Schandinat4e5527c2012-02-12 20:08:41 +0000555 int set_hres = cxres ? cxres : var->xres;
556 int set_vres = cyres ? cyres : var->yres;
Florian Tobias Schandinatdd73d682010-03-10 15:21:28 -0800557 int panel_hres = plvds_setting_info->lcd_panel_hres;
558 int panel_vres = plvds_setting_info->lcd_panel_vres;
Florian Tobias Schandinat1606f872011-03-23 13:49:32 +0000559 u32 clock;
Florian Tobias Schandinatf18e3e02011-05-22 23:30:48 +0000560 struct display_timing mode_crt_reg, panel_crt_reg, timing;
Florian Tobias Schandinatbfe7d5f2011-08-07 13:08:45 +0000561 struct crt_mode_table *mode_crt_table, *panel_crt_table;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700562
563 DEBUG_MSG(KERN_INFO "viafb_lcd_set_mode!!\n");
564 /* Get mode table */
Florian Tobias Schandinatbfe7d5f2011-08-07 13:08:45 +0000565 mode_crt_table = viafb_get_best_mode(set_hres, set_vres, 60);
Joseph Chanac6c97e2008-10-15 22:03:25 -0700566 mode_crt_reg = mode_crt_table->crtc;
567 /* Get panel table Pointer */
Florian Tobias Schandinatbfe7d5f2011-08-07 13:08:45 +0000568 panel_crt_table = viafb_get_best_mode(panel_hres, panel_vres, 60);
Joseph Chanac6c97e2008-10-15 22:03:25 -0700569 panel_crt_reg = panel_crt_table->crtc;
570 DEBUG_MSG(KERN_INFO "bellow viafb_lcd_set_mode!!\n");
Joseph Chanac6c97e2008-10-15 22:03:25 -0700571 if (VT1636_LVDS == plvds_chip_info->lvds_chip_name)
572 viafb_init_lvds_vt1636(plvds_setting_info, plvds_chip_info);
Florian Tobias Schandinatfd3cc692011-03-11 00:04:01 +0000573 clock = panel_crt_reg.hor_total * panel_crt_reg.ver_total
574 * panel_crt_table->refresh_rate;
575 plvds_setting_info->vclk = clock;
Florian Tobias Schandinatf18e3e02011-05-22 23:30:48 +0000576
577 if (set_iga == IGA2 && (set_hres < panel_hres || set_vres < panel_vres)
578 && plvds_setting_info->display_method == LCD_EXPANDSION) {
579 timing = panel_crt_reg;
580 load_lcd_scaling(set_hres, set_vres, panel_hres, panel_vres);
Joseph Chanac6c97e2008-10-15 22:03:25 -0700581 } else {
Florian Tobias Schandinatf18e3e02011-05-22 23:30:48 +0000582 timing = lcd_centering_timging(mode_crt_reg, panel_crt_reg);
583 if (set_iga == IGA2)
584 /* disable scaling */
585 via_write_reg_mask(VIACR, 0x79, 0x00,
Joseph Chanac6c97e2008-10-15 22:03:25 -0700586 BIT0 + BIT1 + BIT2);
Joseph Chanac6c97e2008-10-15 22:03:25 -0700587 }
588
Florian Tobias Schandinatf18e3e02011-05-22 23:30:48 +0000589 timing.hor_blank_end += timing.hor_blank_start;
590 timing.hor_sync_end += timing.hor_sync_start;
591 timing.ver_blank_end += timing.ver_blank_start;
592 timing.ver_sync_end += timing.ver_sync_start;
593 if (set_iga == IGA1)
594 via_set_primary_timing(&timing);
595 else if (set_iga == IGA2)
596 via_set_secondary_timing(&timing);
597
Florian Tobias Schandinat4bbac052010-03-10 15:21:36 -0800598 /* Fetch count for IGA2 only */
599 viafb_load_fetch_count_reg(set_hres, mode_bpp / 8, set_iga);
Joseph Chanac6c97e2008-10-15 22:03:25 -0700600
Florian Tobias Schandinat4bbac052010-03-10 15:21:36 -0800601 if ((viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266)
602 && (viaparinfo->chip_info->gfx_chip_name != UNICHROME_K400))
603 viafb_load_FIFO_reg(set_iga, set_hres, set_vres);
Joseph Chanac6c97e2008-10-15 22:03:25 -0700604
605 fill_lcd_format();
Florian Tobias Schandinat1606f872011-03-23 13:49:32 +0000606 viafb_set_vclock(clock, set_iga);
Joseph Chanac6c97e2008-10-15 22:03:25 -0700607 lcd_patch_skew(plvds_setting_info, plvds_chip_info);
608
609 /* If K8M800, enable LCD Prefetch Mode. */
610 if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800)
611 || (UNICHROME_K8M890 == viaparinfo->chip_info->gfx_chip_name))
612 viafb_write_reg_mask(CR6A, VIACR, 0x01, BIT0);
613
Joseph Chanac6c97e2008-10-15 22:03:25 -0700614 /* Patch for non 32bit alignment mode */
Florian Tobias Schandinat4e5527c2012-02-12 20:08:41 +0000615 via_pitch_alignment_patch_lcd(plvds_setting_info, plvds_chip_info,
616 set_hres);
Joseph Chanac6c97e2008-10-15 22:03:25 -0700617}
618
619static void integrated_lvds_disable(struct lvds_setting_information
620 *plvds_setting_info,
621 struct lvds_chip_information *plvds_chip_info)
622{
623 bool turn_off_first_powersequence = false;
624 bool turn_off_second_powersequence = false;
625 if (INTERFACE_LVDS0LVDS1 == plvds_chip_info->output_interface)
626 turn_off_first_powersequence = true;
627 if (INTERFACE_LVDS0 == plvds_chip_info->output_interface)
628 turn_off_first_powersequence = true;
629 if (INTERFACE_LVDS1 == plvds_chip_info->output_interface)
630 turn_off_second_powersequence = true;
631 if (turn_off_second_powersequence) {
632 /* Use second power sequence control: */
633
634 /* Turn off power sequence. */
635 viafb_write_reg_mask(CRD4, VIACR, 0, BIT1);
636
637 /* Turn off back light. */
638 viafb_write_reg_mask(CRD3, VIACR, 0xC0, BIT6 + BIT7);
639 }
640 if (turn_off_first_powersequence) {
641 /* Use first power sequence control: */
642
643 /* Turn off power sequence. */
644 viafb_write_reg_mask(CR6A, VIACR, 0, BIT3);
645
646 /* Turn off back light. */
647 viafb_write_reg_mask(CR91, VIACR, 0xC0, BIT6 + BIT7);
648 }
649
Joseph Chanac6c97e2008-10-15 22:03:25 -0700650 /* Power off LVDS channel. */
651 switch (plvds_chip_info->output_interface) {
652 case INTERFACE_LVDS0:
653 {
654 viafb_write_reg_mask(CRD2, VIACR, 0x80, BIT7);
655 break;
656 }
657
658 case INTERFACE_LVDS1:
659 {
660 viafb_write_reg_mask(CRD2, VIACR, 0x40, BIT6);
661 break;
662 }
663
664 case INTERFACE_LVDS0LVDS1:
665 {
666 viafb_write_reg_mask(CRD2, VIACR, 0xC0, BIT6 + BIT7);
667 break;
668 }
669 }
670}
671
672static void integrated_lvds_enable(struct lvds_setting_information
673 *plvds_setting_info,
674 struct lvds_chip_information *plvds_chip_info)
675{
Joseph Chanac6c97e2008-10-15 22:03:25 -0700676 DEBUG_MSG(KERN_INFO "integrated_lvds_enable, out_interface:%d\n",
677 plvds_chip_info->output_interface);
678 if (plvds_setting_info->lcd_mode == LCD_SPWG)
679 viafb_write_reg_mask(CRD2, VIACR, 0x00, BIT0 + BIT1);
Harald Weltee6bf0d22009-12-15 16:46:44 -0800680 else
Joseph Chanac6c97e2008-10-15 22:03:25 -0700681 viafb_write_reg_mask(CRD2, VIACR, 0x03, BIT0 + BIT1);
Joseph Chanac6c97e2008-10-15 22:03:25 -0700682
Harald Weltee6bf0d22009-12-15 16:46:44 -0800683 switch (plvds_chip_info->output_interface) {
684 case INTERFACE_LVDS0LVDS1:
685 case INTERFACE_LVDS0:
Joseph Chanac6c97e2008-10-15 22:03:25 -0700686 /* Use first power sequence control: */
Joseph Chanac6c97e2008-10-15 22:03:25 -0700687 /* Use hardware control power sequence. */
688 viafb_write_reg_mask(CR91, VIACR, 0, BIT0);
Joseph Chanac6c97e2008-10-15 22:03:25 -0700689 /* Turn on back light. */
690 viafb_write_reg_mask(CR91, VIACR, 0, BIT6 + BIT7);
Joseph Chanac6c97e2008-10-15 22:03:25 -0700691 /* Turn on hardware power sequence. */
692 viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3);
Harald Weltee6bf0d22009-12-15 16:46:44 -0800693 break;
694 case INTERFACE_LVDS1:
695 /* Use second power sequence control: */
696 /* Use hardware control power sequence. */
697 viafb_write_reg_mask(CRD3, VIACR, 0, BIT0);
698 /* Turn on back light. */
699 viafb_write_reg_mask(CRD3, VIACR, 0, BIT6 + BIT7);
700 /* Turn on hardware power sequence. */
701 viafb_write_reg_mask(CRD4, VIACR, 0x02, BIT1);
702 break;
Joseph Chanac6c97e2008-10-15 22:03:25 -0700703 }
704
Joseph Chanac6c97e2008-10-15 22:03:25 -0700705 /* Power on LVDS channel. */
706 switch (plvds_chip_info->output_interface) {
707 case INTERFACE_LVDS0:
708 {
709 viafb_write_reg_mask(CRD2, VIACR, 0, BIT7);
710 break;
711 }
712
713 case INTERFACE_LVDS1:
714 {
715 viafb_write_reg_mask(CRD2, VIACR, 0, BIT6);
716 break;
717 }
718
719 case INTERFACE_LVDS0LVDS1:
720 {
721 viafb_write_reg_mask(CRD2, VIACR, 0, BIT6 + BIT7);
722 break;
723 }
724 }
725}
726
727void viafb_lcd_disable(void)
728{
729
730 if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
731 lcd_powersequence_off();
732 /* DI1 pad off */
733 viafb_write_reg_mask(SR1E, VIASR, 0x00, 0x30);
734 } else if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) {
735 if (viafb_LCD2_ON
736 && (INTEGRATED_LVDS ==
737 viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name))
738 integrated_lvds_disable(viaparinfo->lvds_setting_info,
739 &viaparinfo->chip_info->lvds_chip_info2);
740 if (INTEGRATED_LVDS ==
741 viaparinfo->chip_info->lvds_chip_info.lvds_chip_name)
742 integrated_lvds_disable(viaparinfo->lvds_setting_info,
743 &viaparinfo->chip_info->lvds_chip_info);
744 if (VT1636_LVDS == viaparinfo->chip_info->
745 lvds_chip_info.lvds_chip_name)
746 viafb_disable_lvds_vt1636(viaparinfo->lvds_setting_info,
747 &viaparinfo->chip_info->lvds_chip_info);
748 } else if (VT1636_LVDS ==
749 viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
750 viafb_disable_lvds_vt1636(viaparinfo->lvds_setting_info,
751 &viaparinfo->chip_info->lvds_chip_info);
752 } else {
Joseph Chanac6c97e2008-10-15 22:03:25 -0700753 /* Backlight off */
754 viafb_write_reg_mask(SR3D, VIASR, 0x00, 0x20);
755 /* 24 bit DI data paht off */
756 viafb_write_reg_mask(CR91, VIACR, 0x80, 0x80);
Joseph Chanac6c97e2008-10-15 22:03:25 -0700757 }
758
759 /* Disable expansion bit */
760 viafb_write_reg_mask(CR79, VIACR, 0x00, 0x01);
Joseph Chanac6c97e2008-10-15 22:03:25 -0700761 /* Simultaneout disabled */
762 viafb_write_reg_mask(CR6B, VIACR, 0x00, 0x08);
Joseph Chanac6c97e2008-10-15 22:03:25 -0700763}
764
Florian Tobias Schandinatcd7e9102010-08-11 22:22:54 +0000765static void set_lcd_output_path(int set_iga, int output_interface)
766{
767 switch (output_interface) {
768 case INTERFACE_DFP:
769 if ((UNICHROME_K8M890 == viaparinfo->chip_info->gfx_chip_name)
770 || (UNICHROME_P4M890 ==
771 viaparinfo->chip_info->gfx_chip_name))
772 viafb_write_reg_mask(CR97, VIACR, 0x84,
773 BIT7 + BIT2 + BIT1 + BIT0);
774 case INTERFACE_DVP0:
775 case INTERFACE_DVP1:
776 case INTERFACE_DFP_HIGH:
777 case INTERFACE_DFP_LOW:
778 if (set_iga == IGA2)
779 viafb_write_reg(CR91, VIACR, 0x00);
780 break;
781 }
782}
783
Joseph Chanac6c97e2008-10-15 22:03:25 -0700784void viafb_lcd_enable(void)
785{
Florian Tobias Schandinatcd7e9102010-08-11 22:22:54 +0000786 viafb_write_reg_mask(CR6B, VIACR, 0x00, BIT3);
787 viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3);
788 set_lcd_output_path(viaparinfo->lvds_setting_info->iga_path,
789 viaparinfo->chip_info->lvds_chip_info.output_interface);
790 if (viafb_LCD2_ON)
791 set_lcd_output_path(viaparinfo->lvds_setting_info2->iga_path,
792 viaparinfo->chip_info->
793 lvds_chip_info2.output_interface);
794
Joseph Chanac6c97e2008-10-15 22:03:25 -0700795 if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
796 /* DI1 pad on */
797 viafb_write_reg_mask(SR1E, VIASR, 0x30, 0x30);
798 lcd_powersequence_on();
799 } else if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) {
800 if (viafb_LCD2_ON && (INTEGRATED_LVDS ==
801 viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name))
802 integrated_lvds_enable(viaparinfo->lvds_setting_info2, \
803 &viaparinfo->chip_info->lvds_chip_info2);
804 if (INTEGRATED_LVDS ==
805 viaparinfo->chip_info->lvds_chip_info.lvds_chip_name)
806 integrated_lvds_enable(viaparinfo->lvds_setting_info,
807 &viaparinfo->chip_info->lvds_chip_info);
808 if (VT1636_LVDS == viaparinfo->chip_info->
809 lvds_chip_info.lvds_chip_name)
810 viafb_enable_lvds_vt1636(viaparinfo->
811 lvds_setting_info, &viaparinfo->chip_info->
812 lvds_chip_info);
813 } else if (VT1636_LVDS ==
814 viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
815 viafb_enable_lvds_vt1636(viaparinfo->lvds_setting_info,
816 &viaparinfo->chip_info->lvds_chip_info);
817 } else {
Joseph Chanac6c97e2008-10-15 22:03:25 -0700818 /* Backlight on */
819 viafb_write_reg_mask(SR3D, VIASR, 0x20, 0x20);
820 /* 24 bit DI data paht on */
821 viafb_write_reg_mask(CR91, VIACR, 0x00, 0x80);
Joseph Chanac6c97e2008-10-15 22:03:25 -0700822 /* LCD enabled */
823 viafb_write_reg_mask(CR6A, VIACR, 0x48, 0x48);
824 }
Joseph Chanac6c97e2008-10-15 22:03:25 -0700825}
826
827static void lcd_powersequence_off(void)
828{
829 int i, mask, data;
830
831 /* Software control power sequence */
832 viafb_write_reg_mask(CR91, VIACR, 0x11, 0x11);
833
834 for (i = 0; i < 3; i++) {
835 mask = PowerSequenceOff[0][i];
836 data = PowerSequenceOff[1][i] & mask;
837 viafb_write_reg_mask(CR91, VIACR, (u8) data, (u8) mask);
838 udelay(PowerSequenceOff[2][i]);
839 }
840
841 /* Disable LCD */
842 viafb_write_reg_mask(CR6A, VIACR, 0x00, 0x08);
843}
844
845static void lcd_powersequence_on(void)
846{
847 int i, mask, data;
848
849 /* Software control power sequence */
850 viafb_write_reg_mask(CR91, VIACR, 0x11, 0x11);
851
852 /* Enable LCD */
853 viafb_write_reg_mask(CR6A, VIACR, 0x08, 0x08);
854
855 for (i = 0; i < 3; i++) {
856 mask = PowerSequenceOn[0][i];
857 data = PowerSequenceOn[1][i] & mask;
858 viafb_write_reg_mask(CR91, VIACR, (u8) data, (u8) mask);
859 udelay(PowerSequenceOn[2][i]);
860 }
861
862 udelay(1);
863}
864
865static void fill_lcd_format(void)
866{
867 u8 bdithering = 0, bdual = 0;
868
869 if (viaparinfo->lvds_setting_info->device_lcd_dualedge)
870 bdual = BIT4;
871 if (viaparinfo->lvds_setting_info->LCDDithering)
872 bdithering = BIT0;
873 /* Dual & Dithering */
874 viafb_write_reg_mask(CR88, VIACR, (bdithering | bdual), BIT4 + BIT0);
875}
876
877static void check_diport_of_integrated_lvds(
878 struct lvds_chip_information *plvds_chip_info,
879 struct lvds_setting_information
880 *plvds_setting_info)
881{
882 /* Determine LCD DI Port by hardware layout. */
883 switch (viafb_display_hardware_layout) {
884 case HW_LAYOUT_LCD_ONLY:
885 {
886 if (plvds_setting_info->device_lcd_dualedge) {
887 plvds_chip_info->output_interface =
888 INTERFACE_LVDS0LVDS1;
889 } else {
890 plvds_chip_info->output_interface =
891 INTERFACE_LVDS0;
892 }
893
894 break;
895 }
896
897 case HW_LAYOUT_DVI_ONLY:
898 {
899 plvds_chip_info->output_interface = INTERFACE_NONE;
900 break;
901 }
902
903 case HW_LAYOUT_LCD1_LCD2:
904 case HW_LAYOUT_LCD_EXTERNAL_LCD2:
905 {
906 plvds_chip_info->output_interface =
907 INTERFACE_LVDS0LVDS1;
908 break;
909 }
910
911 case HW_LAYOUT_LCD_DVI:
912 {
913 plvds_chip_info->output_interface = INTERFACE_LVDS1;
914 break;
915 }
916
917 default:
918 {
919 plvds_chip_info->output_interface = INTERFACE_LVDS1;
920 break;
921 }
922 }
923
924 DEBUG_MSG(KERN_INFO
925 "Display Hardware Layout: 0x%x, LCD DI Port: 0x%x\n",
926 viafb_display_hardware_layout,
927 plvds_chip_info->output_interface);
928}
929
Florian Tobias Schandinatf4ab2f7a2010-08-09 01:34:27 +0000930void __devinit viafb_init_lvds_output_interface(struct lvds_chip_information
Joseph Chanac6c97e2008-10-15 22:03:25 -0700931 *plvds_chip_info,
932 struct lvds_setting_information
933 *plvds_setting_info)
934{
935 if (INTERFACE_NONE != plvds_chip_info->output_interface) {
936 /*Do nothing, lcd port is specified by module parameter */
937 return;
938 }
939
940 switch (plvds_chip_info->lvds_chip_name) {
941
942 case VT1636_LVDS:
943 switch (viaparinfo->chip_info->gfx_chip_name) {
944 case UNICHROME_CX700:
945 plvds_chip_info->output_interface = INTERFACE_DVP1;
946 break;
947 case UNICHROME_CN700:
948 plvds_chip_info->output_interface = INTERFACE_DFP_LOW;
949 break;
950 default:
951 plvds_chip_info->output_interface = INTERFACE_DVP0;
952 break;
953 }
954 break;
955
956 case INTEGRATED_LVDS:
957 check_diport_of_integrated_lvds(plvds_chip_info,
958 plvds_setting_info);
959 break;
960
961 default:
962 switch (viaparinfo->chip_info->gfx_chip_name) {
963 case UNICHROME_K8M890:
964 case UNICHROME_P4M900:
965 case UNICHROME_P4M890:
966 plvds_chip_info->output_interface = INTERFACE_DFP_LOW;
967 break;
968 default:
969 plvds_chip_info->output_interface = INTERFACE_DFP;
970 break;
971 }
972 break;
973 }
974}
975
976static struct display_timing lcd_centering_timging(struct display_timing
977 mode_crt_reg,
978 struct display_timing panel_crt_reg)
979{
980 struct display_timing crt_reg;
981
982 crt_reg.hor_total = panel_crt_reg.hor_total;
983 crt_reg.hor_addr = mode_crt_reg.hor_addr;
984 crt_reg.hor_blank_start =
985 (panel_crt_reg.hor_addr - mode_crt_reg.hor_addr) / 2 +
986 crt_reg.hor_addr;
987 crt_reg.hor_blank_end = panel_crt_reg.hor_blank_end;
988 crt_reg.hor_sync_start =
989 (panel_crt_reg.hor_sync_start -
990 panel_crt_reg.hor_blank_start) + crt_reg.hor_blank_start;
991 crt_reg.hor_sync_end = panel_crt_reg.hor_sync_end;
992
993 crt_reg.ver_total = panel_crt_reg.ver_total;
994 crt_reg.ver_addr = mode_crt_reg.ver_addr;
995 crt_reg.ver_blank_start =
996 (panel_crt_reg.ver_addr - mode_crt_reg.ver_addr) / 2 +
997 crt_reg.ver_addr;
998 crt_reg.ver_blank_end = panel_crt_reg.ver_blank_end;
999 crt_reg.ver_sync_start =
1000 (panel_crt_reg.ver_sync_start -
1001 panel_crt_reg.ver_blank_start) + crt_reg.ver_blank_start;
1002 crt_reg.ver_sync_end = panel_crt_reg.ver_sync_end;
1003
1004 return crt_reg;
1005}
1006
Joseph Chanac6c97e2008-10-15 22:03:25 -07001007bool viafb_lcd_get_mobile_state(bool *mobile)
1008{
Stephen Hemmingerb65d6042011-03-03 09:59:01 -08001009 unsigned char __iomem *romptr, *tableptr, *biosptr;
Joseph Chanac6c97e2008-10-15 22:03:25 -07001010 u8 core_base;
Joseph Chanac6c97e2008-10-15 22:03:25 -07001011 /* Rom address */
Stephen Hemmingerb65d6042011-03-03 09:59:01 -08001012 const u32 romaddr = 0x000C0000;
1013 u16 start_pattern;
Joseph Chanac6c97e2008-10-15 22:03:25 -07001014
1015 biosptr = ioremap(romaddr, 0x10000);
Stephen Hemmingerb65d6042011-03-03 09:59:01 -08001016 start_pattern = readw(biosptr);
Joseph Chanac6c97e2008-10-15 22:03:25 -07001017
Joseph Chanac6c97e2008-10-15 22:03:25 -07001018 /* Compare pattern */
1019 if (start_pattern == 0xAA55) {
1020 /* Get the start of Table */
1021 /* 0x1B means BIOS offset position */
1022 romptr = biosptr + 0x1B;
Stephen Hemmingerb65d6042011-03-03 09:59:01 -08001023 tableptr = biosptr + readw(romptr);
Joseph Chanac6c97e2008-10-15 22:03:25 -07001024
1025 /* Get the start of biosver structure */
1026 /* 18 means BIOS version position. */
1027 romptr = tableptr + 18;
Stephen Hemmingerb65d6042011-03-03 09:59:01 -08001028 romptr = biosptr + readw(romptr);
Joseph Chanac6c97e2008-10-15 22:03:25 -07001029
1030 /* The offset should be 44, but the
1031 actual image is less three char. */
1032 /* pRom += 44; */
1033 romptr += 41;
1034
Stephen Hemmingerb65d6042011-03-03 09:59:01 -08001035 core_base = readb(romptr);
Joseph Chanac6c97e2008-10-15 22:03:25 -07001036
1037 if (core_base & 0x8)
1038 *mobile = false;
1039 else
1040 *mobile = true;
1041 /* release memory */
1042 iounmap(biosptr);
1043
1044 return true;
1045 } else {
1046 iounmap(biosptr);
1047 return false;
1048 }
1049}