intel_extreme: reduce use of display_mode where display_timing is enough

In most cases we don't need to use the complete display_mode struct and
we just need the timings. This will avoid future confusion between the
virtual width/height and the actual display timings, if we implement
scrolling someday.

Change-Id: I6c4430b84130b956a47ea0a01afb0843f5a34fd2
Reviewed-on: https://review.haiku-os.org/c/haiku/+/4665
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
Adrien Destugues 2021-10-27 14:46:04 +02:00 committed by waddlesplash
parent 0cabd8891f
commit 4492fde7bf
12 changed files with 77 additions and 107 deletions

View File

@ -249,7 +249,7 @@ struct intel_shared_info {
uint32 mode_count;
display_mode current_mode; // pretty much a hack until per-display modes
display_mode panel_mode; // VBIOS VBT panel mode
display_timing panel_timing; // Hardware timings of the LVDS panel, extracted from BIOS
uint32 bytes_per_row;
uint32 bits_per_pixel;
uint32 dpms_mode;

View File

@ -250,7 +250,7 @@ FDILink::FDILink(pipe_index pipeIndex)
status_t
FDILink::Train(display_mode* target)
FDILink::Train(display_timing* target)
{
CALLED();
@ -284,7 +284,7 @@ FDILink::Train(display_mode* target)
// Khz / 10. ( each output octet encoded as 10 bits.
uint32 linkBandwidth = gInfo->shared_info->fdi_link_frequency * 1000 / 10;
//Reserving 5% bandwidth for possible spread spectrum clock use
uint32 bps = target->timing.pixel_clock * bitsPerPixel * 21 / 20;
uint32 bps = target->pixel_clock * bitsPerPixel * 21 / 20;
//use DIV_ROUND_UP:
uint32 lanes = (bps + (linkBandwidth * 8) - 1) / (linkBandwidth * 8);
@ -338,7 +338,7 @@ FDILink::Train(display_mode* target)
if (ret_n > 0x800000) {
ret_n = 0x800000;
}
uint64 ret_m = target->timing.pixel_clock * ret_n * bitsPerPixel / linkspeed;
uint64 ret_m = target->pixel_clock * ret_n * bitsPerPixel / linkspeed;
while ((ret_n > 0xffffff) || (ret_m > 0xffffff)) {
ret_m >>= 1;
ret_n >>= 1;
@ -356,7 +356,7 @@ FDILink::Train(display_mode* target)
if (ret_n > 0x800000) {
ret_n = 0x800000;
}
ret_m = target->timing.pixel_clock * ret_n / linkspeed;
ret_m = target->pixel_clock * ret_n / linkspeed;
while ((ret_n > 0xffffff) || (ret_m > 0xffffff)) {
ret_m >>= 1;
ret_n >>= 1;

View File

@ -65,7 +65,7 @@ public:
FDIReceiver& Receiver()
{ return fReceiver; };
status_t Train(display_mode* target);
status_t Train(display_timing* target);
private:
status_t _NormalTrain(uint32 lanes);

View File

@ -59,7 +59,7 @@ PanelFitter::IsEnabled()
void
PanelFitter::Enable(const display_mode& mode)
PanelFitter::Enable(const display_timing& timing)
{
_Enable(true);
@ -69,7 +69,7 @@ PanelFitter::Enable(const display_mode& mode)
TRACE("%s: PCH_PANEL_FITTER_WINDOW_POS, 0x%" B_PRIx32 "\n", __func__, read32(fRegisterBase + PCH_PANEL_FITTER_WINDOW_POS));
// Window size _must_ be the last register programmed as it 'arms'/unlocks all the other ones..
write32(fRegisterBase + PCH_PANEL_FITTER_WINDOW_SIZE, (mode.timing.h_display << 16) | mode.timing.v_display);
write32(fRegisterBase + PCH_PANEL_FITTER_WINDOW_SIZE, (timing.h_display << 16) | timing.v_display);
}

View File

@ -17,7 +17,7 @@ public:
virtual ~PanelFitter();
bool IsEnabled();
void Enable(const display_mode& mode);
void Enable(const display_timing& timing);
void Disable();
private:

View File

@ -363,13 +363,13 @@ AnalogPort::SetDisplayMode(display_mode* target, uint32 colorMode)
// Setup PanelFitter and Train FDI if it exists
PanelFitter* fitter = fPipe->PFT();
if (fitter != NULL)
fitter->Enable(*target);
fitter->Enable(target->timing);
FDILink* link = fPipe->FDI();
if (link != NULL)
link->Train(target);
link->Train(&target->timing);
pll_divisors divisors;
compute_pll_divisors(target, &divisors, false);
compute_pll_divisors(&target->timing, &divisors, false);
uint32 extraPLLFlags = 0;
if (gInfo->shared_info->device_type.Generation() >= 3)
@ -561,7 +561,7 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
// For LVDS panels, we may need to set the timings according to the panel
// native video mode, and let the panel fitter do the scaling. But the
// place where the scaling happens varies accross generations of devices.
display_mode hardwareTarget;
display_timing hardwareTarget;
bool needsScaling = false;
// TODO figure out how it's done (or if we need to configure something at
@ -570,25 +570,20 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
&& gInfo->shared_info->device_type.Generation() >= 3
&& gInfo->shared_info->got_vbt) {
// Set vbios hardware panel mode as base
hardwareTarget = gInfo->shared_info->panel_mode;
hardwareTarget = gInfo->shared_info->panel_timing;
if (hardwareTarget.timing.h_display == target->timing.h_display
&& hardwareTarget.timing.v_display == target->timing.v_display) {
if (hardwareTarget.h_display == target->timing.h_display
&& hardwareTarget.v_display == target->timing.v_display) {
// We are setting the native video mode, nothing special to do
TRACE("Setting LVDS to native mode\n");
hardwareTarget = *target;
hardwareTarget = target->timing;
} else {
// We need to enable the panel fitter
TRACE("%s: hardware mode will actually be %dx%d\n", __func__,
hardwareTarget.timing.h_display, hardwareTarget.timing.v_display);
hardwareTarget.h_display, hardwareTarget.v_display);
hardwareTarget.space = target->space;
// retain requested virtual size
hardwareTarget.virtual_width = target->virtual_width;
hardwareTarget.virtual_height = target->virtual_height;
// FIXME we should also get the refresh frequency from the target
// mode, and then "sanitize" the resulting mode we made up.
needsScaling = true;
}
} else {
@ -596,7 +591,7 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
"generation, scaling may not work\n");
// We don't have VBT data, try to set the requested mode directly
// and hope for the best
hardwareTarget = *target;
hardwareTarget = target->timing;
}
// Setup PanelFitter and Train FDI if it exists
@ -664,7 +659,7 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
// Program pipe PLL's (using the hardware mode timings, since that's what
// the PLL is used for)
fPipe->ConfigureClocks(divisors, hardwareTarget.timing.pixel_clock,
fPipe->ConfigureClocks(divisors, hardwareTarget.pixel_clock,
extraPLLFlags);
if (gInfo->shared_info->device_type.Generation() != 4) {
@ -799,13 +794,13 @@ DigitalPort::SetDisplayMode(display_mode* target, uint32 colorMode)
// Setup PanelFitter and Train FDI if it exists
PanelFitter* fitter = fPipe->PFT();
if (fitter != NULL)
fitter->Enable(*target);
fitter->Enable(target->timing);
FDILink* link = fPipe->FDI();
if (link != NULL)
link->Train(target);
link->Train(&target->timing);
pll_divisors divisors;
compute_pll_divisors(target, &divisors, false);
compute_pll_divisors(&target->timing, &divisors, false);
uint32 extraPLLFlags = 0;
if (gInfo->shared_info->device_type.Generation() >= 3)
@ -1345,16 +1340,16 @@ DigitalDisplayInterface::SetDisplayMode(display_mode* target, uint32 colorMode)
// Setup PanelFitter and Train FDI if it exists
PanelFitter* fitter = fPipe->PFT();
if (fitter != NULL)
fitter->Enable(*target);
fitter->Enable(target->timing);
// Skip FDI if we have a CPU connected display
if (PortIndex() != INTEL_PORT_A) {
FDILink* link = fPipe->FDI();
if (link != NULL)
link->Train(target);
link->Train(&target->timing);
}
pll_divisors divisors;
compute_pll_divisors(target, &divisors, false);
compute_pll_divisors(&target->timing, &divisors, false);
uint32 extraPLLFlags = 0;
if (gInfo->shared_info->device_type.Generation() >= 3)

View File

@ -179,9 +179,9 @@ limit_modes_for_gen3_lvds(display_mode* mode)
// display.
// FIXME do this only for that display. The whole display mode logic
// needs to be adjusted to know which display we're talking about.
if (gInfo->shared_info->panel_mode.timing.h_display < mode->timing.h_display)
if (gInfo->shared_info->panel_timing.h_display < mode->timing.h_display)
return false;
if (gInfo->shared_info->panel_mode.timing.v_display < mode->timing.v_display)
if (gInfo->shared_info->panel_timing.v_display < mode->timing.v_display)
return false;
return true;
@ -230,9 +230,17 @@ create_mode_list(void)
if (gInfo->shared_info->device_type.Generation() < 4)
limitModes = limit_modes_for_gen3_lvds;
display_mode mode;
mode.timing = gInfo->shared_info->panel_timing;
mode.space = B_RGB32;
mode.virtual_width = mode.timing.h_display;
mode.virtual_height = mode.timing.v_display;
mode.h_display_start = 0;
mode.v_display_start = 0;
mode.flags = 0;
// TODO: support lower modes via scaling and windowing
gInfo->mode_list_area = create_display_modes("intel extreme modes",
NULL, &gInfo->shared_info->panel_mode, 1,
gInfo->mode_list_area = create_display_modes("intel extreme modes", NULL, &mode, 1,
supportedSpaces, colorSpaceCount, limitModes, &list, &count);
} else {
// Otherwise return the 'real' list of modes

View File

@ -184,9 +184,9 @@ static pll_limits kLimitsPinLvds = {
static bool
lvds_dual_link(display_mode* current)
lvds_dual_link(display_timing* current)
{
float requestedPixelClock = current->timing.pixel_clock / 1000.0f;
float requestedPixelClock = current->pixel_clock / 1000.0f;
if (requestedPixelClock > 112.999)
return true;
@ -215,7 +215,7 @@ valid_pll_divisors(pll_divisors* divisors, pll_limits* limits)
static void
compute_pll_p2(display_mode* current, pll_divisors* divisors,
compute_pll_p2(display_timing* current, pll_divisors* divisors,
pll_limits* limits, bool isLVDS)
{
if (isLVDS) {
@ -227,7 +227,7 @@ compute_pll_p2(display_mode* current, pll_divisors* divisors,
divisors->p2 = limits->max.p2;
}
} else {
if (current->timing.pixel_clock < limits->dot_limit) {
if (current->pixel_clock < limits->dot_limit) {
// slow DAC timing
divisors->p2 = limits->max.p2;
} else {
@ -269,9 +269,9 @@ compute_pll_p(pll_divisors* divisors)
static void
compute_dpll_g4x(display_mode* current, pll_divisors* divisors, bool isLVDS)
compute_dpll_g4x(display_timing* current, pll_divisors* divisors, bool isLVDS)
{
float requestedPixelClock = current->timing.pixel_clock / 1000.0f;
float requestedPixelClock = current->pixel_clock / 1000.0f;
float referenceClock
= gInfo->shared_info->pll_info.reference_frequency / 1000.0f;
@ -363,9 +363,9 @@ compute_dpll_g4x(display_mode* current, pll_divisors* divisors, bool isLVDS)
static void
compute_dpll_9xx(display_mode* current, pll_divisors* divisors, bool isLVDS)
compute_dpll_9xx(display_timing* current, pll_divisors* divisors, bool isLVDS)
{
float requestedPixelClock = current->timing.pixel_clock / 1000.0f;
float requestedPixelClock = current->pixel_clock / 1000.0f;
float referenceClock
= gInfo->shared_info->pll_info.reference_frequency / 1000.0f;
@ -447,7 +447,7 @@ compute_dpll_9xx(display_mode* current, pll_divisors* divisors, bool isLVDS)
void
compute_pll_divisors(display_mode* current, pll_divisors* divisors, bool isLVDS)
compute_pll_divisors(display_timing* current, pll_divisors* divisors, bool isLVDS)
{
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_G4x)
|| (gInfo->shared_info->pch_info != INTEL_PCH_NONE)) {

View File

@ -33,7 +33,7 @@ struct pll_limits {
bool valid_pll_divisors(pll_divisors* divisors, pll_limits* limits);
void compute_pll_divisors(display_mode* current, pll_divisors* divisors,
void compute_pll_divisors(display_timing* current, pll_divisors* divisors,
bool isLVDS);
void refclk_activate_ilk(bool hasPanel);

View File

@ -102,16 +102,6 @@ struct lvds_bdb2_lfp_info {
static struct vbios {
area_id area;
uint8* memory;
display_mode* shared_info;
struct {
uint16 hsync_start;
uint16 hsync_end;
uint16 hsync_total;
uint16 vsync_start;
uint16 vsync_end;
uint16 vsync_total;
} timings_common;
uint16_t ReadWord(off_t address)
{
return memory[address] | memory[address + 1] << 8;
@ -160,57 +150,37 @@ get_bios(void)
}
static bool
feed_shared_info(uint8* data)
static void
sanitize_panel_timing(display_timing& timing)
{
bool bogus = false;
/* handle bogus h/vtotal values, if got such */
if (vbios.timings_common.hsync_end > vbios.timings_common.hsync_total) {
vbios.timings_common.hsync_total = vbios.timings_common.hsync_end + 1;
if (timing.h_sync_end > timing.h_total) {
timing.h_total = timing.h_sync_end + 1;
bogus = true;
TRACE((DEVICE_NAME": got bogus htotal. Fixing\n"));
}
if (vbios.timings_common.vsync_end > vbios.timings_common.vsync_total) {
vbios.timings_common.vsync_total = vbios.timings_common.vsync_end + 1;
if (timing.v_sync_end > timing.v_total) {
timing.v_total = timing.v_sync_end + 1;
bogus = true;
TRACE((DEVICE_NAME": got bogus vtotal. Fixing\n"));
}
if (bogus) {
TRACE((DEVICE_NAME": adjusted LFP modeline: x%d Hz,\t"
TRACE((DEVICE_NAME": adjusted LFP modeline: %" B_PRIu32 " KHz,\t"
"%d %d %d %d %d %d %d %d\n",
_PIXEL_CLOCK(data) / ((_H_ACTIVE(data) + _H_BLANK(data))
* (_V_ACTIVE(data) + _V_BLANK(data))),
_H_ACTIVE(data), vbios.timings_common.hsync_start,
vbios.timings_common.hsync_end, vbios.timings_common.hsync_total,
_V_ACTIVE(data), vbios.timings_common.vsync_start,
vbios.timings_common.vsync_end, vbios.timings_common.vsync_total));
timing.pixel_clock / (timing.h_total * timing.v_total),
timing.h_display, timing.h_sync_start,
timing.h_sync_end, timing.h_total,
timing.v_display, timing.v_sync_start,
timing.v_sync_end, timing.v_total));
}
/* TODO: add retrieved info to edid info struct, not fixed mode struct */
/* struct display_timing is not packed, so we have to set elements
individually */
vbios.shared_info->timing.pixel_clock = _PIXEL_CLOCK(data) / 1000;
vbios.shared_info->timing.h_display = vbios.shared_info->virtual_width
= _H_ACTIVE(data);
vbios.shared_info->timing.h_sync_start = vbios.timings_common.hsync_start;
vbios.shared_info->timing.h_sync_end = vbios.timings_common.hsync_end;
vbios.shared_info->timing.h_total = vbios.timings_common.hsync_total;
vbios.shared_info->timing.v_display = vbios.shared_info->virtual_height
= _V_ACTIVE(data);
vbios.shared_info->timing.v_sync_start = vbios.timings_common.vsync_start;
vbios.shared_info->timing.v_sync_end = vbios.timings_common.vsync_end;
vbios.shared_info->timing.v_total = vbios.timings_common.vsync_total;
delete_area(vbios.area);
return true;
}
bool
get_lvds_mode_from_bios(display_mode* sharedInfo)
get_lvds_mode_from_bios(display_timing* panelTiming)
{
if (!get_bios())
return false;
@ -276,27 +246,24 @@ get_lvds_mode_from_bios(display_mode* sharedInfo)
"in BIOS VBT tables\n",
lvds2_lfp_info->x_res, lvds2_lfp_info->y_res));
vbios.timings_common.hsync_start = _H_ACTIVE(timing_data)
+ _H_SYNC_OFF(timing_data);
vbios.timings_common.hsync_end
= vbios.timings_common.hsync_start
+ _H_SYNC_WIDTH(timing_data);
vbios.timings_common.hsync_total = _H_ACTIVE(timing_data)
+ _H_BLANK(timing_data);
vbios.timings_common.vsync_start = _V_ACTIVE(timing_data)
+ _V_SYNC_OFF(timing_data);
vbios.timings_common.vsync_end
= vbios.timings_common.vsync_start
+ _V_SYNC_WIDTH(timing_data);
vbios.timings_common.vsync_total = _V_ACTIVE(timing_data)
+ _V_BLANK(timing_data);
panelTiming->pixel_clock = _PIXEL_CLOCK(timing_data) / 1000;
panelTiming->h_sync_start = _H_ACTIVE(timing_data) + _H_SYNC_OFF(timing_data);
panelTiming->h_sync_end = panelTiming->h_sync_start + _H_SYNC_WIDTH(timing_data);
panelTiming->h_total = _H_ACTIVE(timing_data) + _H_BLANK(timing_data);
panelTiming->h_display = _H_ACTIVE(timing_data);
panelTiming->v_sync_start = _V_ACTIVE(timing_data) + _V_SYNC_OFF(timing_data);
panelTiming->v_sync_end = panelTiming->v_sync_start + _V_SYNC_WIDTH(timing_data);
panelTiming->v_total = _V_ACTIVE(timing_data) + _V_BLANK(timing_data);
panelTiming->v_display = _V_ACTIVE(timing_data);
panelTiming->flags = 0;
vbios.shared_info = sharedInfo;
return feed_shared_info(timing_data);
sanitize_panel_timing(*panelTiming);
delete_area(vbios.area);
return true;
}
}
}
delete_area(vbios.area);
return true;
return false;
}

View File

@ -446,7 +446,7 @@ intel_extreme_init(intel_info &info)
// Pull VBIOS panel mode for later use
info.shared_info->got_vbt = get_lvds_mode_from_bios(
&info.shared_info->panel_mode);
&info.shared_info->panel_timing);
/* at least 855gm can't drive more than one head at time */
if (info.device_type.InFamily(INTEL_FAMILY_8xx))

View File

@ -72,7 +72,7 @@ find_reg(const intel_info& info, uint32 target)
}
extern bool get_lvds_mode_from_bios(display_mode *mode);
extern bool get_lvds_mode_from_bios(display_timing *timing);
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,