1/*
2 * Copyright © 2007 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 *    Zhenyu Wang <zhenyu.z.wang@intel.com>
25 *
26 */
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include "i830.h"
32
33#define SUBSYS_ANY (~0)
34
35#define DMIID_DIR "/sys/class/dmi/id/"
36#define DMIID_FILE(x) (DMIID_DIR # x)
37
38typedef struct {
39    int chipType;
40    int subsysVendor;
41    int subsysCard;
42    void (*hook)(I830Ptr);
43} i830_quirk, *i830_quirk_ptr;
44
45enum i830_dmi_data_t {
46    bios_vendor,
47    bios_version,
48    bios_date,
49    sys_vendor,
50    product_name,
51    product_version,
52    product_serial,
53    product_uuid,
54    board_vendor,
55    board_name,
56    board_version,
57    board_serial,
58    board_asset_tag,
59    chassis_vendor,
60    chassis_type,
61    chassis_version,
62    chassis_serial,
63    chassis_asset_tag,
64    dmi_data_max,
65};
66
67static char *i830_dmi_data[dmi_data_max];
68
69#define I830_DMI_FIELD_FUNC(field) \
70static void i830_dmi_store_##field(void) \
71{\
72    FILE *f = NULL;\
73    int ret;\
74    f = fopen(DMIID_FILE(field), "r");\
75    if (f == NULL) {\
76	xfree(i830_dmi_data[field]); i830_dmi_data[field] = NULL;\
77	return;\
78    }\
79    ret = fread(i830_dmi_data[field], 64, 1, f);	\
80    fclose(f);\
81}
82
83I830_DMI_FIELD_FUNC(bios_vendor);
84I830_DMI_FIELD_FUNC(bios_version);
85I830_DMI_FIELD_FUNC(bios_date);
86I830_DMI_FIELD_FUNC(sys_vendor);
87I830_DMI_FIELD_FUNC(product_name);
88I830_DMI_FIELD_FUNC(product_version);
89I830_DMI_FIELD_FUNC(product_serial);
90I830_DMI_FIELD_FUNC(product_uuid);
91I830_DMI_FIELD_FUNC(board_vendor);
92I830_DMI_FIELD_FUNC(board_name);
93I830_DMI_FIELD_FUNC(board_version);
94I830_DMI_FIELD_FUNC(board_serial);
95I830_DMI_FIELD_FUNC(board_asset_tag);
96I830_DMI_FIELD_FUNC(chassis_vendor);
97I830_DMI_FIELD_FUNC(chassis_type);
98I830_DMI_FIELD_FUNC(chassis_version);
99I830_DMI_FIELD_FUNC(chassis_serial);
100I830_DMI_FIELD_FUNC(chassis_asset_tag);
101
102static void i830_dmi_scan(void)
103{
104    int i;
105
106    for (i = 0; i < dmi_data_max; i++) {
107	i830_dmi_data[i] = xcalloc(64, sizeof(char));
108	if (!i830_dmi_data[i]) {
109	    int j;
110	    for (j = 0; j < i; j++) {
111		xfree(i830_dmi_data[j]);
112		i830_dmi_data[i] = NULL;
113	    }
114	    return;
115	}
116    }
117
118    i830_dmi_store_bios_vendor();
119    i830_dmi_store_bios_version();
120    i830_dmi_store_bios_date();
121    i830_dmi_store_sys_vendor();
122    i830_dmi_store_product_name();
123    i830_dmi_store_product_version();
124    i830_dmi_store_product_serial();
125    i830_dmi_store_product_uuid();
126    i830_dmi_store_board_vendor();
127    i830_dmi_store_board_name();
128    i830_dmi_store_board_version();
129    i830_dmi_store_board_serial();
130    i830_dmi_store_board_asset_tag();
131    i830_dmi_store_chassis_vendor();
132    i830_dmi_store_chassis_type();
133    i830_dmi_store_chassis_version();
134    i830_dmi_store_chassis_serial();
135    i830_dmi_store_chassis_asset_tag();
136}
137
138#define DMIID_DUMP(field) \
139    ErrorF("\t" # field ": %s", i830_dmi_data[field] ?\
140	    i830_dmi_data[field] : "unknown")
141
142static void i830_dmi_dump(void)
143{
144    ErrorF("i830_dmi_dump:\n");
145    DMIID_DUMP(bios_vendor);
146    DMIID_DUMP(bios_version);
147    DMIID_DUMP(bios_date);
148    DMIID_DUMP(sys_vendor);
149    DMIID_DUMP(product_name);
150    DMIID_DUMP(product_version);
151    DMIID_DUMP(product_serial);
152    DMIID_DUMP(product_uuid);
153    DMIID_DUMP(board_vendor);
154    DMIID_DUMP(board_name);
155    DMIID_DUMP(board_version);
156    DMIID_DUMP(board_serial);
157    DMIID_DUMP(board_asset_tag);
158    DMIID_DUMP(chassis_vendor);
159    DMIID_DUMP(chassis_type);
160    DMIID_DUMP(chassis_version);
161    DMIID_DUMP(chassis_serial);
162    DMIID_DUMP(chassis_asset_tag);
163}
164
165/*
166 * Old chips have undocumented panel fitting registers.  Some of them actually
167 * work; this quirk indicates that.
168 */
169static void quirk_pfit_safe (I830Ptr pI830)
170{
171    pI830->quirk_flag |= QUIRK_PFIT_SAFE;
172}
173
174/*
175 * Some machines hose the display regs regardless of the ACPI DOS
176 * setting, so we need to reset modes at ACPI event time.
177 */
178static void quirk_reset_modes (I830Ptr pI830)
179{
180    pI830->quirk_flag |= QUIRK_RESET_MODES;
181}
182
183static void quirk_pipea_force (I830Ptr pI830)
184{
185    pI830->quirk_flag |= QUIRK_PIPEA_FORCE;
186}
187
188static void quirk_ignore_tv (I830Ptr pI830)
189{
190    pI830->quirk_flag |= QUIRK_IGNORE_TV;
191}
192
193static void quirk_ignore_lvds (I830Ptr pI830)
194{
195    pI830->quirk_flag |= QUIRK_IGNORE_LVDS;
196}
197
198static void quirk_ignore_crt (I830Ptr pI830)
199{
200    pI830->quirk_flag |= QUIRK_IGNORE_CRT;
201}
202
203static void quirk_mac_mini (I830Ptr pI830)
204{
205    pI830->quirk_flag |= QUIRK_IGNORE_MACMINI_LVDS;
206}
207
208static void quirk_lenovo_tv_dmi (I830Ptr pI830)
209{
210    /* X60, X60s has no TV output.
211     * Z61 has S-video TV output.
212     * And they have same subsys ids...
213     *
214     * http://www-307.ibm.com/pc/support/site.wss/MIGR-45120.html
215     * http://www.thinkwiki.org/wiki/List_of_DMI_IDs
216     */
217    if (!i830_dmi_data[bios_version]) {
218	ErrorF("Failed to load DMI info, X60 TV quirk not applied.\n");
219	return;
220    }
221    if (!strncmp(i830_dmi_data[bios_version], "7B", 2) || /* X60, X60s */
222	    !strncmp(i830_dmi_data[bios_version], "7E", 2)) /* R60e */
223	pI830->quirk_flag |= QUIRK_IGNORE_TV;
224}
225
226static void quirk_msi_lvds_dmi (I830Ptr pI830)
227{
228   /* MSI IM-945GSE-A has no TV output, nor a LVDS connection.
229    */
230   if (!i830_dmi_data[board_name]) {
231       ErrorF("Failed to load DMI info, MSI LVDS quirk not applied.\n");
232       return;
233   }
234   if (!strncmp(i830_dmi_data[board_name],"A9830IMS",8)) {
235       pI830->quirk_flag |= QUIRK_IGNORE_LVDS;
236       pI830->quirk_flag |= QUIRK_IGNORE_TV;
237   }
238}
239
240static void quirk_ibase_lvds (I830Ptr pI830)
241{
242   if (!i830_dmi_data[board_name]) {
243       ErrorF("Failed to load DMI info, iBase LVDS quirk not applied.\n");
244       return;
245   }
246   if (!strncmp(i830_dmi_data[board_name], "i855-W83627HF", 13)) {
247       pI830->quirk_flag |= QUIRK_IGNORE_LVDS;
248   }
249}
250
251static void quirk_ivch_dvob (I830Ptr pI830)
252{
253	pI830->quirk_flag |= QUIRK_IVCH_NEED_DVOB;
254}
255
256/* For broken hw/bios for incorrect acpi _LID state that
257   can't be fixed with customed DSDT or other way */
258static void quirk_broken_acpi_lid (I830Ptr pI830)
259{
260	pI830->quirk_flag |= QUIRK_BROKEN_ACPI_LID;
261}
262
263/* keep this list sorted by OEM, then by chip ID */
264static i830_quirk i830_quirk_list[] = {
265    /* Aopen mini pc */
266    { PCI_CHIP_I915_GM, 0xa0a0, SUBSYS_ANY, quirk_ignore_lvds },
267    { PCI_CHIP_I945_GM, 0xa0a0, SUBSYS_ANY, quirk_ignore_lvds },
268    { PCI_CHIP_I965_GM, 0xa0a0, SUBSYS_ANY, quirk_ignore_lvds },
269    { PCI_CHIP_GM45_GM, 0xa0a0, SUBSYS_ANY, quirk_ignore_lvds },
270
271    { PCI_CHIP_I965_GM, 0x8086, 0x1999, quirk_ignore_lvds },
272
273    /* Apple Mac mini has no lvds, but macbook pro does */
274    { PCI_CHIP_I945_GM, 0x8086, 0x7270, quirk_mac_mini },
275
276    /* Transtec Senyo 610 mini pc */
277    { PCI_CHIP_I965_GM, 0x1509, 0x2f15, quirk_ignore_lvds },
278
279    /* Clevo M720R has no tv output */
280    { PCI_CHIP_I965_GM, 0x1558, 0x0721, quirk_ignore_tv },
281
282    /* Dell Latitude X1 */
283    { PCI_CHIP_I915_GM, 0x1028, 0x01a3, quirk_ignore_tv },
284    /* Dell Latitude X1 / D630 (LP: #197740) */
285    { PCI_CHIP_I915_GM, 0x1028, 0x01f9, quirk_ignore_tv },
286    /* Dell XPS 1330 */
287    { PCI_CHIP_I965_GM, 0x1028, 0x0209, quirk_ignore_tv },
288    /* Dell Inspiron 1535 */
289    { PCI_CHIP_I965_GM, 0x1028, 0x0254, quirk_ignore_tv },
290    /* Dell Inspiron 1735 */
291    { PCI_CHIP_I965_GM, 0x1028, 0x0256, quirk_ignore_tv },
292    /* Dell Inspiron 1318 */
293    { PCI_CHIP_I965_GM, 0x1028, 0x0286, quirk_ignore_tv },
294    /* Dell Vostro A840 (LP: #235155) */
295    { PCI_CHIP_I965_GM, 0x1028, 0x0298, quirk_ignore_tv },
296    /* Dell Studio Hybrid */
297    { PCI_CHIP_I965_GM, 0x1028, 0x0279, quirk_ignore_lvds },
298
299    /* Lenovo Napa TV (use dmi)*/
300    { PCI_CHIP_I945_GM, 0x17aa, SUBSYS_ANY, quirk_lenovo_tv_dmi },
301    /* Lenovo 3000 v200 */
302    { PCI_CHIP_I965_GM, 0x17aa, 0x3c18, quirk_ignore_tv },
303
304    /* MSI IM-945GSE-A has no LVDS or TV (use dmi) */
305    { PCI_CHIP_I945_GME, 0x8086, 0x27ae, quirk_msi_lvds_dmi },
306
307    /* Panasonic Toughbook CF-Y4 has no TV output */
308    { PCI_CHIP_I915_GM, 0x10f7, 0x8338, quirk_ignore_tv },
309    /* Panasonic Toughbook CF-Y7 has no TV output */
310    { PCI_CHIP_I965_GM, 0x10f7, 0x8338, quirk_ignore_tv },
311
312    /* Toshiba Satellite U300 has no TV output */
313    { PCI_CHIP_I965_GM, 0x1179, 0xff50, quirk_ignore_tv },
314    /* Toshiba i830M laptop (fix bug 11148) */
315    { PCI_CHIP_I830_M, 0x1179, 0xff00, quirk_ivch_dvob },
316
317    /* Motion Computing M1200 reported on irc */
318    { PCI_CHIP_I830_M, 0x14c0, 0x0012, quirk_ivch_dvob },
319
320    /* Samsung Q35 has no TV output */
321    { PCI_CHIP_I945_GM, 0x144d, 0xc504, quirk_ignore_tv },
322    /* Samsung Q45 has no TV output */
323    { PCI_CHIP_I965_GM, 0x144d, 0xc510, quirk_ignore_tv },
324
325    /* HP Compaq nx6110 has no TV output */
326    { PCI_CHIP_I915_GM, 0x103c, 0x099c, quirk_ignore_tv },
327    /* HP Compaq nx6310 has no TV output */
328    { PCI_CHIP_I945_GM, 0x103c, 0x30aa, quirk_ignore_tv },
329    /* HP Compaq 6730s has no TV output */
330    { PCI_CHIP_GM45_GM, 0x103c, 0x30e8, quirk_ignore_tv },
331    /* HP Compaq 2730p needs pipe A force quirk (LP: #291555) */
332    { PCI_CHIP_GM45_GM, 0x103c, 0x30eb, quirk_pipea_force },
333    /* HP Mini needs pipe A force quirk (LP: #322104) */
334    { PCI_CHIP_I945_GME,0x103c, 0x361a, quirk_pipea_force },
335    /* HP Mini 5101 needs pipe A force quirk */
336    { PCI_CHIP_I945_GME,0x103c, 0x3632, quirk_pipea_force },
337
338    /* Thinkpad R31 needs pipe A force quirk */
339    { PCI_CHIP_I830_M, 0x1014, 0x0505, quirk_pipea_force },
340    /* Dell Latitude D400 needs pipe A force quirk (LP: #228519) */
341    { PCI_CHIP_I855_GM, 0x1028, 0x0139, quirk_pipea_force },
342    /* Dell Latitude D500 needs pipe A force quirk */
343    { PCI_CHIP_I855_GM, 0x1028, 0x0152, quirk_pipea_force },
344    /* Dell Latitude D505 needs pipe A force quirk (LP: #235643) */
345    { PCI_CHIP_I855_GM, 0x1028, 0x0163, quirk_pipea_force },
346    /* Dell Latitude X300 needs pipe A force quirk */
347    { PCI_CHIP_I855_GM, 0x1028, 0x014f, quirk_pipea_force },
348    /* Dell Inspiron 510m needs pipe A force quirk */
349    { PCI_CHIP_I855_GM, 0x1028, 0x0164, quirk_pipea_force },
350    /* Toshiba Satellite A30 needs pipe A force quirk */
351    { PCI_CHIP_I855_GM, 0x1179, 0xff00 , quirk_pipea_force },
352    /* Toshiba Protege R-205, S-209 needs pipe A force quirk */
353    { PCI_CHIP_I915_GM, 0x1179, 0x0001, quirk_pipea_force },
354    /* Intel 855GM hardware (See LP: #216490) */
355    { PCI_CHIP_I855_GM, 0x1028, 0x00c8, quirk_pipea_force },
356    /* Intel 855GM hardware (See Novell Bugzilla #406123) */
357    { PCI_CHIP_I855_GM, 0x10cf, 0x1215, quirk_pipea_force },
358    /* HP Pavilion ze4944ea needs pipe A force quirk (See LP: #242389) */
359    { PCI_CHIP_I855_GM, 0x103c, 0x3084, quirk_pipea_force },
360
361    { PCI_CHIP_I855_GM, 0x161f, 0x2030, quirk_pfit_safe },
362
363    /* ThinkPad X30 needs pipe A force quirk (LP: #304614) */
364    { PCI_CHIP_I830_M,  0x1014, 0x0513, quirk_pipea_force },
365    /* ThinkPad X40 needs pipe A force quirk */
366    { PCI_CHIP_I855_GM, 0x1014, 0x0557, quirk_pipea_force },
367
368    /* ThinkPad T60 needs pipe A force quirk (bug #16494) */
369    { PCI_CHIP_I945_GM, 0x17aa, 0x201a, quirk_pipea_force },
370
371    /* Sony vaio PCG-r600HFP (fix bug 13722) */
372    { PCI_CHIP_I830_M, 0x104d, 0x8100, quirk_ivch_dvob },
373    /* Sony vaio VGN-SZ4MN (See LP: #212163) */
374    { PCI_CHIP_I830_M, 0x104d, 0x81e6, quirk_pipea_force },
375    /* Sony VGC-LT71DB has no VGA output (bug #17395) */
376    { PCI_CHIP_I965_GM, 0x104d, 0x9018, quirk_ignore_crt },
377
378    /* Quanta Gigabyte W251U (See LP: #244242) */
379    { PCI_CHIP_I945_GM, 0x152d, 0x0755, quirk_pipea_force },
380
381    /* Ordi Enduro UW31 (See LP: #152416) */
382    { PCI_CHIP_I945_GM, 0x1584, 0x9900, quirk_ignore_tv },
383
384    /* Dell Latitude D500 needs reset modes quirk */
385    { PCI_CHIP_I855_GM, 0x1028, 0x0152, quirk_reset_modes },
386
387    /* Littlebit Sepia X35 (rebranded Asus Z37E) (See LP: #201257) */
388    { PCI_CHIP_I965_GM, 0x1043, 0x8265, quirk_ignore_tv },
389
390    /* 855 & before need to leave pipe A & dpll A up */
391    { PCI_CHIP_I855_GM, SUBSYS_ANY, SUBSYS_ANY, quirk_pipea_force },
392    { PCI_CHIP_845_G, SUBSYS_ANY, SUBSYS_ANY, quirk_pipea_force },
393
394    /* Asus Eee Box has no LVDS */
395    { PCI_CHIP_I945_GME, 0x1043, 0x1252, quirk_ignore_lvds },
396
397    /* #19239: Mirrus Centrino laptop */
398    { PCI_CHIP_I915_GM, 0x1584, 0x9800, quirk_broken_acpi_lid },
399
400    /* #19529: iBase MB890 board */
401    { PCI_CHIP_I855_GM, 0x8086, 0x3582, quirk_ibase_lvds },
402
403    { 0, 0, 0, NULL },
404};
405
406void i830_fixup_devices(ScrnInfoPtr scrn)
407{
408    I830Ptr pI830 = I830PTR(scrn);
409    i830_quirk_ptr p = i830_quirk_list;
410    int i;
411
412    i830_dmi_scan();
413
414    if (0)
415	i830_dmi_dump();
416
417    while (p && p->chipType != 0) {
418	if (DEVICE_ID(pI830->PciInfo) == p->chipType &&
419	    (SUBVENDOR_ID(pI830->PciInfo) == p->subsysVendor ||
420	     p->subsysVendor == SUBSYS_ANY) &&
421	    (SUBSYS_ID(pI830->PciInfo) == p->subsysCard ||
422	     p->subsysCard == SUBSYS_ANY))
423	    p->hook(pI830);
424	++p;
425    }
426
427    for (i = 0; i < dmi_data_max; i++)
428	if (i830_dmi_data[i])
429	    xfree(i830_dmi_data[i]);
430}
431