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(index: 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(panel_id: 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(i2c_adapter: 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(i2c_adapter: 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(adap: VIA_PORT_2C, |
330 | slave_addr: (u8) viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr, |
331 | index: (u8) index, pdata: &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(timing_value: 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(timing_value: 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(timing_value: 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(timing_value: 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(hres: panel_hres, vres: panel_vres, refresh: 60); |
545 | viafb_fill_var_timing_info(var: &panel_var, mode: 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(var: &panel_var, cxres: panel_hres, cyres: panel_vres); |
555 | load_lcd_scaling(set_hres, set_vres, panel_hres, panel_vres); |
556 | } else { |
557 | timing = var_to_timing(var: &panel_var, cxres: set_hres, cyres: set_vres); |
558 | if (set_iga == IGA2) |
559 | /* disable scaling */ |
560 | via_write_reg_mask(VIACR, index: 0x79, data: 0x00, |
561 | BIT0 + BIT1 + BIT2); |
562 | } |
563 | |
564 | if (set_iga == IGA1) |
565 | via_set_primary_timing(timing: &timing); |
566 | else if (set_iga == IGA2) |
567 | via_set_secondary_timing(timing: &timing); |
568 | |
569 | /* Fetch count for IGA2 only */ |
570 | viafb_load_fetch_count_reg(h_addr: set_hres, bpp_byte: 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, hor_active: set_hres, ver_active: set_vres); |
575 | |
576 | fill_lcd_format(); |
577 | viafb_set_vclock(CLK: 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(iga_path: plvds_setting_info->iga_path, hres: set_hres, |
587 | bpp: 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(plvds_setting_info: viaparinfo->lvds_setting_info, |
710 | plvds_chip_info: &viaparinfo->chip_info->lvds_chip_info2); |
711 | if (INTEGRATED_LVDS == |
712 | viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) |
713 | integrated_lvds_disable(plvds_setting_info: viaparinfo->lvds_setting_info, |
714 | plvds_chip_info: &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(plvds_setting_info: viaparinfo->lvds_setting_info, |
718 | plvds_chip_info: &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(plvds_setting_info: viaparinfo->lvds_setting_info, |
722 | plvds_chip_info: &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(set_iga: viaparinfo->lvds_setting_info->iga_path, |
761 | output_interface: viaparinfo->chip_info->lvds_chip_info.output_interface); |
762 | if (viafb_LCD2_ON) |
763 | set_lcd_output_path(set_iga: viaparinfo->lvds_setting_info2->iga_path, |
764 | output_interface: 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(plvds_setting_info: viaparinfo->lvds_setting_info2, \ |
775 | plvds_chip_info: &viaparinfo->chip_info->lvds_chip_info2); |
776 | if (INTEGRATED_LVDS == |
777 | viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) |
778 | integrated_lvds_enable(plvds_setting_info: viaparinfo->lvds_setting_info, |
779 | plvds_chip_info: &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(plvds_setting_info: viaparinfo-> |
783 | lvds_setting_info, plvds_chip_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(plvds_setting_info: viaparinfo->lvds_setting_info, |
788 | plvds_chip_info: &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(offset: romaddr, size: 0x10000); |
957 | start_pattern = readw(addr: 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(addr: romptr); |
965 | |
966 | /* Get the start of biosver structure */ |
967 | /* 18 means BIOS version position. */ |
968 | romptr = tableptr + 18; |
969 | romptr = biosptr + readw(addr: 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(addr: romptr); |
977 | |
978 | if (core_base & 0x8) |
979 | *mobile = false; |
980 | else |
981 | *mobile = true; |
982 | /* release memory */ |
983 | iounmap(addr: biosptr); |
984 | |
985 | return true; |
986 | } else { |
987 | iounmap(addr: biosptr); |
988 | return false; |
989 | } |
990 | } |
991 | |