582 | | i2c_bus bus; |
583 | | bus.cookie = (void*)(addr_t)INTEL_I2C_IO_A; |
584 | | bus.set_signals = &set_i2c_signals; |
585 | | bus.get_signals = &get_i2c_signals; |
586 | | ddc2_init_timing(&bus); |
587 | | |
588 | | status_t error = ddc2_read_edid1(&bus, &gInfo->edid_info, NULL, NULL); |
589 | | if (error == B_OK) { |
| 588 | // TODO: We may want to choose different GPIO pin maps |
| 589 | // for different generations of cards... not sure |
| 590 | const gpio_map gpioPinMap[] = { |
| 591 | {"ssc", INTEL_I2C_IO_B, 0}, |
| 592 | {"vga", INTEL_I2C_IO_A, HEAD_MODE_A_ANALOG}, |
| 593 | {"lvds", INTEL_I2C_IO_C, HEAD_MODE_LVDS_PANEL}, |
| 594 | {"dpc", INTEL_I2C_IO_D, 0}, |
| 595 | {"dpb", INTEL_I2C_IO_E, 0}, |
| 596 | {"dpd", INTEL_I2C_IO_F, 0}, |
| 597 | }; |
| 598 | |
| 599 | // TODO: We may want to do extra validation on gpio validOn |
| 600 | // vs the HEAD_MODE_ in head_mode |
| 601 | for (uint32 i = 0; i < sizeof(gpioPinMap) / sizeof(gpioPinMap[0]); i++) { |
| 602 | i2c_bus bus; |
| 603 | bus.cookie = (void*)gpioPinMap[i].pin; |
| 604 | bus.set_signals = &set_i2c_signals; |
| 605 | bus.get_signals = &get_i2c_signals; |
| 606 | ddc2_init_timing(&bus); |
| 607 | |
| 608 | status_t result = ddc2_read_edid1(&bus, &gInfo->edid_info, |
| 609 | NULL, NULL); |
| 610 | |
| 611 | if (result != B_OK) |
| 612 | continue; |
| 613 | |
| 614 | TRACE("found edid data on gpio '%s'\n", gpioPinMap[i].name); |
| 615 | |
594 | | } else { |
595 | | TRACE("getting EDID on port A (analog) failed: %s. " |
596 | | "Trying on port C (lvds)\n", strerror(error)); |
597 | | bus.cookie = (void*)INTEL_I2C_IO_C; |
598 | | error = ddc2_read_edid1(&bus, &gInfo->edid_info, NULL, NULL); |
599 | | if (error == B_OK) { |
600 | | edid_dump(&gInfo->edid_info); |
601 | | gInfo->has_edid = true; |
602 | | } else if (gInfo->shared_info->has_vesa_edid_info) { |
603 | | TRACE("getting EDID on port C failed: %s. Use VESA EDID info\n", |
604 | | strerror(error)); |
605 | | memcpy(&gInfo->edid_info, &gInfo->shared_info->vesa_edid_info, |
606 | | sizeof(edid1_info)); |
607 | | gInfo->has_edid = true; |
608 | | } else { |
609 | | TRACE("getting EDID on port C failed: %s\n", |
610 | | strerror(error)); |
611 | | |
612 | | // We could not read any EDID info. Fallback to creating a list with |
613 | | // only the mode set up by the BIOS. |
614 | | // TODO: support lower modes via scaling and windowing |
615 | | if (((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0 |
616 | | && (gInfo->head_mode & HEAD_MODE_A_ANALOG) == 0) |
617 | | || ((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0 |
618 | | && gInfo->shared_info->got_vbt)) { |
619 | | size_t size = (sizeof(display_mode) + B_PAGE_SIZE - 1) |
620 | | & ~(B_PAGE_SIZE - 1); |
621 | | |
622 | | display_mode* list; |
623 | | area_id area = create_area("intel extreme modes", |
624 | | (void**)&list, B_ANY_ADDRESS, size, B_NO_LOCK, |
625 | | B_READ_AREA | B_WRITE_AREA); |
626 | | if (area < B_OK) |
627 | | return area; |
628 | | |
629 | | // Prefer information dumped directly from VBT, as the BIOS |
630 | | // one may have display scaling, but only do this if the VBT |
631 | | // resolution is higher than the BIOS one. |
632 | | if (gInfo->shared_info->got_vbt |
633 | | && gInfo->shared_info->current_mode.virtual_width |
634 | | >= gInfo->lvds_panel_mode.virtual_width |
635 | | && gInfo->shared_info->current_mode.virtual_height |
636 | | >= gInfo->lvds_panel_mode.virtual_height) { |
637 | | memcpy(list, &gInfo->shared_info->current_mode, |
638 | | sizeof(display_mode)); |
639 | | mode_fill_missing_bits(list, INTEL_DISPLAY_B_CONTROL); |
640 | | } else { |
641 | | memcpy(list, &gInfo->lvds_panel_mode, |
642 | | sizeof(display_mode)); |
643 | | |
644 | | if (gInfo->shared_info->got_vbt) |
645 | | TRACE("intel_extreme: ignoring VBT mode."); |
646 | | } |
648 | | gInfo->mode_list_area = area; |
649 | | gInfo->mode_list = list; |
650 | | gInfo->shared_info->mode_list_area = gInfo->mode_list_area; |
651 | | gInfo->shared_info->mode_count = 1; |
652 | | return B_OK; |
| 621 | // TODO: We may want to probe multiple GPIO pins here |
| 622 | // someday and store valid ones for multi-head support. |
| 623 | // For now, we break on the first valid one. |
| 624 | break; |
| 625 | } |
| 626 | |
| 627 | if (!gInfo->has_edid) { |
| 628 | // We could not read any EDID info. Fallback to creating a list with |
| 629 | // only the mode set up by the BIOS. |
| 630 | // TODO: support lower modes via scaling and windowing |
| 631 | if (((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0 |
| 632 | && (gInfo->head_mode & HEAD_MODE_A_ANALOG) == 0) |
| 633 | || ((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0 |
| 634 | && gInfo->shared_info->got_vbt)) { |
| 635 | size_t size = (sizeof(display_mode) + B_PAGE_SIZE - 1) |
| 636 | & ~(B_PAGE_SIZE - 1); |
| 637 | |
| 638 | display_mode* list; |
| 639 | area_id area = create_area("intel extreme modes", |
| 640 | (void**)&list, B_ANY_ADDRESS, size, B_NO_LOCK, |
| 641 | B_READ_AREA | B_WRITE_AREA); |
| 642 | if (area < B_OK) |
| 643 | return area; |
| 644 | |
| 645 | // Prefer information dumped directly from VBT, as the BIOS |
| 646 | // one may have display scaling, but only do this if the VBT |
| 647 | // resolution is higher than the BIOS one. |
| 648 | if (gInfo->shared_info->got_vbt |
| 649 | && gInfo->shared_info->current_mode.virtual_width |
| 650 | >= gInfo->lvds_panel_mode.virtual_width |
| 651 | && gInfo->shared_info->current_mode.virtual_height |
| 652 | >= gInfo->lvds_panel_mode.virtual_height) { |
| 653 | memcpy(list, &gInfo->shared_info->current_mode, |
| 654 | sizeof(display_mode)); |
| 655 | mode_fill_missing_bits(list, INTEL_DISPLAY_B_CONTROL); |
| 656 | } else { |
| 657 | memcpy(list, &gInfo->lvds_panel_mode, |
| 658 | sizeof(display_mode)); |
| 659 | |
| 660 | if (gInfo->shared_info->got_vbt) |
| 661 | TRACE("intel_extreme: ignoring VBT mode."); |