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