1 /* 2 * Copyright 2012-2014, Artem Falcon <lomka@gero.in> 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <string.h> 8 9 #include <KernelExport.h> 10 #include <directories.h> 11 #include <stdio.h> 12 #include <driver_settings.h> 13 14 #include "intel_extreme.h" 15 #include "driver.h" 16 17 18 #define TRACE_BIOS 19 #ifdef TRACE_BIOS 20 # define TRACE(x) dprintf x 21 #else 22 # define TRACE(x) ; 23 #endif 24 25 26 struct vbt_header { 27 uint8 signature[20]; 28 uint16 version; 29 uint16 header_size; 30 uint16 vbt_size; 31 uint8 vbt_checksum; 32 uint8 reserved0; 33 uint32 bdb_offset; 34 uint32 aim_offset[4]; 35 } __attribute__((packed)); 36 37 38 struct bdb_header { 39 uint8 signature[16]; 40 uint16 version; 41 uint16 header_size; 42 uint16 bdb_size; 43 } __attribute__((packed)); 44 45 46 enum bdb_block_id { 47 BDB_LVDS_OPTIONS = 40, 48 BDB_LVDS_LFP_DATA_PTRS = 41, 49 BDB_LVDS_BACKLIGHT = 43, 50 BDB_GENERIC_DTD = 58 51 }; 52 53 54 // FIXME the struct definition for the bdb_header is not complete, so we rely 55 // on direct access with hardcoded offsets to get the timings out of it. 56 #define _PIXEL_CLOCK(x) (x[0] + (x[1] << 8)) * 10000 57 #define _H_ACTIVE(x) (x[2] + ((x[4] & 0xF0) << 4)) 58 #define _H_BLANK(x) (x[3] + ((x[4] & 0x0F) << 8)) 59 #define _H_SYNC_OFF(x) (x[8] + ((x[11] & 0xC0) << 2)) 60 #define _H_SYNC_WIDTH(x) (x[9] + ((x[11] & 0x30) << 4)) 61 #define _V_ACTIVE(x) (x[5] + ((x[7] & 0xF0) << 4)) 62 #define _V_BLANK(x) (x[6] + ((x[7] & 0x0F) << 8)) 63 #define _V_SYNC_OFF(x) ((x[10] >> 4) + ((x[11] & 0x0C) << 2)) 64 #define _V_SYNC_WIDTH(x) ((x[10] & 0x0F) + ((x[11] & 0x03) << 4)) 65 66 #define BDB_BACKLIGHT_TYPE_NONE 0 67 #define BDB_BACKLIGHT_TYPE_PWM 2 68 69 70 struct lvds_bdb1 { 71 uint8 id; 72 uint16 size; 73 uint8 panel_type; 74 uint8 reserved0; 75 uint16 caps; 76 } __attribute__((packed)); 77 78 79 struct lvds_bdb2_entry { 80 uint16 lfp_info_offset; 81 uint8 lfp_info_size; 82 uint16 lfp_edid_dtd_offset; 83 uint8 lfp_edid_dtd_size; 84 uint16 lfp_edid_pid_offset; 85 uint8 lfp_edid_pid_size; 86 } __attribute__((packed)); 87 88 89 struct lvds_bdb2 { 90 uint8 id; 91 uint16 size; 92 uint8 table_size; /* followed by one or more lvds_data_ptr structs */ 93 struct lvds_bdb2_entry panels[16]; 94 } __attribute__((packed)); 95 96 97 struct lvds_bdb2_lfp_info { 98 uint16 x_res; 99 uint16 y_res; 100 uint32 lvds_reg; 101 uint32 lvds_reg_val; 102 uint32 pp_on_reg; 103 uint32 pp_on_reg_val; 104 uint32 pp_off_reg; 105 uint32 pp_off_reg_val; 106 uint32 pp_cycle_reg; 107 uint32 pp_cycle_reg_val; 108 uint32 pfit_reg; 109 uint32 pfit_reg_val; 110 uint16 terminator; 111 } __attribute__((packed)); 112 113 114 115 struct generic_dtd_entry { 116 uint32 pixel_clock; 117 uint16 hactive; 118 uint16 hblank; 119 uint16 hfront_porch; 120 uint16 hsync; 121 uint16 vactive; 122 uint16 vblank; 123 uint16 vfront_porch; 124 uint16 vsync; 125 uint16 width_mm; 126 uint16 height_mm; 127 128 uint8 rsvd_flags:6; 129 uint8 vsync_positive_polarity:1; 130 uint8 hsync_positive_polarity:1; 131 132 uint8 rsvd[3]; 133 } __attribute__((packed)); 134 135 136 struct bdb_generic_dtd { 137 uint8 id; 138 uint16 size; 139 uint16 gdtd_size; 140 struct generic_dtd_entry dtd[]; 141 } __attribute__((packed)); 142 143 144 struct bdb_lfp_backlight_data_entry { 145 uint8 type: 2; 146 uint8 active_low_pwm: 1; 147 uint8 reserved1: 5; 148 uint16 pwm_freq_hz; 149 uint8 min_brightness; // Versions < 234 150 uint8 reserved2; 151 uint8 reserved3; 152 } __attribute__((packed)); 153 154 155 struct bdb_lfp_backlight_control_method { 156 uint8 type: 4; 157 uint8 controller: 4; 158 } __attribute__((packed)); 159 160 161 struct lfp_brightness_level { 162 uint16 level; 163 uint16 reserved; 164 } __attribute__((packed)); 165 166 167 struct bdb_lfp_backlight_data { 168 uint8 entry_size; 169 struct bdb_lfp_backlight_data_entry data[16]; 170 uint8 level [16]; // Only for versions < 234 171 struct bdb_lfp_backlight_control_method backlight_control[16]; 172 struct lfp_brightness_level brightness_level[16]; // Versions >= 234 173 struct lfp_brightness_level brightness_min_level[16]; // Versions >= 234 174 uint8 brightness_precision_bits[16]; // Versions >= 236 175 } __attribute__((packed)); 176 177 178 static struct vbios { 179 area_id area; 180 uint8* memory; 181 uint16_t ReadWord(off_t address) 182 { 183 return memory[address] | memory[address + 1] << 8; 184 } 185 } vbios; 186 187 188 static bool 189 read_settings_dumpRom(void) 190 { 191 bool dumpRom = false; 192 193 void* settings = load_driver_settings("intel_extreme"); 194 if (settings != NULL) { 195 dumpRom = get_driver_boolean_parameter(settings, 196 "dump_rom", false, false); 197 198 unload_driver_settings(settings); 199 } 200 return dumpRom; 201 } 202 203 204 static void 205 dumprom(void *rom, uint32 size, intel_info &info) 206 { 207 int fd; 208 uint32 cnt; 209 char fname[64]; 210 211 /* determine the romfile name: we need split-up per card in the system */ 212 sprintf (fname, kUserDirectory "//intel_extreme.%04x_%04x_%02x%02x%02x.rom", 213 info.pci->vendor_id, info.pci->device_id, info.pci->bus, info.pci->device, info.pci->function); 214 215 fd = open (fname, O_WRONLY | O_CREAT, 0666); 216 if (fd < 0) return; 217 218 /* The ROM size is a multiple of 1kb.. */ 219 for (cnt = 0; (cnt < size); cnt += 1024) 220 write (fd, ((void *)(((uint8 *)rom) + cnt)), 1024); 221 close (fd); 222 } 223 224 225 /*! This is reimplementation, Haiku uses BIOS call and gets most current panel 226 info, we're, otherwise, digging in VBIOS memory and parsing VBT tables to 227 get native panel timings. This will allow to get non-updated, 228 PROM-programmed timings info when compensation mode is off on your machine. 229 */ 230 231 // outdated: https://01.org/sites/default/files/documentation/skl_opregion_rev0p5.pdf 232 233 #define ASLS 0xfc // ASL Storage. 234 #define OPREGION_SIGNATURE "IntelGraphicsMem" 235 #define OPREGION_ASLE_OFFSET 0x300 236 #define OPREGION_VBT_OFFSET 0x400 237 #define MBOX_ACPI (1 << 0) 238 #define MBOX_SWSCI (1 << 1) 239 #define MBOX_ASLE (1 << 2) 240 #define MBOX_ASLE_EXT (1 << 3) 241 242 243 struct opregion_header { 244 uint8 signature[16]; 245 uint32 size; 246 uint8 reserved; 247 uint8 revision_version; 248 uint8 minor_version; 249 uint8 major_version; 250 uint8 sver[32]; 251 uint8 vver[16]; 252 uint8 gver[16]; 253 uint32 mboxes; 254 uint32 driver_model; 255 uint32 platform_configuration; 256 uint8 gop_version[32]; 257 uint8 rsvd[124]; 258 } __attribute__((packed)); 259 260 261 struct opregion_asle { 262 uint32 ardy; 263 uint32 aslc; 264 uint32 tche; 265 uint32 alsi; 266 uint32 bclp; 267 uint32 pfit; 268 uint32 cblv; 269 uint16 bclm[20]; 270 uint32 cpfm; 271 uint32 epfm; 272 uint8 plut[74]; 273 uint32 pfmb; 274 uint32 cddv; 275 uint32 pcft; 276 uint32 srot; 277 uint32 iuer; 278 uint64 fdss; 279 uint32 fdsp; 280 uint32 stat; 281 uint64 rvda; 282 uint32 rvds; 283 uint8 rsvd[58]; 284 } __attribute__((packed)); 285 286 287 static bool 288 get_bios(int* vbtOffset) 289 { 290 STATIC_ASSERT(sizeof(opregion_header) == 0x100); 291 STATIC_ASSERT(sizeof(opregion_asle) == 0x100); 292 293 intel_info &info = *gDeviceInfo[0]; 294 // first try to fetch Intel OpRegion which should be populated by the BIOS at start 295 uint32 kVBIOSSize; 296 297 for (uint32 romMethod = 0; romMethod < 2; romMethod++) { 298 switch(romMethod) { 299 case 0: 300 { 301 // get OpRegion - see Intel ACPI IGD info in acpi_igd_opregion_spec_0.pdf 302 uint64 kVBIOSAddress = get_pci_config(info.pci, ASLS, 4); 303 if (kVBIOSAddress == 0) { 304 TRACE((DEVICE_NAME ": ACPI OpRegion not supported!\n")); 305 continue; 306 } 307 kVBIOSSize = 8 * 1024; 308 TRACE((DEVICE_NAME ": Graphic OpRegion physical addr: 0x%" B_PRIx64 309 "; size: 0x%" B_PRIx32 "\n", kVBIOSAddress, kVBIOSSize)); 310 vbios.area = map_physical_memory("ASLS mapping", kVBIOSAddress, 311 kVBIOSSize, B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA, (void **)&vbios.memory); 312 if (vbios.area < 0) 313 continue; 314 TRACE((DEVICE_NAME ": mapping OpRegion: 0x%" B_PRIx64 " -> %p\n", 315 kVBIOSAddress, vbios.memory)); 316 // check if we got the OpRegion and signature 317 if (memcmp(vbios.memory, OPREGION_SIGNATURE, 16) != 0) { 318 TRACE((DEVICE_NAME ": OpRegion signature mismatch\n")); 319 delete_area(vbios.area); 320 vbios.area = -1; 321 continue; 322 } 323 opregion_header* header = (opregion_header*)vbios.memory; 324 opregion_asle* asle = (opregion_asle*)(vbios.memory + OPREGION_ASLE_OFFSET); 325 if (header->major_version < 2 || (header->mboxes & MBOX_ASLE) == 0 326 || asle->rvda == 0 || asle->rvds == 0) { 327 vbios.memory += OPREGION_VBT_OFFSET; 328 kVBIOSSize -= OPREGION_VBT_OFFSET; 329 break; 330 } 331 uint64 rvda = asle->rvda; 332 kVBIOSSize = asle->rvds; 333 if (header->major_version > 3 || header->minor_version >= 1) { 334 rvda += kVBIOSAddress; 335 } 336 TRACE((DEVICE_NAME ": RVDA physical addr: 0x%" B_PRIx64 337 "; size: 0x%" B_PRIx32 "\n", rvda, kVBIOSSize)); 338 delete_area(vbios.area); 339 vbios.area = map_physical_memory("RVDA mapping", rvda, 340 kVBIOSSize, B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA, (void **)&vbios.memory); 341 if (vbios.area < 0) 342 continue; 343 break; 344 } 345 case 1: 346 { 347 uint64 kVBIOSAddress = 0xc0000; 348 kVBIOSSize = 64 * 1024; 349 /* !!!DANGER!!!: mapping of BIOS using legacy location as a fallback, 350 hence, if panel mode will be set using info from VBT this way, it will 351 be taken from primary card's VBIOS */ 352 vbios.area = map_physical_memory("VBIOS mapping", kVBIOSAddress, 353 kVBIOSSize, B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA, (void**)&vbios.memory); 354 if (vbios.area < 0) 355 continue; 356 357 TRACE((DEVICE_NAME ": mapping VBIOS: 0x%" B_PRIx64 " -> %p\n", 358 kVBIOSAddress, vbios.memory)); 359 break; 360 } 361 } 362 363 // dump ROM to file if selected in settings file 364 if (read_settings_dumpRom()) 365 dumprom(vbios.memory, kVBIOSSize, info); 366 367 // scan BIOS for VBT signature 368 *vbtOffset = kVBIOSSize; 369 for (uint32 i = 0; i + 4 < kVBIOSSize; i += 4) { 370 if (memcmp(vbios.memory + i, "$VBT", 4) == 0) { 371 *vbtOffset = i; 372 break; 373 } 374 } 375 376 if ((*vbtOffset + (uint32)sizeof(vbt_header)) >= kVBIOSSize) { 377 TRACE((DEVICE_NAME": bad VBT offset : 0x%x\n", *vbtOffset)); 378 delete_area(vbios.area); 379 continue; 380 } 381 382 struct vbt_header* vbt = (struct vbt_header*)(vbios.memory + *vbtOffset); 383 if (memcmp(vbt->signature, "$VBT", 4) != 0) { 384 TRACE((DEVICE_NAME": bad VBT signature: %20s\n", vbt->signature)); 385 delete_area(vbios.area); 386 continue; 387 } 388 return true; 389 } 390 391 return false; 392 } 393 394 395 static void 396 sanitize_panel_timing(display_timing& timing) 397 { 398 bool bogus = false; 399 400 /* handle bogus h/vtotal values, if got such */ 401 if (timing.h_sync_end > timing.h_total) { 402 timing.h_total = timing.h_sync_end + 1; 403 bogus = true; 404 TRACE((DEVICE_NAME": got bogus htotal. Fixing\n")); 405 } 406 if (timing.v_sync_end > timing.v_total) { 407 timing.v_total = timing.v_sync_end + 1; 408 bogus = true; 409 TRACE((DEVICE_NAME": got bogus vtotal. Fixing\n")); 410 } 411 412 if (bogus) { 413 TRACE((DEVICE_NAME": adjusted LFP modeline: %" B_PRIu32 " KHz,\t" 414 "%d %d %d %d %d %d %d %d\n", 415 timing.pixel_clock / (timing.h_total * timing.v_total), 416 timing.h_display, timing.h_sync_start, 417 timing.h_sync_end, timing.h_total, 418 timing.v_display, timing.v_sync_start, 419 timing.v_sync_end, timing.v_total)); 420 } 421 } 422 423 424 bool 425 get_lvds_mode_from_bios(display_timing* panelTiming, uint16* minBrightness) 426 { 427 int vbtOffset = 0; 428 if (!get_bios(&vbtOffset)) 429 return false; 430 431 struct vbt_header* vbt = (struct vbt_header*)(vbios.memory + vbtOffset); 432 int bdbOffset = vbtOffset + vbt->bdb_offset; 433 434 struct bdb_header* bdb = (struct bdb_header*)(vbios.memory + bdbOffset); 435 if (memcmp(bdb->signature, "BIOS_DATA_BLOCK ", 16) != 0) { 436 TRACE((DEVICE_NAME": bad BDB signature\n")); 437 delete_area(vbios.area); 438 } 439 TRACE((DEVICE_NAME ": VBT signature \"%.*s\", BDB version %d\n", 440 (int)sizeof(vbt->signature), vbt->signature, bdb->version)); 441 442 int blockSize; 443 int panelType = -1; 444 bool panelTimingFound = false; 445 446 for (int bdbBlockOffset = bdb->header_size; bdbBlockOffset < bdb->bdb_size; 447 bdbBlockOffset += blockSize) { 448 int start = bdbOffset + bdbBlockOffset; 449 450 int id = vbios.memory[start]; 451 blockSize = vbios.ReadWord(start + 1) + 3; 452 switch (id) { 453 case BDB_LVDS_OPTIONS: 454 { 455 struct lvds_bdb1 *lvds1; 456 lvds1 = (struct lvds_bdb1 *)(vbios.memory + start); 457 panelType = lvds1->panel_type; 458 if (panelType > 0xf) { 459 TRACE((DEVICE_NAME ": invalid panel type %d\n", panelType)); 460 panelType = -1; 461 break; 462 } 463 TRACE((DEVICE_NAME ": panel type: %d\n", panelType)); 464 break; 465 } 466 case BDB_LVDS_LFP_DATA_PTRS: 467 { 468 // First make sure we found block BDB_LVDS_OPTIONS and the panel type 469 if (panelType == -1) 470 break; 471 472 // on newer versions, check also generic DTD, use LFP panel DTD as a fallback 473 if (bdb->version >= 229 && panelTimingFound) 474 break; 475 476 struct lvds_bdb2 *lvds2; 477 struct lvds_bdb2_lfp_info *lvds2_lfp_info; 478 479 lvds2 = (struct lvds_bdb2 *)(vbios.memory + start); 480 lvds2_lfp_info = (struct lvds_bdb2_lfp_info *) 481 (vbios.memory + bdbOffset 482 + lvds2->panels[panelType].lfp_info_offset); 483 /* Show terminator: Check not done in drm i915 driver: Assuming chk not valid. */ 484 TRACE((DEVICE_NAME ": LFP info terminator %x\n", lvds2_lfp_info->terminator)); 485 486 uint8_t* timing_data = vbios.memory + bdbOffset 487 + lvds2->panels[panelType].lfp_edid_dtd_offset; 488 TRACE((DEVICE_NAME ": found LFP of size %d x %d " 489 "in BIOS VBT tables\n", 490 lvds2_lfp_info->x_res, lvds2_lfp_info->y_res)); 491 492 panelTiming->pixel_clock = _PIXEL_CLOCK(timing_data) / 1000; 493 panelTiming->h_sync_start = _H_ACTIVE(timing_data) + _H_SYNC_OFF(timing_data); 494 panelTiming->h_sync_end = panelTiming->h_sync_start + _H_SYNC_WIDTH(timing_data); 495 panelTiming->h_total = _H_ACTIVE(timing_data) + _H_BLANK(timing_data); 496 panelTiming->h_display = _H_ACTIVE(timing_data); 497 panelTiming->v_sync_start = _V_ACTIVE(timing_data) + _V_SYNC_OFF(timing_data); 498 panelTiming->v_sync_end = panelTiming->v_sync_start + _V_SYNC_WIDTH(timing_data); 499 panelTiming->v_total = _V_ACTIVE(timing_data) + _V_BLANK(timing_data); 500 panelTiming->v_display = _V_ACTIVE(timing_data); 501 panelTiming->flags = 0; 502 503 sanitize_panel_timing(*panelTiming); 504 505 panelTimingFound = true; 506 break; 507 508 } 509 case BDB_GENERIC_DTD: 510 { 511 // First make sure we found block BDB_LVDS_OPTIONS and the panel type 512 if (panelType == -1) 513 break; 514 515 bdb_generic_dtd* generic_dtd = (bdb_generic_dtd*)(vbios.memory + start); 516 if (generic_dtd->gdtd_size < sizeof(bdb_generic_dtd)) { 517 TRACE((DEVICE_NAME ": invalid gdtd_size %d\n", generic_dtd->gdtd_size)); 518 break; 519 } 520 int32 count = (blockSize - sizeof(bdb_generic_dtd)) / generic_dtd->gdtd_size; 521 if (panelType >= count) { 522 TRACE((DEVICE_NAME ": panel type not found %d in %" B_PRId32 " dtds\n", 523 panelType, count)); 524 break; 525 } 526 generic_dtd_entry* dtd = &generic_dtd->dtd[panelType]; 527 TRACE((DEVICE_NAME ": pixel_clock %" B_PRId32 " " 528 "hactive %d hfront_porch %d hsync %d hblank %d " 529 "vactive %d vfront_porch %d vsync %d vblank %d\n", 530 dtd->pixel_clock, dtd->hactive, dtd->hfront_porch, dtd->hsync, dtd->hblank, 531 dtd->vactive, dtd->vfront_porch, dtd->vsync, dtd->vblank)); 532 533 TRACE((DEVICE_NAME ": found generic dtd entry of size %d x %d " 534 "in BIOS VBT tables\n", dtd->hactive, dtd->vactive)); 535 536 panelTiming->pixel_clock = dtd->pixel_clock; 537 panelTiming->h_sync_start = dtd->hactive + dtd->hfront_porch; 538 panelTiming->h_sync_end = panelTiming->h_sync_start + dtd->hsync; 539 panelTiming->h_total = dtd->hactive + dtd->hblank; 540 panelTiming->h_display = dtd->hactive; 541 panelTiming->v_sync_start = dtd->vactive + dtd->vfront_porch; 542 panelTiming->v_sync_end = panelTiming->v_sync_start + dtd->vsync; 543 panelTiming->v_total = dtd->vactive + dtd->vblank; 544 panelTiming->v_display = dtd->vactive; 545 panelTiming->flags = 0; 546 if (dtd->hsync_positive_polarity) 547 panelTiming->flags |= B_POSITIVE_HSYNC; 548 if (dtd->vsync_positive_polarity) 549 panelTiming->flags |= B_POSITIVE_VSYNC; 550 551 sanitize_panel_timing(*panelTiming); 552 panelTimingFound = true; 553 break; 554 } 555 case BDB_LVDS_BACKLIGHT: 556 { 557 TRACE((DEVICE_NAME ": found bdb lvds backlight info\n")); 558 // First make sure we found block BDB_LVDS_OPTIONS and the panel type 559 if (panelType == -1) 560 break; 561 562 bdb_lfp_backlight_data* backlightData 563 = (bdb_lfp_backlight_data*)(vbios.memory + start); 564 565 const struct bdb_lfp_backlight_data_entry* entry = &backlightData->data[panelType]; 566 567 if (entry->type == BDB_BACKLIGHT_TYPE_PWM) { 568 uint16 minLevel; 569 if (bdb->version < 234) { 570 minLevel = entry->min_brightness; 571 } else { 572 minLevel = backlightData->brightness_min_level[panelType].level; 573 if (bdb->version >= 236 574 && backlightData->brightness_precision_bits[panelType] == 16) { 575 TRACE((DEVICE_NAME ": divide level by 255\n")); 576 minLevel /= 255; 577 } 578 } 579 580 *minBrightness = minLevel; 581 TRACE((DEVICE_NAME ": display %d min brightness level is %u\n", panelType, 582 minLevel)); 583 } else { 584 TRACE((DEVICE_NAME ": display %d does not have PWM\n", panelType)); 585 } 586 break; 587 } 588 } 589 } 590 591 delete_area(vbios.area); 592 return panelTimingFound; 593 } 594