intel_extreme: Properly use VBIOS panel mode

* Move current_mode into the accelerant as the
  driver doesn't care.
* Record panel_mode in driver and present to accelerant
* eDP, if no EDID and mobile, leave edid incomplete.
  Mode set should notice that and fall back to panel_mode
This commit is contained in:
Alexander von Gluck IV
2016-03-11 18:20:28 -06:00
parent a81f65eae5
commit 3d1bd895ad
8 changed files with 61 additions and 59 deletions
@@ -213,12 +213,12 @@ struct intel_shared_info {
area_id mode_list_area; // area containing display mode list
uint32 mode_count;
display_mode current_mode;
display_mode panel_mode; // VBIOS VBT panel mode
uint32 bytes_per_row;
uint32 bits_per_pixel;
uint32 dpms_mode;
area_id registers_area; // area of memory mapped registers
area_id registers_area; // area of memory mapped registers
uint32 register_blocks[REGISTER_BLOCK_COUNT];
uint8* status_page;
@@ -963,8 +963,24 @@ EmbeddedDisplayPort::EmbeddedDisplayPort()
bool
EmbeddedDisplayPort::IsConnected()
{
if (!gInfo->shared_info->device_type.IsMobile())
return false;
addr_t portRegister = _PortRegister();
return DisplayPort::IsConnected();
TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
portRegister);
if (!gInfo->shared_info->device_type.IsMobile()) {
TRACE("%s: skipping eDP on non-mobile GPU\n", __func__);
return false;
}
if ((read32(portRegister) & DISPLAY_MONITOR_PORT_DETECTED) == 0) {
TRACE("%s: %s link not detected\n", __func__, PortName());
return false;
}
HasEDID();
// If eDP has EDID, awesome. We use it.
// No EDID? The modesetting code falls back to VBIOS panel_mode
return true;
}
@@ -40,6 +40,8 @@ struct accelerant_info {
intel_shared_info* shared_info;
area_id shared_info_area;
display_mode current_mode; // pretty much a hack until per-display modes
display_mode* mode_list; // cloned list of standard display modes
area_id mode_list_area;
@@ -68,9 +70,6 @@ struct accelerant_info {
int device;
uint8 head_mode;
bool is_clone;
// LVDS panel mode passed from the bios/startup.
display_mode lvds_panel_mode;
};
@@ -114,7 +113,6 @@ extern void setup_ring_buffer(ring_buffer &ringBuffer, const char* name);
// modes.cpp
extern void wait_for_vblank(void);
extern void set_frame_buffer_base(void);
extern void save_lvds_mode(void);
extern status_t create_mode_list(void);
// memory.cpp
+29 -41
View File
@@ -40,6 +40,9 @@
#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
#if 0
// This hack needs to die. Leaving in for a little while
// incase we *really* need it.
static void
retrieve_current_mode(display_mode& mode, uint32 pllRegister)
{
@@ -193,6 +196,7 @@ retrieve_current_mode(display_mode& mode, uint32 pllRegister)
mode.flags = B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS
| B_DPMS | B_SUPPORTS_OVERLAYS;
}
#endif
static void
@@ -274,7 +278,8 @@ void
set_frame_buffer_base()
{
intel_shared_info &sharedInfo = *gInfo->shared_info;
display_mode &mode = sharedInfo.current_mode;
display_mode &mode = gInfo->current_mode;
uint32 baseRegister;
uint32 surfaceRegister;
@@ -320,30 +325,29 @@ create_mode_list(void)
gInfo->has_edid = true;
}
if (!gInfo->has_edid) {
// If no EDID, but have vbt from driver, use that mode
if (!gInfo->has_edid && gInfo->shared_info->got_vbt) {
// We could not read any EDID info. Fallback to creating a list with
// only the mode set up by the BIOS.
// TODO: support lower modes via scaling and windowing
if ((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0
&& (gInfo->head_mode & HEAD_MODE_A_ANALOG) == 0) {
size_t size = (sizeof(display_mode) + B_PAGE_SIZE - 1)
& ~(B_PAGE_SIZE - 1);
size_t size = (sizeof(display_mode) + B_PAGE_SIZE - 1)
& ~(B_PAGE_SIZE - 1);
display_mode* list;
area_id area = create_area("intel extreme modes",
(void**)&list, B_ANY_ADDRESS, size, B_NO_LOCK,
B_READ_AREA | B_WRITE_AREA);
if (area < 0)
return area;
display_mode* list;
area_id area = create_area("intel extreme modes",
(void**)&list, B_ANY_ADDRESS, size, B_NO_LOCK,
B_READ_AREA | B_WRITE_AREA);
if (area < 0)
return area;
memcpy(list, &gInfo->lvds_panel_mode, sizeof(display_mode));
memcpy(list, &gInfo->shared_info->panel_mode, sizeof(display_mode));
gInfo->mode_list_area = area;
gInfo->mode_list = list;
gInfo->shared_info->mode_list_area = gInfo->mode_list_area;
gInfo->shared_info->mode_count = 1;
return B_OK;
}
gInfo->mode_list_area = area;
gInfo->mode_list = list;
gInfo->shared_info->mode_list_area = gInfo->mode_list_area;
gInfo->shared_info->mode_count = 1;
return B_OK;
}
// Otherwise return the 'real' list of modes
@@ -373,24 +377,6 @@ wait_for_vblank(void)
}
/*! Store away panel information if identified on startup
(used for pipe B->lvds).
*/
void
save_lvds_mode(void)
{
// dump currently programmed mode.
display_mode biosMode;
retrieve_current_mode(biosMode, INTEL_DISPLAY_B_PLL);
sanitize_display_mode(biosMode);
// The BIOS mode may not be a valid mode, as LVDS output does not
// really care about the sync values
gInfo->lvds_panel_mode = biosMode;
}
// #pragma mark -
@@ -488,7 +474,7 @@ intel_set_display_mode(display_mode* mode)
base) < B_OK) {
// oh, how did that happen? Unfortunately, there is no really good way
// back
if (intel_allocate_memory(sharedInfo.current_mode.virtual_height
if (intel_allocate_memory(gInfo->current_mode.virtual_height
* sharedInfo.bytes_per_row, 0, base) == B_OK) {
sharedInfo.frame_buffer = base;
sharedInfo.frame_buffer_offset = base
@@ -618,8 +604,10 @@ intel_set_display_mode(display_mode* mode)
write32(INTEL_DISPLAY_B_BYTES_PER_ROW, bytesPerRow);
// update shared info
gInfo->current_mode = target;
// TODO: move to gInfo
sharedInfo.bytes_per_row = bytesPerRow;
sharedInfo.current_mode = target;
sharedInfo.bits_per_pixel = bitsPerPixel;
set_frame_buffer_base();
@@ -637,7 +625,7 @@ intel_get_display_mode(display_mode* _currentMode)
{
CALLED();
*_currentMode = gInfo->shared_info->current_mode;
*_currentMode = gInfo->current_mode;
// This seems unreliable. We should always know the current_mode
//retrieve_current_mode(*_currentMode, INTEL_DISPLAY_A_PLL);
@@ -710,7 +698,7 @@ intel_move_display(uint16 horizontalStart, uint16 verticalStart)
intel_shared_info &sharedInfo = *gInfo->shared_info;
Autolock locker(sharedInfo.accelerant_lock);
display_mode &mode = sharedInfo.current_mode;
display_mode &mode = gInfo->current_mode;
if (horizontalStart + mode.timing.h_display > mode.virtual_width
|| verticalStart + mode.timing.v_display > mode.virtual_height)
@@ -207,7 +207,7 @@ set_color_key(uint8 red, uint8 green, uint8 blue, uint8 redMask,
static void
set_color_key(const overlay_window* window)
{
switch (gInfo->shared_info->current_mode.space) {
switch (gInfo->current_mode.space) {
case B_CMAP8:
set_color_key(0, 0, window->blue.value, 0x0, 0x0, 0xff);
break;
@@ -589,10 +589,10 @@ intel_configure_overlay(overlay_token overlayToken,
left = 0;
if (top < 0)
top = 0;
if (right > gInfo->shared_info->current_mode.timing.h_display)
right = gInfo->shared_info->current_mode.timing.h_display;
if (bottom > gInfo->shared_info->current_mode.timing.v_display)
bottom = gInfo->shared_info->current_mode.timing.v_display;
if (right > gInfo->current_mode.timing.h_display)
right = gInfo->current_mode.timing.h_display;
if (bottom > gInfo->current_mode.timing.v_display)
bottom = gInfo->current_mode.timing.v_display;
if (left >= right || top >= bottom) {
// overlay is not within visible bounds
hide_overlay();
@@ -119,8 +119,6 @@ static struct vbios {
} vbios;
/* TODO: move code to accelerant, if possible */
/*! This is reimplementation, Haiku uses BIOS call and gets most current panel
info, we're, otherwise, digging in VBIOS memory and parsing VBT tables to
get native panel timings. This will allow to get non-updated,
@@ -405,8 +405,10 @@ intel_extreme_init(intel_info &info)
info.shared_info->frame_buffer = 0;
info.shared_info->dpms_mode = B_DPMS_ON;
// Pull VBIOS panel mode for later use
info.shared_info->got_vbt = get_lvds_mode_from_bios(
&info.shared_info->current_mode);
&info.shared_info->panel_mode);
/* at least 855gm can't drive more than one head at time */
if (info.device_type.InFamily(INTEL_FAMILY_8xx))
info.shared_info->single_head_locked = 1;
@@ -70,7 +70,7 @@ find_reg(const intel_info& info, uint32 target)
}
extern bool get_lvds_mode_from_bios(display_mode *shared_info);
extern bool get_lvds_mode_from_bios(display_mode *mode);
extern status_t intel_free_memory(intel_info& info, addr_t offset);
extern status_t intel_allocate_memory(intel_info& info, size_t size,
size_t alignment, uint32 flags, addr_t* _offset,