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