intel_extreme: Rebase and refactor mmlr's work from 2013

* New port storage classes and cleaner logic
This commit is contained in:
Alexander von Gluck IV 2015-10-17 09:01:28 -05:00
parent c06aefa0ee
commit 50f0b3fe76
16 changed files with 1539 additions and 288 deletions

View File

@ -134,6 +134,24 @@ struct DeviceType {
return (type & INTEL_TYPE_MODEL_MASK) == model;
}
bool IsMobile() const
{
return (type & INTEL_TYPE_MODEL_MASK) == INTEL_TYPE_MOBILE;
}
bool SupportsHDMI() const
{
switch (type & INTEL_TYPE_GROUP_MASK) {
case INTEL_TYPE_G4x:
case INTEL_TYPE_ILK:
case INTEL_TYPE_SNB:
case INTEL_TYPE_IVBG:
case INTEL_TYPE_VLV:
return true;
}
return false;
}
bool HasPlatformControlHub() const
{
return InGroup(INTEL_TYPE_ILK) || InGroup(INTEL_TYPE_SNB)
@ -439,19 +457,37 @@ struct intel_free_graphics_memory {
#define INTEL_DISPLAY_A_IMAGE_SIZE (0x001c | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_B_IMAGE_SIZE (0x101c | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_A_ANALOG_PORT (0x1100 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_A_DIGITAL_PORT (0x1120 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_B_DIGITAL_PORT (0x1140 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_C_DIGITAL (0x1160 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_LVDS_PORT (0x1180 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_ANALOG_PORT (0x1100 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DIGITAL_PORT_A (0x1120 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DIGITAL_PORT_B (0x1140 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DIGITAL_PORT_C (0x1160 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DIGITAL_LVDS_PORT (0x1180 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_HDMI_PORT_B (0x1140 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_HDMI_PORT_C (0x1160 | REGS_NORTH_PIPE_AND_PORT)
#define PCH_HDMI_PORT_B (0x1140 | REGS_SOUTH_TRANSCODER_PORT)
#define PCH_HDMI_PORT_C (0x1150 | REGS_SOUTH_TRANSCODER_PORT)
#define PCH_HDMI_PORT_D (0x1160 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_PORT_A (0x4000 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_PORT_B (0x4100 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_PORT_C (0x4200 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_PORT_D (0x4300 | REGS_NORTH_PIPE_AND_PORT)
// valid for both DVI/HDMI and DisplayPort
#define PORT_DETECTED (1 << 2)
// planes
#define INTEL_DISPLAY_A_PIPE_CONTROL (0x0008 | REGS_NORTH_PLANE_CONTROL)
#define INTEL_PIPE_ENABLED (1UL << 31)
#define INTEL_PIPE_CONTROL 0x08
#define INTEL_PIPE_STATUS 0x24
#define INTEL_PIPE_OFFSET 0x1000
#define INTEL_DISPLAY_A_PIPE_CONTROL (0x0008 | REGS_NORTH_PLANE_CONTROL)
#define INTEL_DISPLAY_B_PIPE_CONTROL (0x1008 | REGS_NORTH_PLANE_CONTROL)
#define DISPLAY_PIPE_ENABLED (1UL << 31)
#define INTEL_DISPLAY_A_PIPE_STATUS (0x0024 | REGS_NORTH_PLANE_CONTROL)
#define INTEL_DISPLAY_B_PIPE_STATUS (0x1024 | REGS_NORTH_PLANE_CONTROL)
#define DISPLAY_PIPE_VBLANK_ENABLED (1UL << 17)
#define DISPLAY_PIPE_VBLANK_STATUS (1UL << 1)
@ -594,6 +630,43 @@ struct intel_free_graphics_memory {
#define INTEL_OVERLAY_GAMMA_1 0x30020
#define INTEL_OVERLAY_GAMMA_0 0x30024
// FDI - Flexible Display Interface, the interface between the (CPU-internal)
// GPU and the PCH display outputs. Proprietary interface, based on DisplayPort
// though, so similar link training and all...
// There's an FDI transmitter (TX) on the CPU and an FDI receiver (RX) on the
// PCH for each display pipe.
// FDI receiver A is hooked up to transcoder A, FDI receiver B is hooked up to
// transcoder B, so we have the same mapping as with the display pipes.
#define PCH_FDI_RX_BASE_REGISTER 0xf0000
#define PCH_FDI_RX_PIPE_OFFSET 0x01000
#define PCH_FDI_RX_CONTROL 0x0c
#define FDI_RX_CLOCK_MASK (1 << 4)
#define FDI_RX_CLOCK_RAW (0 << 4)
#define FDI_RX_CLOCK_PCD (1 << 4)
#define PCH_FDI_RX_TRANS_UNIT_SIZE_1 0x30
#define PCH_FDI_RX_TRANS_UNIT_SIZE_2 0x38
#define FDI_RX_TRANS_UNIT_SIZE(x) ((x - 1) << 25)
#define FDI_RX_TRANS_UNIT_MASK 0x7e000000
// Transfer unit size 1 is the primary and fixed transfer unit size,
// TU size 2 is the lower power state transfer unit size when using dynamic
// refresh rates (we don't do that though).
// CPU Panel Fitters - These are for IronLake and up and are the CPU internal
// panel fitters.
#define PCH_PANEL_FITTER_BASE_REGISTER 0x68000
#define PCH_PANEL_FITTER_PIPE_OFFSET 0x00800
#define PCH_PANEL_FITTER_WINDOW_POS 0x70
#define PCH_PANEL_FITTER_WINDOW_SIZE 0x74
#define PCH_PANEL_FITTER_CONTROL 0x80
#define PCH_PANEL_FITTER_V_SCALE 0x84
#define PCH_PANEL_FITTER_H_SCALE 0x90
#define PANEL_FITTER_ENABLED (1 << 31)
#define PANEL_FITTER_FILTER_MASK (3 << 23)
struct overlay_scale {
uint32 _reserved0 : 3;
uint32 horizontal_scale_fraction : 12;

View File

@ -0,0 +1,183 @@
/*
* Copyright 2011, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz, mmlr@mlotz.ch
*/
#include "DisplayPipe.h"
#include "accelerant.h"
#include "intel_extreme.h"
#include <stdlib.h>
#include <string.h>
#define TRACE_PIPE
#ifdef TRACE_PIPE
extern "C" void _sPrintf(const char* format, ...);
# define TRACE(x) _sPrintf x
#else
# define TRACE(x) ;
#endif
// #pragma mark - DisplayPipe
DisplayPipe::DisplayPipe(int32 pipeIndex)
:
fFDILink(NULL),
fPanelFitter(NULL),
fBaseRegister(INTEL_PIPE_BASE_REGISTER + pipeIndex * INTEL_PIPE_PIPE_OFFSET)
{
}
bool
DisplayPipe::IsEnabled()
{
return (read32(fBaseRegister + INTEL_PIPE_CONTROL) & PIPE_ENABLED) != 0;
}
void
DisplayPipe::Enable(const display_mode& mode)
{
_Enable(true);
}
void
DisplayPipe::Disable()
{
_Enable(false);
}
void
DisplayPipe::ConfigureTimings(const pll_divisors& divisors)
{
if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD)) {
write32(INTEL_DISPLAY_A_PLL_DIVISOR_0,
(((1 << divisors.n) << DISPLAY_PLL_N_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_N_DIVISOR_MASK)
| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_M2_DIVISOR_MASK));
} else {
write32(INTEL_DISPLAY_A_PLL_DIVISOR_0,
(((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT)
& DISPLAY_PLL_N_DIVISOR_MASK)
| (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT)
& DISPLAY_PLL_M1_DIVISOR_MASK)
| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
& DISPLAY_PLL_M2_DIVISOR_MASK));
}
uint32 pll = DISPLAY_PLL_ENABLED | DISPLAY_PLL_NO_VGA_CONTROL;
if (gInfo->shared_info->device_type.InFamily(INTEL_TYPE_9xx)) {
if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD)) {
pll |= ((1 << (divisors.post1 - 1))
<< DISPLAY_PLL_IGD_POST1_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_POST1_DIVISOR_MASK;
} else {
pll |= ((1 << (divisors.post1 - 1))
<< DISPLAY_PLL_POST1_DIVISOR_SHIFT)
& DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
// pll |= ((divisors.post1 - 1) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
// & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
}
if (divisors.post2_high)
pll |= DISPLAY_PLL_DIVIDE_HIGH;
pll |= DISPLAY_PLL_MODE_ANALOG;
if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_96x))
pll |= 6 << DISPLAY_PLL_PULSE_PHASE_SHIFT;
} else {
if (!divisors.post2_high)
pll |= DISPLAY_PLL_DIVIDE_4X;
pll |= DISPLAY_PLL_2X_CLOCK;
if (divisors.post1 > 2) {
pll |= ((divisors.post1 - 2) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
& DISPLAY_PLL_POST1_DIVISOR_MASK;
} else
pll |= DISPLAY_PLL_POST1_DIVIDE_2;
}
write32(INTEL_DISPLAY_A_PLL, pll);
read32(INTEL_DISPLAY_A_PLL);
spin(150);
write32(INTEL_DISPLAY_A_PLL, pll);
read32(INTEL_DISPLAY_A_PLL);
spin(150);
// update timing parameters
write32(INTEL_DISPLAY_A_HTOTAL,
((uint32)(target.timing.h_total - 1) << 16)
| ((uint32)target.timing.h_display - 1));
write32(INTEL_DISPLAY_A_HBLANK,
((uint32)(target.timing.h_total - 1) << 16)
| ((uint32)target.timing.h_display - 1));
write32(INTEL_DISPLAY_A_HSYNC,
((uint32)(target.timing.h_sync_end - 1) << 16)
| ((uint32)target.timing.h_sync_start - 1));
write32(INTEL_DISPLAY_A_VTOTAL,
((uint32)(target.timing.v_total - 1) << 16)
| ((uint32)target.timing.v_display - 1));
write32(INTEL_DISPLAY_A_VBLANK,
((uint32)(target.timing.v_total - 1) << 16)
| ((uint32)target.timing.v_display - 1));
write32(INTEL_DISPLAY_A_VSYNC,
((uint32)(target.timing.v_sync_end - 1) << 16)
| ((uint32)target.timing.v_sync_start - 1));
write32(INTEL_DISPLAY_A_IMAGE_SIZE,
((uint32)(target.virtual_width - 1) << 16)
| ((uint32)target.virtual_height - 1));
write32(INTEL_ANALOG_PORT, (read32(INTEL_ANALOG_PORT)
& ~(DISPLAY_MONITOR_POLARITY_MASK
| DISPLAY_MONITOR_VGA_POLARITY))
| ((target.timing.flags & B_POSITIVE_HSYNC) != 0
? DISPLAY_MONITOR_POSITIVE_HSYNC : 0)
| ((target.timing.flags & B_POSITIVE_VSYNC) != 0
? DISPLAY_MONITOR_POSITIVE_VSYNC : 0));
// TODO: verify the two comments below: the X driver doesn't seem to
// care about both of them!
// These two have to be set for display B, too - this obviously means
// that the second head always must adopt the color space of the first
// head.
write32(INTEL_DISPLAY_A_CONTROL, (read32(INTEL_DISPLAY_A_CONTROL)
& ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA))
| colorMode);
if ((gInfo->head_mode & HEAD_MODE_B_DIGITAL) != 0) {
write32(INTEL_DISPLAY_B_IMAGE_SIZE,
((uint32)(target.virtual_width - 1) << 16)
| ((uint32)target.virtual_height - 1));
write32(INTEL_DISPLAY_B_CONTROL, (read32(INTEL_DISPLAY_B_CONTROL)
& ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA))
| colorMode);
}
}
void
DisplayPipe::_Enable(bool enable)
{
uint32 targetRegister = fBaseRegister + INTEL_PIPE_CONTROL;
write32(targetRegister, read32(targetRegister) & ~PIPE_ENABLED
| (enable ? PIPE_ENABLED | 0));
read32(targetRegister);
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 2011, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz, mmlr@mlotz.ch
*/
#ifndef INTEL_PIPE_H
#define INTEL_PIPE_H
class FDILink;
class PanelFitter;
struct pll_divisors;
class DisplayPipe {
public:
DisplayPipe(int32 pipeIndex);
virtual ~DisplayPipe();
bool IsEnabled();
void Enable(const display_mode& mode);
void Disable();
void ConfigureTimings(
const pll_divisors& divisors);
// access to the various parts of the pipe
::FDILink* FDILink()
{ return fFDILink; }
::PanelFitter* PanelFitter()
{ return fPanelFitter; }
private:
void _Enable(bool enable);
FDILink* fFDILink;
PanelFitter* fPanelFitter;
uint32 fRegisterBase;
};
#endif // INTEL_PIPE_H

View File

@ -0,0 +1,138 @@
/*
* Copyright 2011, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz, mmlr@mlotz.ch
*/
#include "FlexibleDisplayInterface.h"
#include "accelerant.h"
#include "intel_extreme.h"
#include <stdlib.h>
#include <string.h>
#define TRACE_FDI
#ifdef TRACE_FDI
extern "C" void _sPrintf(const char* format, ...);
# define TRACE(x) _sPrintf x
#else
# define TRACE(x) ;
#endif
// #pragma mark - FDITransmitter
FDITransmitter::FDITransmitter(int32 pipeIndex)
:
fBaseRegister(PCH_FDI_TX_BASE_REGISTER + pipeIndex * PCH_FDI_TX_PIPE_OFFSET)
{
}
bool
FDITransmitter::IsPLLEnabled()
{
return (read32(fBaseRegister + PCH_FDI_TX_CONTROL) & PCH_FDI_TX_PLL_ENABLED)
!= 0;
}
void
FDITransmitter::EnablePLL()
{
uint32 targetRegister = fBaseRegister + PCH_FDI_TX_CONTROL;
uint32 value = read32(targetRegister);
if ((value & PCH_FDI_TX_PLL_ENABLED) != 0) {
// already enabled, possibly IronLake where it always is
return;
}
write32(targetRegister, value | PCH_FDI_TX_PLL_ENABLED);
read32(targetRegister);
spin(100); // warmup 10us + dmi delay 20us, be generous
}
void
FDITransmitter::DisablePLL()
{
if (gInfo->shared_info->device_type.IsGroup(INTEL_TYPE_ILK)) {
// on IronLake the FDI PLL is alaways enabled, so no point in trying...
return;
}
uint32 targetRegister = fBaseRegister + PCH_FDI_TX_CONTROL;
write32(targetRegister, read32(targetRegister) & ~PCH_FDI_TX_PLL_ENABLED);
read32(targetRegister);
spin(100);
}
// #pragma mark - FDIReceiver
FDIReceiver::FDIReceiver(int32 pipeIndex)
:
fBaseRegister(PCH_FDI_RX_BASE_REGISTER + pipeIndex * PCH_FDI_RX_PIPE_OFFSET)
{
}
bool
FDIReceiver::IsPLLEnabled()
{
return (read32(fBaseRegister + PCH_FDI_RX_CONTROL) & PCH_FDI_RX_PLL_ENABLED)
!= 0;
}
void
FDIReceiver::EnablePLL()
{
uint32 targetRegister = fBaseRegister + PCH_FDI_RX_CONTROL;
uint32 value = read32(targetRegister);
if ((value & PCH_FDI_RX_PLL_ENABLED) != 0)
return;
write32(targetRegister, value | PCH_FDI_RX_PLL_ENABLED);
read32(targetRegister);
spin(200); // warmup 10us + dmi delay 20us, be generous
}
void
FDIReceiver::DisablePLL()
{
uint32 targetRegister = fBaseRegister + PCH_FDI_RX_CONTROL;
write32(targetRegister, read32(targetRegister) & ~PCH_FDI_RX_PLL_ENABLED);
read32(targetRegister);
spin(100);
}
void
FDIReceiver::SwtichClock(bool toPCDClock)
{
uint32 targetRegister = fBaseRegister + PCH_FDI_RX_CONTROL;
write32(targetRegister, (read32(targetRegister) & ~PCH_FDI_RX_CLOCK_MASK)
| (toPCDClock ? PCH_FDI_RX_CLOCK_PCD : PCH_FDI_RX_CLOCK_RAW));
read32(targetRegister);
spin(200);
}
// #pragma mark - FDILink
FDILink::FDILink(int32 pipeIndex)
:
fTransmitter(pipeIndex),
fReceiver(pipeIndex)
{
}

View File

@ -0,0 +1,53 @@
/*
* Copyright 2011, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz, mmlr@mlotz.ch
*/
#ifndef INTEL_FDI_H
#define INTEL_FDI_H
class FDITransmitter {
public:
FDITransmitter(int32 pipeIndex);
virtual ~FDITransmitter();
bool IsPLLEnabled();
void EnablePLL();
void DisablePLL();
private:
uint32 fRegisterBase;
};
class FDIReceiver {
public:
FDIReceiver(int32 pipeIndex);
bool IsPLLEnabled();
void EnablePLL();
void DisablePLL();
void SwitchClock(bool toPCDClock);
protected:
uint32 fRegisterBase;
};
class FDILink {
public:
FDILink(int32 pipeIndex);
FDITransmitter& Transmitter();
FDIReceiver& Receiver();
private:
FDITransmitter fTransmitter;
FDIReceiver fReceiver;
};
#endif // INTEL_FDI_H

View File

@ -16,5 +16,10 @@ Addon intel_extreme.accelerant :
mode.cpp
overlay.cpp
# overlay_3d_i965.cpp
: be libaccelerantscommon.a
# classes
# DisplayPipe.cpp
# FlexibleDisplayInterface.cpp
# PanelFitter.cpp
Ports.cpp
: be $(TARGET_LIBSTDC++) libaccelerantscommon.a
;

View File

@ -0,0 +1,69 @@
/*
* Copyright 2011, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz, mmlr@mlotz.ch
*/
#include "PanelFitter.h"
#include "accelerant.h"
#include "intel_extreme.h"
#include <stdlib.h>
#include <string.h>
#define TRACE_FITTER
#ifdef TRACE_FITTER
extern "C" void _sPrintf(const char* format, ...);
# define TRACE(x) _sPrintf x
#else
# define TRACE(x) ;
#endif
// #pragma mark - PanelFitter
PanelFitter::PanelFitter(int32 pipeIndex)
:
fBaseRegister(PCH_PANEL_FITTER_BASE_REGISTER
+ pipeIndex * PCH_PANEL_FITTER_PIPE_OFFSET)
{
}
bool
PanelFitter::IsEnabled()
{
return (read32(fBaseRegister + PCH_PANEL_FITTER_CONTROL)
& PANEL_FITTER_ENABLED) != 0;
}
void
PanelFitter::Enable(const display_mode& mode)
{
// TODO: program the right window size and position based on the mode
_Enable(true);
}
void
PanelFitter::Disable()
{
_Enable(false);
}
void
PanelFitter::_Enable(bool enable)
{
uint32 targetRegister = fBaseRegister + PCH_PANEL_FITTER_CONTROL;
write32(targetRegister, read32(targetRegister) & ~PANEL_FITTER_ENABLED
| (enable ? PANEL_FITTER_ENABLED | 0));
read32(targetRegister);
}

View File

@ -0,0 +1,27 @@
/*
* Copyright 2011, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz, mmlr@mlotz.ch
*/
#ifndef INTEL_FITTER_H
#define INTEL_FITTER_H
class PanelFitter {
public:
PanelFitter(int32 pipeIndex);
virtual ~PanelFitter();
bool IsEnabled();
void Enable(const display_mode& mode);
void Disable();
private:
void _Enable(bool enable);
uint32 fRegisterBase;
};
#endif // INTEL_FITTER_H

View File

@ -0,0 +1,378 @@
/*
* Copyright 2006-2015, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
* Michael Lotz, mmlr@mlotz.ch
* Alexander von Gluck IV, kallisti5@unixzen.com
*/
#include "Ports.h"
#include <Debug.h>
#include <ddc.h>
#include <stdlib.h>
#include <string.h>
#include "accelerant.h"
#include "intel_extreme.h"
#undef TRACE
#define TRACE_PORTS
#ifdef TRACE_PORTS
# define TRACE(x...) _sPrintf("intel_extreme:" x)
#else
# define TRACE(x...)
#endif
#define ERROR(x...) _sPrintf("intel_extreme: " x)
#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
Port::Port(port_index index, const char* baseName)
:
fPortIndex(index),
fPortName(NULL),
fEDIDState(B_NO_INIT)
{
char portID[2];
portID[0] = 'A' + index - INTEL_PORT_A;
portID[1] = 0;
char buffer[32];
buffer[0] = 0;
strlcat(buffer, baseName, sizeof(buffer));
strlcat(buffer, " ", sizeof(buffer));
strlcat(buffer, portID, sizeof(buffer));
fPortName = strdup(buffer);
}
Port::~Port()
{
free(fPortName);
}
bool
Port::HasEDID()
{
if (fEDIDState == B_NO_INIT)
GetEDID(NULL);
return fEDIDState == B_OK;
}
status_t
Port::GetEDID(edid1_info* edid, bool forceRead)
{
CALLED();
if (fEDIDState == B_NO_INIT || forceRead) {
TRACE("%s: trying to read EDID\n", PortName());
addr_t ddcRegister = _DDCRegister();
if (ddcRegister == 0) {
fEDIDState = B_ERROR;
return fEDIDState;
}
TRACE("%s: using register %" B_PRIx32 "\n", PortName(), ddcRegister);
i2c_bus bus;
bus.cookie = (void*)ddcRegister;
bus.set_signals = &_SetI2CSignals;
bus.get_signals = &_GetI2CSignals;
ddc2_init_timing(&bus);
fEDIDState = ddc2_read_edid1(&bus, &fEDIDInfo, NULL, NULL);
if (fEDIDState == B_OK) {
TRACE("%s: found EDID information!\n", PortName());
edid_dump(&fEDIDInfo);
}
}
if (fEDIDState != B_OK) {
TRACE("%s: no EDID information found.\n", PortName());
return fEDIDState;
}
if (edid != NULL)
memcpy(edid, &fEDIDInfo, sizeof(edid1_info));
return B_OK;
}
status_t
Port::GetPLLLimits(pll_limits& limits)
{
return B_ERROR;
}
status_t
Port::_GetI2CSignals(void* cookie, int* _clock, int* _data)
{
addr_t ioRegister = (addr_t)cookie;
uint32 value = read32(ioRegister);
*_clock = (value & I2C_CLOCK_VALUE_IN) != 0;
*_data = (value & I2C_DATA_VALUE_IN) != 0;
return B_OK;
}
status_t
Port::_SetI2CSignals(void* cookie, int clock, int data)
{
addr_t ioRegister = (addr_t)cookie;
uint32 value;
if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_83x)) {
// on these chips, the reserved values are fixed
value = 0;
} else {
// on all others, we have to preserve them manually
value = read32(ioRegister) & I2C_RESERVED;
}
if (data != 0)
value |= I2C_DATA_DIRECTION_MASK;
else {
value |= I2C_DATA_DIRECTION_MASK | I2C_DATA_DIRECTION_OUT
| I2C_DATA_VALUE_MASK;
}
if (clock != 0)
value |= I2C_CLOCK_DIRECTION_MASK;
else {
value |= I2C_CLOCK_DIRECTION_MASK | I2C_CLOCK_DIRECTION_OUT
| I2C_CLOCK_VALUE_MASK;
}
write32(ioRegister, value);
read32(ioRegister);
// make sure the PCI bus has flushed the write
return B_OK;
}
// #pragma mark - Analog Port
AnalogPort::AnalogPort()
:
Port(INTEL_PORT_A, "Analog")
{
}
bool
AnalogPort::IsConnected()
{
return HasEDID();
}
uint32
AnalogPort::_DDCRegister()
{
// always fixed
return INTEL_I2C_IO_A;
}
// #pragma mark - LVDS Panel
LVDSPort::LVDSPort()
:
Port(INTEL_PORT_C, "LVDS")
{
}
bool
LVDSPort::IsConnected()
{
uint32 registerValue = read32(INTEL_DIGITAL_LVDS_PORT);
if (gInfo->shared_info->device_type.HasPlatformControlHub()) {
// there's a detection bit we can use
if ((registerValue & PCH_LVDS_DETECTED) == 0)
return false;
}
// Try getting EDID, as the LVDS port doesn't overlap with anything else,
// we don't run the risk of getting someone else's data.
return HasEDID();
}
uint32
LVDSPort::_DDCRegister()
{
// always fixed
return INTEL_I2C_IO_C;
}
// #pragma mark - DVI/SDVO/generic
DigitalPort::DigitalPort(port_index index, const char* baseName)
:
Port(index, baseName)
{
}
bool
DigitalPort::IsConnected()
{
// As this port overlaps with pretty much everything, this must be called
// after having ruled out all other port types.
return HasEDID();
}
uint32
DigitalPort::_DDCRegister()
{
switch (PortIndex()) {
case INTEL_PORT_B:
return INTEL_I2C_IO_E;
case INTEL_PORT_C:
return INTEL_I2C_IO_D;
case INTEL_PORT_D:
return INTEL_I2C_IO_F;
default:
return 0;
}
return 0;
}
// #pragma mark - HDMI
HDMIPort::HDMIPort(port_index index)
:
DigitalPort(index, "HDMI")
{
}
bool
HDMIPort::IsConnected()
{
if (!gInfo->shared_info->device_type.SupportsHDMI())
return false;
uint32 portRegister = _PortRegister();
if (portRegister == 0)
return false;
if (!gInfo->shared_info->device_type.HasPlatformControlHub()
&& PortIndex() == INTEL_PORT_C) {
// there's no detection bit on this port
} else if ((read32(portRegister) & PORT_DETECTED) == 0)
return false;
return HasEDID();
}
uint32
HDMIPort::_PortRegister()
{
// on PCH there's an additional port sandwiched in
bool hasPCH = gInfo->shared_info->device_type.HasPlatformControlHub();
switch (PortIndex()) {
case INTEL_PORT_B:
return hasPCH ? PCH_HDMI_PORT_B : INTEL_HDMI_PORT_B;
case INTEL_PORT_C:
return hasPCH ? PCH_HDMI_PORT_C : INTEL_HDMI_PORT_C;
case INTEL_PORT_D:
return hasPCH ? PCH_HDMI_PORT_D : 0;
default:
return 0;
}
return 0;
}
// #pragma mark - DisplayPort
DisplayPort::DisplayPort(port_index index, const char* baseName)
:
DigitalPort(index, baseName)
{
}
bool
DisplayPort::IsConnected()
{
uint32 portRegister = _PortRegister();
if (portRegister == 0)
return false;
if ((read32(portRegister) & PORT_DETECTED) == 0)
return false;
return HasEDID();
}
uint32
DisplayPort::_PortRegister()
{
switch (PortIndex()) {
case INTEL_PORT_A:
return INTEL_DISPLAY_PORT_A;
case INTEL_PORT_B:
return INTEL_DISPLAY_PORT_B;
case INTEL_PORT_C:
return INTEL_DISPLAY_PORT_C;
case INTEL_PORT_D:
return INTEL_DISPLAY_PORT_D;
default:
return 0;
}
return 0;
}
// #pragma mark - Embedded DisplayPort
EmbeddedDisplayPort::EmbeddedDisplayPort()
:
DisplayPort(INTEL_PORT_A, "Embedded DisplayPort")
{
}
bool
EmbeddedDisplayPort::IsConnected()
{
if (!gInfo->shared_info->device_type.IsMobile())
return false;
return DisplayPort::IsConnected();
}

View File

@ -0,0 +1,160 @@
/*
* Copyright 2011, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz, mmlr@mlotz.ch
*/
#ifndef INTEL_PORTS_H
#define INTEL_PORTS_H
#include <edid.h>
#define MAX_PORTS 20 // a generous upper bound
struct pll_limits;
enum port_type {
INTEL_PORT_TYPE_ANY, // wildcard for lookup functions
INTEL_PORT_TYPE_ANALOG,
INTEL_PORT_TYPE_DVI,
INTEL_PORT_TYPE_LVDS,
INTEL_PORT_TYPE_DP,
INTEL_PORT_TYPE_eDP,
INTEL_PORT_TYPE_HDMI
};
enum port_index {
INTEL_PORT_ANY, // wildcard for lookup functions
INTEL_PORT_A,
INTEL_PORT_B,
INTEL_PORT_C,
INTEL_PORT_D
};
class Port {
public:
Port(port_index index,
const char* baseName);
virtual ~Port();
virtual uint32 Type() const = 0;
const char* PortName() const
{ return fPortName; }
port_index PortIndex() const
{ return fPortIndex; }
virtual bool IsConnected() = 0;
bool HasEDID();
virtual status_t GetEDID(edid1_info* edid,
bool forceRead = false);
virtual status_t GetPLLLimits(pll_limits& limits);
protected:
void _SetName(const char* name);
static status_t _GetI2CSignals(void* cookie, int* _clock,
int* _data);
static status_t _SetI2CSignals(void* cookie, int clock,
int data);
private:
virtual uint32 _DDCRegister() = 0;
port_index fPortIndex;
char* fPortName;
status_t fEDIDState;
edid1_info fEDIDInfo;
};
class AnalogPort : public Port {
public:
AnalogPort();
virtual uint32 Type() const
{ return INTEL_PORT_TYPE_ANALOG; }
virtual bool IsConnected();
protected:
virtual uint32 _DDCRegister();
};
class LVDSPort : public Port {
public:
LVDSPort();
virtual uint32 Type() const
{ return INTEL_PORT_TYPE_LVDS; }
virtual bool IsConnected();
protected:
virtual uint32 _DDCRegister();
};
class DigitalPort : public Port {
public:
DigitalPort(
port_index index = INTEL_PORT_B,
const char* baseName = "DVI");
virtual uint32 Type() const
{ return INTEL_PORT_TYPE_DVI; }
virtual bool IsConnected();
protected:
virtual uint32 _DDCRegister();
};
class HDMIPort : public DigitalPort {
public:
HDMIPort(port_index index);
virtual uint32 Type() const
{ return INTEL_PORT_TYPE_HDMI; }
virtual bool IsConnected();
protected:
uint32 _PortRegister();
};
class DisplayPort : public DigitalPort {
public:
DisplayPort(port_index index,
const char* baseName = "DisplayPort");
virtual uint32 Type() const
{ return INTEL_PORT_TYPE_DP; }
virtual bool IsConnected();
protected:
uint32 _PortRegister();
};
class EmbeddedDisplayPort : public DisplayPort {
public:
EmbeddedDisplayPort();
virtual uint32 Type() const
{ return INTEL_PORT_TYPE_eDP; }
virtual bool IsConnected();
};
#endif // INTEL_PORTS_H

View File

@ -19,18 +19,20 @@
#include <unistd.h>
#include <syslog.h>
#include <new>
#include <AGP.h>
#undef TRACE
#define TRACE_ACCELERANT
#ifdef TRACE_ACCELERANT
# define TRACE(x...) _sPrintf("intel_extreme accelerant:" x)
# define TRACE(x...) _sPrintf("intel_extreme:" x)
#else
# define TRACE(x...)
#endif
#define ERROR(x...) _sPrintf("intel_extreme accelerant: " x)
#define ERROR(x...) _sPrintf("intel_extreme: " x)
#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
@ -179,6 +181,23 @@ uninit_common(void)
}
static bool
has_connected_port(port_index portIndex, uint32 type)
{
for (uint32 i = 0; i < gInfo->port_count; i++) {
Port* port = gInfo->ports[i];
if (type != INTEL_PORT_TYPE_ANY && port->Type() != type)
continue;
if (portIndex != INTEL_PORT_ANY && port->PortIndex() != portIndex)
continue;
return true;
}
return false;
}
// #pragma mark - public accelerant functions
@ -199,36 +218,91 @@ intel_init_accelerant(int device)
setup_ring_buffer(info.primary_ring_buffer, "intel primary ring buffer");
// determine head depending on what's already enabled from the BIOS
// TODO: it would be nicer to retrieve this data via DDC - else the
// display is gone for good if the BIOS decides to only show the
// picture on the connected analog monitor!
gInfo->head_mode = 0;
if (read32(INTEL_DISPLAY_B_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED)
gInfo->head_mode |= HEAD_MODE_B_DIGITAL;
if (read32(INTEL_DISPLAY_A_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED)
gInfo->head_mode |= HEAD_MODE_A_ANALOG;
TRACE("pipe control for: 0x%" B_PRIx32 " 0x%" B_PRIx32 "\n",
read32(INTEL_PIPE_CONTROL), read32(INTEL_PIPE_CONTROL));
uint32 lvds = read32(INTEL_DISPLAY_LVDS_PORT);
// Try to determine what ports to use. We use the following heuristic:
// * Check for DisplayPort, these can be more or less detected reliably.
// * Check for HDMI, it'll fail on devices not having HDMI for us to fall
// back to DVI.
// * Assume DVI B if no HDMI and no DisplayPort is present, confirmed by
// reading EDID in the IsConnected() call.
// * Check for analog if possible (there's a detection bit on PCH),
// otherwise the assumed presence is confirmed by reading EDID in
// IsConnected().
// If we have an enabled display pipe we save the passed information and
// assume it is the valid panel size..
// Later we query for proper EDID info if it exists, or figure something
// else out. (Default modes, etc.)
bool hasPCH = gInfo->shared_info->device_type.HasPlatformControlHub();
if ((hasPCH && (lvds & PCH_LVDS_DETECTED) != 0)
|| (!hasPCH && (lvds & DISPLAY_PIPE_ENABLED) != 0)) {
save_lvds_mode();
gInfo->head_mode |= HEAD_MODE_LVDS_PANEL;
gInfo->port_count = 0;
for (int i = INTEL_PORT_B; i <= INTEL_PORT_D; i++) {
Port* displayPort = new(std::nothrow) DisplayPort((port_index)i);
if (displayPort == NULL)
return B_NO_MEMORY;
if (displayPort->IsConnected())
gInfo->ports[gInfo->port_count++] = displayPort;
else
delete displayPort;
}
TRACE("head detected: %#x\n", gInfo->head_mode);
TRACE("adpa: %08" B_PRIx32 ", dova: %08" B_PRIx32 ", dovb: %08" B_PRIx32
", lvds: %08" B_PRIx32 "\n",
read32(INTEL_DISPLAY_A_ANALOG_PORT),
read32(INTEL_DISPLAY_A_DIGITAL_PORT),
read32(INTEL_DISPLAY_B_DIGITAL_PORT),
read32(INTEL_DISPLAY_LVDS_PORT));
for (int i = INTEL_PORT_B; i <= INTEL_PORT_D; i++) {
if (has_connected_port((port_index)i, INTEL_PORT_TYPE_ANY)) {
// we overlap with a DisplayPort, this is not HDMI
continue;
}
Port* hdmiPort = new(std::nothrow) HDMIPort((port_index)i);
if (hdmiPort == NULL)
return B_NO_MEMORY;
if (hdmiPort->IsConnected())
gInfo->ports[gInfo->port_count++] = hdmiPort;
else
delete hdmiPort;
}
if (!has_connected_port(INTEL_PORT_ANY, INTEL_PORT_TYPE_ANY)) {
// there's neither DisplayPort nor HDMI so far, assume DVI B
Port* dviPort = new(std::nothrow) DigitalPort(INTEL_PORT_B);
if (dviPort == NULL)
return B_NO_MEMORY;
if (dviPort->IsConnected()) {
gInfo->ports[gInfo->port_count++] = dviPort;
gInfo->head_mode |= HEAD_MODE_B_DIGITAL;
} else
delete dviPort;
}
// always try the LVDS port, it'll simply fail if not applicable
Port* lvdsPort = new(std::nothrow) LVDSPort();
if (lvdsPort == NULL)
return B_NO_MEMORY;
if (lvdsPort->IsConnected()) {
gInfo->ports[gInfo->port_count++] = lvdsPort;
gInfo->head_mode |= HEAD_MODE_LVDS_PANEL;
gInfo->head_mode |= HEAD_MODE_A_ANALOG;
} else
delete lvdsPort;
// also always try eDP, it'll also just fail if not applicable
Port* eDPPort = new(std::nothrow) EmbeddedDisplayPort();
if (eDPPort == NULL)
return B_NO_MEMORY;
if (eDPPort->IsConnected())
gInfo->ports[gInfo->port_count++] = eDPPort;
else
delete eDPPort;
// then finally always try the analog port
Port* analogPort = new(std::nothrow) AnalogPort();
if (analogPort == NULL)
return B_NO_MEMORY;
if (analogPort->IsConnected()) {
gInfo->ports[gInfo->port_count++] = analogPort;
gInfo->head_mode |= HEAD_MODE_A_ANALOG;
} else
delete analogPort;
TRACE("connected ports detected: %" B_PRIu32 "\n", gInfo->port_count);
status = create_mode_list();
if (status != B_OK) {

View File

@ -14,6 +14,8 @@
#include <edid.h>
#include <video_overlay.h>
#include "Ports.h"
struct overlay {
overlay_buffer buffer;
@ -48,6 +50,9 @@ struct accelerant_info {
uint32 last_vertical_overlay_scale;
uint32 overlay_position_buffer_offset;
uint32 port_count;
Port* ports[MAX_PORTS];
edid1_info edid_info;
bool has_edid;
@ -64,10 +69,12 @@ struct accelerant_info {
display_mode lvds_panel_mode;
};
#define HEAD_MODE_A_ANALOG 0x01
#define HEAD_MODE_B_DIGITAL 0x02
#define HEAD_MODE_CLONE 0x03
#define HEAD_MODE_LVDS_PANEL 0x08
#define HEAD_MODE_A_ANALOG 0x0001
#define HEAD_MODE_B_DIGITAL 0x0002
#define HEAD_MODE_CLONE 0x0003
#define HEAD_MODE_LVDS_PANEL 0x0008
#define HEAD_MODE_TESTING 0x1000
#define HEAD_MODE_STIPPI 0x2000
extern accelerant_info* gInfo;

View File

@ -71,22 +71,22 @@ enable_display_pipe(bool enable)
if (enable) {
if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
write32(INTEL_DISPLAY_A_PIPE_CONTROL,
pipeAControl | DISPLAY_PIPE_ENABLED);
pipeAControl | INTEL_PIPE_ENABLED);
}
if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) {
write32(INTEL_DISPLAY_B_PIPE_CONTROL,
pipeBControl | DISPLAY_PIPE_ENABLED);
pipeBControl | INTEL_PIPE_ENABLED);
}
} else {
if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
write32(INTEL_DISPLAY_A_PIPE_CONTROL,
pipeAControl & ~DISPLAY_PIPE_ENABLED);
pipeAControl & ~INTEL_PIPE_ENABLED);
}
if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) {
write32(INTEL_DISPLAY_B_PIPE_CONTROL,
pipeBControl & ~DISPLAY_PIPE_ENABLED);
pipeBControl & ~INTEL_PIPE_ENABLED);
}
}
@ -188,16 +188,15 @@ set_display_power_mode(uint32 mode)
}
if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
write32(INTEL_DISPLAY_A_ANALOG_PORT,
(read32(INTEL_DISPLAY_A_ANALOG_PORT)
write32(INTEL_ANALOG_PORT, (read32(INTEL_ANALOG_PORT)
& ~(DISPLAY_MONITOR_MODE_MASK | DISPLAY_MONITOR_PORT_ENABLED))
| monitorMode
| (mode != B_DPMS_OFF ? DISPLAY_MONITOR_PORT_ENABLED : 0));
}
if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) {
write32(INTEL_DISPLAY_B_DIGITAL_PORT,
(read32(INTEL_DISPLAY_B_DIGITAL_PORT)
& ~(DISPLAY_MONITOR_MODE_MASK | DISPLAY_MONITOR_PORT_ENABLED))
write32(INTEL_DIGITAL_PORT_B, (read32(INTEL_DIGITAL_PORT_B)
& ~(/*DISPLAY_MONITOR_MODE_MASK |*/ DISPLAY_MONITOR_PORT_ENABLED))
| (mode != B_DPMS_OFF ? DISPLAY_MONITOR_PORT_ENABLED : 0));
// TODO: monitorMode?
}

501
src/add-ons/accelerants/intel_extreme/mode.cpp Executable file → Normal file
View File

@ -1,5 +1,5 @@
/*
* Copyright 2006-2014, Haiku, Inc. All Rights Reserved.
* Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Support for i915 chipset and up based on the X driver,
@ -10,20 +10,26 @@
*/
#include "accelerant_protos.h"
#include "accelerant.h"
#include "utility.h"
#include <Debug.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <Debug.h>
#include <create_display_modes.h>
#include <ddc.h>
#include <edid.h>
#include <validate_display_mode.h>
#include "accelerant_protos.h"
#include "accelerant.h"
#if 0
#include "DisplayPipe.h"
#include "FlexibleDisplayInterface.h"
#endif
#include "Ports.h"
#include "utility.h"
#undef TRACE
#define TRACE_MODE
@ -37,23 +43,6 @@
#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
struct display_registers {
uint32 pll;
uint32 divisors;
uint32 control;
uint32 pipe_config;
uint32 horiz_total;
uint32 horiz_blank;
uint32 horiz_sync;
uint32 vert_total;
uint32 vert_blank;
uint32 vert_sync;
uint32 size;
uint32 stride;
uint32 position;
uint32 pipe_source;
};
struct pll_divisors {
uint32 post;
uint32 post1;
@ -73,64 +62,6 @@ struct pll_limits {
uint32 max_vco;
};
struct gpio_map {
const char* name;
uint32 pin;
uint32 validOn;
};
static void mode_fill_missing_bits(display_mode *, uint32);
static status_t
get_i2c_signals(void* cookie, int* _clock, int* _data)
{
uint32 ioRegister = (uint32)(addr_t)cookie;
uint32 value = read32(ioRegister);
*_clock = (value & I2C_CLOCK_VALUE_IN) != 0;
*_data = (value & I2C_DATA_VALUE_IN) != 0;
return B_OK;
}
static status_t
set_i2c_signals(void* cookie, int clock, int data)
{
uint32 ioRegister = (uint32)(addr_t)cookie;
uint32 value;
if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_83x)) {
// on these chips, the reserved values are fixed
value = 0;
} else {
// on all others, we have to preserve them manually
value = read32(ioRegister) & I2C_RESERVED;
}
if (data != 0)
value |= I2C_DATA_DIRECTION_MASK;
else {
value |= I2C_DATA_DIRECTION_MASK | I2C_DATA_DIRECTION_OUT
| I2C_DATA_VALUE_MASK;
}
if (clock != 0)
value |= I2C_CLOCK_DIRECTION_MASK;
else {
value |= I2C_CLOCK_DIRECTION_MASK | I2C_CLOCK_DIRECTION_OUT
| I2C_CLOCK_VALUE_MASK;
}
write32(ioRegister, value);
read32(ioRegister);
// make sure the PCI bus has flushed the write
return B_OK;
}
static void
get_pll_limits(pll_limits &limits)
@ -191,14 +122,16 @@ get_pll_limits(pll_limits &limits)
limits = kLimits;
}
TRACE("PLL limits, min: p %" B_PRIu32 " (p1 %" B_PRIu32 ", p2 %" B_PRIu32
"), n %" B_PRIu32 ", m %" B_PRIu32 " (m1 %" B_PRIu32 ", m2 %" B_PRIu32
")\n", limits.min.post, limits.min.post1, limits.min.post2,
limits.min.n, limits.min.m, limits.min.m1, limits.min.m2);
TRACE("PLL limits, max: p %" B_PRIu32 " (p1 %" B_PRIu32 ", p2 %" B_PRIu32
"), n %" B_PRIu32 ", m %" B_PRIu32 " (m1 %" B_PRIu32 ", m2 %" B_PRIu32
")\n", limits.max.post, limits.max.post1, limits.max.post2,
limits.max.n, limits.max.m, limits.max.m1, limits.max.m2);
TRACE("PLL limits, min: p %" B_PRId32 " (p1 %" B_PRId32 ", "
"p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " "
"(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.min.post,
limits.min.post1, limits.min.post2, limits.min.n, limits.min.m,
limits.min.m1, limits.min.m2);
TRACE("PLL limits, max: p %" B_PRId32 " (p1 %" B_PRId32 ", "
"p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " "
"(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.max.post,
limits.max.post1, limits.max.post2, limits.max.n, limits.max.m,
limits.max.m1, limits.max.m2);
}
@ -232,7 +165,7 @@ compute_pll_divisors(const display_mode &current, pll_divisors& divisors,
TRACE("%s: required MHz: %g\n", __func__, requestedPixelClock);
if (isLVDS) {
if ((read32(INTEL_DISPLAY_LVDS_PORT) & LVDS_CLKB_POWER_MASK)
if ((read32(INTEL_DIGITAL_LVDS_PORT) & LVDS_CLKB_POWER_MASK)
== LVDS_CLKB_POWER_UP)
divisors.post2 = LVDS_POST2_RATE_FAST;
else
@ -284,40 +217,15 @@ compute_pll_divisors(const display_mode &current, pll_divisors& divisors,
divisors = bestDivisors;
TRACE("%s: found: %g MHz, p = %" B_PRIu32 " (p1 = %" B_PRIu32 ", p2 = %"
B_PRIu32 "), n = %" B_PRIu32 ", m = %" B_PRIu32 " (m1 = %" B_PRIu32
", m2 = %" B_PRIu32 ")\n", __func__,
TRACE("%s: found: %g MHz, p = %" B_PRId32 " (p1 = %" B_PRId32 ", "
"p2 = %" B_PRId32 "), n = %" B_PRId32 ", m = %" B_PRId32 " "
"(m1 = %" B_PRId32 ", m2 = %" B_PRId32 ")\n", __func__,
((referenceClock * divisors.m) / divisors.n) / divisors.post,
divisors.post, divisors.post1, divisors.post2, divisors.n,
divisors.m, divisors.m1, divisors.m2);
}
static void
mode_fill_missing_bits(display_mode *mode, uint32 cntrl)
{
uint32 value = read32(cntrl);
switch (value & DISPLAY_CONTROL_COLOR_MASK) {
case DISPLAY_CONTROL_RGB32:
default:
mode->space = B_RGB32;
break;
case DISPLAY_CONTROL_RGB16:
mode->space = B_RGB16;
break;
case DISPLAY_CONTROL_RGB15:
mode->space = B_RGB15;
break;
case DISPLAY_CONTROL_CMAP8:
mode->space = B_CMAP8;
break;
}
mode->flags = B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS | B_DPMS;
}
static void
retrieve_current_mode(display_mode& mode, uint32 pllRegister)
{
@ -352,7 +260,6 @@ retrieve_current_mode(display_mode& mode, uint32 pllRegister)
controlRegister = INTEL_DISPLAY_B_CONTROL;
} else {
// TODO: not supported
TRACE("%s: pllRegister not yet supported\n", __func__);
return;
}
@ -448,13 +355,27 @@ retrieve_current_mode(display_mode& mode, uint32 pllRegister)
if (mode.virtual_height < mode.timing.v_display)
mode.virtual_height = mode.timing.v_display;
mode_fill_missing_bits(&mode, controlRegister);
value = read32(controlRegister);
switch (value & DISPLAY_CONTROL_COLOR_MASK) {
case DISPLAY_CONTROL_RGB32:
default:
mode.space = B_RGB32;
break;
case DISPLAY_CONTROL_RGB16:
mode.space = B_RGB16;
break;
case DISPLAY_CONTROL_RGB15:
mode.space = B_RGB15;
break;
case DISPLAY_CONTROL_CMAP8:
mode.space = B_CMAP8;
break;
}
mode.h_display_start = 0;
mode.v_display_start = 0;
if (gInfo->overlay_registers != NULL) {
mode.flags |= B_SUPPORTS_OVERLAYS;
}
mode.flags = B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS
| B_DPMS | B_SUPPORTS_OVERLAYS;
}
@ -502,12 +423,15 @@ sanitize_display_mode(display_mode& mode)
{
// Some cards only support even pixel counts, while others require an odd
// one.
bool olderCard = gInfo->shared_info->device_type.InGroup(INTEL_TYPE_Gxx);
olderCard |= gInfo->shared_info->device_type.InGroup(INTEL_TYPE_96x);
olderCard |= gInfo->shared_info->device_type.InGroup(INTEL_TYPE_94x);
olderCard |= gInfo->shared_info->device_type.InGroup(INTEL_TYPE_91x);
olderCard |= gInfo->shared_info->device_type.InFamily(INTEL_TYPE_8xx);
olderCard |= gInfo->shared_info->device_type.InFamily(INTEL_TYPE_7xx);
uint16 pixelCount = 1;
if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_Gxx)
|| gInfo->shared_info->device_type.InGroup(INTEL_TYPE_96x)
|| gInfo->shared_info->device_type.InGroup(INTEL_TYPE_94x)
|| gInfo->shared_info->device_type.InGroup(INTEL_TYPE_91x)
|| gInfo->shared_info->device_type.InFamily(INTEL_TYPE_8xx)
|| gInfo->shared_info->device_type.InFamily(INTEL_TYPE_7xx)) {
pixelCount = 2;
}
// TODO: verify constraints - these are more or less taken from the
// radeon driver!
@ -518,32 +442,15 @@ sanitize_display_mode(display_mode& mode)
gInfo->shared_info->pll_info.min_frequency,
gInfo->shared_info->pll_info.max_frequency,
// horizontal
{1, 0, 8160, 32, 8192, 0, 8192},
{pixelCount, 0, 8160, 32, 8192, 0, 8192},
{1, 1, 4092, 2, 63, 1, 4096}
};
if (olderCard)
constraints.horizontal_timing.resolution = 2;
return sanitize_display_mode(mode, constraints,
gInfo->has_edid ? &gInfo->edid_info : NULL);
}
static bool
check_and_sanitize_display_mode(display_mode* mode)
{
uint16 width = mode->timing.h_display;
uint16 height = mode->timing.v_display;
// Only accept the mode if it is within the supported resolution
// TODO: sanitize_display_mode() should report resolution changes
// differently!
return !sanitize_display_mode(*mode) || (width == mode->timing.h_display
&& height == mode->timing.v_display);
}
// #pragma mark -
@ -555,12 +462,12 @@ set_frame_buffer_base()
uint32 baseRegister;
uint32 surfaceRegister;
if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) {
baseRegister = INTEL_DISPLAY_B_BASE;
surfaceRegister = INTEL_DISPLAY_B_SURFACE;
} else {
if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
baseRegister = INTEL_DISPLAY_A_BASE;
surfaceRegister = INTEL_DISPLAY_A_SURFACE;
} else {
baseRegister = INTEL_DISPLAY_B_BASE;
surfaceRegister = INTEL_DISPLAY_B_SURFACE;
}
if (sharedInfo.device_type.InGroup(INTEL_TYPE_96x)
@ -568,7 +475,7 @@ set_frame_buffer_base()
|| sharedInfo.device_type.InGroup(INTEL_TYPE_ILK)
|| sharedInfo.device_type.InGroup(INTEL_TYPE_SNB)
|| sharedInfo.device_type.InGroup(INTEL_TYPE_IVB)
|| sharedInfo.device_type.InGroup(INTEL_TYPE_VLV)) {
|| gInfo->shared_info->device_type.InGroup(INTEL_TYPE_VLV)) {
write32(baseRegister, mode.v_display_start * sharedInfo.bytes_per_row
+ mode.h_display_start * (sharedInfo.bits_per_pixel + 7) / 8);
read32(baseRegister);
@ -589,53 +496,21 @@ set_frame_buffer_base()
status_t
create_mode_list(void)
{
// TODO: We may want to choose different GPIO pin maps
// for different generations of cards... not sure
const gpio_map gpioPinMap[] = {
{"ssc", INTEL_I2C_IO_B, 0},
{"vga", INTEL_I2C_IO_A, HEAD_MODE_A_ANALOG},
{"lvds", INTEL_I2C_IO_C, HEAD_MODE_LVDS_PANEL},
{"dpc", INTEL_I2C_IO_D, 0},
{"dpb", INTEL_I2C_IO_E, 0},
{"dpd", INTEL_I2C_IO_F, 0},
};
// TODO: We may want to do extra validation on gpio validOn
// vs the HEAD_MODE_ in head_mode
for (uint32 i = 0; i < sizeof(gpioPinMap) / sizeof(gpioPinMap[0]); i++) {
i2c_bus bus;
bus.cookie = (void*)(uintptr_t)gpioPinMap[i].pin;
bus.set_signals = &set_i2c_signals;
bus.get_signals = &get_i2c_signals;
ddc2_init_timing(&bus);
status_t result = ddc2_read_edid1(&bus, &gInfo->edid_info,
NULL, NULL);
if (result != B_OK)
for (uint32 i = 0; i < gInfo->port_count; i++) {
if (gInfo->ports[i] == NULL)
continue;
TRACE("found edid data on gpio '%s'\n", gpioPinMap[i].name);
edid_dump(&gInfo->edid_info);
gInfo->has_edid = true;
if (gInfo->shared_info->single_head_locked)
gInfo->head_mode = HEAD_MODE_A_ANALOG;
// TODO: We may want to probe multiple GPIO pins here
// someday and store valid ones for multi-head support.
// For now, we break on the first valid one.
break;
status_t status = gInfo->ports[i]->GetEDID(&gInfo->edid_info);
if (status == B_OK)
gInfo->has_edid = true;
}
if (!gInfo->has_edid) {
// 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)
|| ((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0
&& gInfo->shared_info->got_vbt)) {
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);
@ -643,27 +518,10 @@ create_mode_list(void)
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 < B_OK)
if (area < 0)
return area;
// Prefer information dumped directly from VBT, as the BIOS
// one may have display scaling, but only do this if the VBT
// resolution is higher than the BIOS one.
if (gInfo->shared_info->got_vbt
&& gInfo->shared_info->current_mode.virtual_width
>= gInfo->lvds_panel_mode.virtual_width
&& gInfo->shared_info->current_mode.virtual_height
>= gInfo->lvds_panel_mode.virtual_height) {
memcpy(list, &gInfo->shared_info->current_mode,
sizeof(display_mode));
mode_fill_missing_bits(list, INTEL_DISPLAY_B_CONTROL);
} else {
memcpy(list, &gInfo->lvds_panel_mode,
sizeof(display_mode));
if (gInfo->shared_info->got_vbt)
TRACE("intel_extreme: ignoring VBT mode.");
}
memcpy(list, &gInfo->lvds_panel_mode, sizeof(display_mode));
gInfo->mode_list_area = area;
gInfo->mode_list = list;
@ -677,8 +535,8 @@ create_mode_list(void)
display_mode* list;
uint32 count = 0;
gInfo->mode_list_area = create_display_modes("intel extreme modes",
gInfo->has_edid ? &gInfo->edid_info : NULL, NULL, 0, NULL, 0,
&check_and_sanitize_display_mode, &list, &count);
gInfo->has_edid ? &gInfo->edid_info : NULL, NULL, 0, NULL, 0, NULL,
&list, &count);
if (gInfo->mode_list_area < B_OK)
return gInfo->mode_list_area;
@ -747,7 +605,7 @@ intel_propose_display_mode(display_mode* target, const display_mode* low,
// first search for the specified mode in the list, if no mode is found
// try to fix the target mode in sanitize_display_mode
// TODO: Only sanitize_display_mode should be used. However, at the moment
// TODO: Only sanitize_display_mode should be used. However, at the moments
// the mode constraints are not optimal and do not work for all
// configurations.
for (uint32 i = 0; i < gInfo->shared_info->mode_count; i++) {
@ -774,12 +632,12 @@ intel_propose_display_mode(display_mode* target, const display_mode* low,
status_t
intel_set_display_mode(display_mode* mode)
{
if (mode == NULL)
return B_BAD_VALUE;
TRACE("%s(%" B_PRIu16 "x%" B_PRIu16 ")\n", __func__,
mode->virtual_width, mode->virtual_height);
if (mode == NULL)
return B_BAD_VALUE;
display_mode target = *mode;
// TODO: it may be acceptable to continue when using panel fitting or
@ -793,9 +651,9 @@ intel_set_display_mode(display_mode* mode)
uint32 colorMode, bytesPerRow, bitsPerPixel;
get_color_space_format(target, colorMode, bytesPerRow, bitsPerPixel);
// TODO stop here, when the requested mode is the same as the current one.
// This would avoid screen flickering when setting a mode that's already in
// place.
// TODO: do not go further if the mode is identical to the current one.
// This would avoid the screen being off when switching workspaces when they
// have the same resolution.
#if 0
static bool first = true;
@ -847,6 +705,86 @@ if (first) {
sharedInfo.frame_buffer = base;
sharedInfo.frame_buffer_offset = base - (addr_t)sharedInfo.graphics_memory;
#if 0
if ((gInfo->head_mode & HEAD_MODE_TESTING) != 0) {
// 1. Enable panel power as needed to retrieve panel configuration
// (use AUX VDD enable bit)
// skip, did detection already, might need that before that though
// 2. Enable PCH clock reference source and PCH SSC modulator,
// wait for warmup (Can be done anytime before enabling port)
// skip, most certainly already set up by bios to use other ports,
// will need for coldstart though
// 3. If enabling CPU embedded DisplayPort A: (Can be done anytime
// before enabling CPU pipe or port)
// a. Enable PCH 120MHz clock source output to CPU, wait for DMI
// latency
// b. Configure and enable CPU DisplayPort PLL in the DisplayPort A
// register, wait for warmup
// skip, not doing eDP right now, should go into
// EmbeddedDisplayPort class though
// 4. If enabling port on PCH: (Must be done before enabling CPU pipe
// or FDI)
// a. Enable PCH FDI Receiver PLL, wait for warmup plus DMI latency
// b. Switch from Rawclk to PCDclk in FDI Receiver (FDI A OR FDI B)
// c. [DevSNB] Enable CPU FDI Transmitter PLL, wait for warmup
// d. [DevILK] CPU FDI PLL is always on and does not need to be
// enabled
FDILink* link = pipe->FDILink();
if (link != NULL) {
link->Receiver().EnablePLL();
link->Receiver().SwitchClock(true);
link->Transmitter().EnablePLL();
}
// 5. Enable CPU panel fitter if needed for hires, required for VGA
// (Can be done anytime before enabling CPU pipe)
PanelFitter* fitter = pipe->PanelFitter();
if (fitter != NULL)
fitter->Enable(mode);
// 6. Configure CPU pipe timings, M/N/TU, and other pipe settings
// (Can be done anytime before enabling CPU pipe)
pll_divisors divisors;
compute_pll_divisors(target, divisors, false);
pipe->ConfigureTimings(divisors);
// 7. Enable CPU pipe
pipe->Enable();
8. Configure and enable CPU planes (VGA or hires)
9. If enabling port on PCH:
// a. Program PCH FDI Receiver TU size same as Transmitter TU size for TU error checking
// b. Train FDI
// i. Set pre-emphasis and voltage (iterate if training steps fail)
ii. Enable CPU FDI Transmitter and PCH FDI Receiver with Training Pattern 1 enabled.
iii. Wait for FDI training pattern 1 time
iv. Read PCH FDI Receiver ISR ([DevIBX-B+] IIR) for bit lock in bit 8 (retry at least once if no lock)
v. Enable training pattern 2 on CPU FDI Transmitter and PCH FDI Receiver
vi. Wait for FDI training pattern 2 time
vii. Read PCH FDI Receiver ISR ([DevIBX-B+] IIR) for symbol lock in bit 9 (retry at least once if no
lock)
viii. Enable normal pixel output on CPU FDI Transmitter and PCH FDI Receiver
ix. Wait for FDI idle pattern time for link to become active
c. Configure and enable PCH DPLL, wait for PCH DPLL warmup (Can be done anytime before enabling
PCH transcoder)
d. [DevCPT] Configure DPLL SEL to set the DPLL to transcoder mapping and enable DPLL to the
transcoder.
e. [DevCPT] Configure DPLL_CTL DPLL_HDMI_multipler.
f. Configure PCH transcoder timings, M/N/TU, and other transcoder settings (should match CPU settings).
g. [DevCPT] Configure and enable Transcoder DisplayPort Control if DisplayPort will be used
h. Enable PCH transcoder
10. Enable ports (DisplayPort must enable in training pattern 1)
11. Enable panel power through panel power sequencing
12. Wait for panel power sequencing to reach enabled steady state
13. Disable panel power override
14. If DisplayPort, complete link training
15. Enable panel backlight
}
#endif
// make sure VGA display is disabled
write32(INTEL_VGA_DISPLAY_CONTROL, VGA_DISPLAY_DISABLED);
read32(INTEL_VGA_DISPLAY_CONTROL);
@ -941,7 +879,7 @@ if (first) {
spin(150);
}
uint32 lvds = read32(INTEL_DISPLAY_LVDS_PORT) | LVDS_PORT_EN
uint32 lvds = read32(INTEL_DIGITAL_LVDS_PORT) | LVDS_PORT_EN
| LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT;
lvds |= LVDS_18BIT_DITHER;
@ -958,8 +896,8 @@ if (first) {
else
lvds &= ~(LVDS_B0B3PAIRS_POWER_UP | LVDS_CLKB_POWER_UP);
write32(INTEL_DISPLAY_LVDS_PORT, lvds);
read32(INTEL_DISPLAY_LVDS_PORT);
write32(INTEL_DIGITAL_LVDS_PORT, lvds);
read32(INTEL_DIGITAL_LVDS_PORT);
if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD)) {
write32(INTEL_DISPLAY_B_PLL_DIVISOR_0,
@ -1094,10 +1032,98 @@ if (first) {
| colorMode);
write32(INTEL_DISPLAY_B_PIPE_CONTROL,
read32(INTEL_DISPLAY_B_PIPE_CONTROL) | DISPLAY_PIPE_ENABLED);
read32(INTEL_DISPLAY_B_PIPE_CONTROL) | INTEL_PIPE_ENABLED);
read32(INTEL_DISPLAY_B_PIPE_CONTROL);
}
if ((gInfo->head_mode & HEAD_MODE_STIPPI) != 0) {
pll_divisors divisors;
compute_pll_divisors(target, divisors, false);
if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD)) {
write32(INTEL_DISPLAY_B_PLL_DIVISOR_0,
(((1 << divisors.n) << DISPLAY_PLL_N_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_N_DIVISOR_MASK)
| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_M2_DIVISOR_MASK));
} else {
write32(INTEL_DISPLAY_B_PLL_DIVISOR_0,
(((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT)
& DISPLAY_PLL_N_DIVISOR_MASK)
| (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT)
& DISPLAY_PLL_M1_DIVISOR_MASK)
| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
& DISPLAY_PLL_M2_DIVISOR_MASK));
}
uint32 pll = DISPLAY_PLL_ENABLED | DISPLAY_PLL_NO_VGA_CONTROL;
if (gInfo->shared_info->device_type.InFamily(INTEL_TYPE_9xx)) {
if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD)) {
pll |= ((1 << (divisors.post1 - 1))
<< DISPLAY_PLL_IGD_POST1_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_POST1_DIVISOR_MASK;
} else {
pll |= ((1 << (divisors.post1 - 1))
<< DISPLAY_PLL_POST1_DIVISOR_SHIFT)
& DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
// pll |= ((divisors.post1 - 1) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
// & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
}
if (divisors.post2_high)
pll |= DISPLAY_PLL_DIVIDE_HIGH;
if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_96x))
pll |= 6 << DISPLAY_PLL_PULSE_PHASE_SHIFT;
} else {
if (!divisors.post2_high)
pll |= DISPLAY_PLL_DIVIDE_4X;
pll |= DISPLAY_PLL_2X_CLOCK;
if (divisors.post1 > 2) {
pll |= ((divisors.post1 - 2) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
& DISPLAY_PLL_POST1_DIVISOR_MASK;
} else
pll |= DISPLAY_PLL_POST1_DIVIDE_2;
}
write32(INTEL_DISPLAY_B_PLL, pll);
read32(INTEL_DISPLAY_B_PLL);
spin(150);
write32(INTEL_DISPLAY_B_PLL, pll);
read32(INTEL_DISPLAY_B_PLL);
spin(150);
// update timing parameters
write32(INTEL_DISPLAY_B_HTOTAL,
((uint32)(target.timing.h_total - 1) << 16)
| ((uint32)target.timing.h_display - 1));
write32(INTEL_DISPLAY_B_HBLANK,
((uint32)(target.timing.h_total - 1) << 16)
| ((uint32)target.timing.h_display - 1));
write32(INTEL_DISPLAY_B_HSYNC,
((uint32)(target.timing.h_sync_end - 1) << 16)
| ((uint32)target.timing.h_sync_start - 1));
write32(INTEL_DISPLAY_B_VTOTAL,
((uint32)(target.timing.v_total - 1) << 16)
| ((uint32)target.timing.v_display - 1));
write32(INTEL_DISPLAY_B_VBLANK,
((uint32)(target.timing.v_total - 1) << 16)
| ((uint32)target.timing.v_display - 1));
write32(INTEL_DISPLAY_B_VSYNC,
((uint32)(target.timing.v_sync_end - 1) << 16)
| ((uint32)target.timing.v_sync_start - 1));
write32(INTEL_DISPLAY_B_IMAGE_SIZE,
((uint32)(target.virtual_width - 1) << 16)
| ((uint32)target.virtual_height - 1));
write32(INTEL_DISPLAY_B_CONTROL, (read32(INTEL_DISPLAY_B_CONTROL)
& ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA))
| colorMode);
}
if ((gInfo->head_mode & HEAD_MODE_A_ANALOG) != 0) {
pll_divisors divisors;
compute_pll_divisors(target, divisors, false);
@ -1151,9 +1177,7 @@ if (first) {
pll |= DISPLAY_PLL_POST1_DIVIDE_2;
}
// Programmer's Ref says we must allow the DPLL to "warm up" before starting the plane
// so mask its bit, wait, enable its bit
write32(INTEL_DISPLAY_A_PLL, pll & ~DISPLAY_PLL_NO_VGA_CONTROL);
write32(INTEL_DISPLAY_A_PLL, pll);
read32(INTEL_DISPLAY_A_PLL);
spin(150);
write32(INTEL_DISPLAY_A_PLL, pll);
@ -1185,8 +1209,7 @@ if (first) {
((uint32)(target.virtual_width - 1) << 16)
| ((uint32)target.virtual_height - 1));
write32(INTEL_DISPLAY_A_ANALOG_PORT,
(read32(INTEL_DISPLAY_A_ANALOG_PORT)
write32(INTEL_ANALOG_PORT, (read32(INTEL_ANALOG_PORT)
& ~(DISPLAY_MONITOR_POLARITY_MASK
| DISPLAY_MONITOR_VGA_POLARITY))
| ((target.timing.flags & B_POSITIVE_HSYNC) != 0
@ -1215,18 +1238,20 @@ if (first) {
}
}
set_display_power_mode(sharedInfo.dpms_mode);
if ((gInfo->head_mode & HEAD_MODE_TESTING) == 0) {
set_display_power_mode(sharedInfo.dpms_mode);
// Changing bytes per row seems to be ignored if the plane/pipe is turned
// off
// Changing bytes per row seems to be ignored if the plane/pipe is turned
// off
if (gInfo->head_mode & HEAD_MODE_A_ANALOG)
write32(INTEL_DISPLAY_A_BYTES_PER_ROW, bytesPerRow);
if (gInfo->head_mode & HEAD_MODE_B_DIGITAL)
write32(INTEL_DISPLAY_B_BYTES_PER_ROW, bytesPerRow);
if (gInfo->head_mode & HEAD_MODE_A_ANALOG)
write32(INTEL_DISPLAY_A_BYTES_PER_ROW, bytesPerRow);
if (gInfo->head_mode & HEAD_MODE_B_DIGITAL)
write32(INTEL_DISPLAY_B_BYTES_PER_ROW, bytesPerRow);
set_frame_buffer_base();
// triggers writing back double-buffered registers
set_frame_buffer_base();
// triggers writing back double-buffered registers
}
// update shared info
sharedInfo.bytes_per_row = bytesPerRow;

View File

@ -47,6 +47,7 @@
(*((volatile uint32*)(address)))
// PCI "Host bridge" is most cases :-)
const struct supported_device {
uint32 bridge_id;
uint32 display_id;
@ -112,6 +113,7 @@ const struct supported_device {
{0x0c00, 0x0412, INTEL_TYPE_IVBG, "Haswell Desktop"},
{0x0c04, 0x0416, INTEL_TYPE_IVBGM, "Haswell Mobile"},
{0x0d04, 0x0d26, INTEL_TYPE_IVBGM, "Haswell Mobile"},
{0x0a04, 0x0a16, INTEL_TYPE_IVBGM, "Haswell Mobile"},
// XXX: 0x0f00 only confirmed on 0x0f30, 0x0f31
{0x0f00, 0x0155, INTEL_TYPE_VLVG, "ValleyView Desktop"},
@ -374,6 +376,19 @@ determine_memory_sizes(intel_info &info, size_t &gttSize, size_t &stolenSize)
static void
set_gtt_entry(intel_info &info, uint32 offset, phys_addr_t physicalAddress)
{
if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_96x
|| (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_Gxx
|| (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_G4x
|| (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_IGD
|| (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_ILK
|| (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_VLV) {
// possible high bits are stored in the lower end
physicalAddress |= (physicalAddress >> 28) & 0x00f0;
} else if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_SNB) {
physicalAddress |= (physicalAddress >> 28) & 0x0ff0;
physicalAddress |= 0x02; // cache control, l3 cacheable
}
// TODO: this is not 64-bit safe!
write32(info.gtt_base + (offset >> GTT_PAGE_SHIFT),
(uint32)physicalAddress | GTT_ENTRY_VALID);

View File

@ -100,6 +100,7 @@ const struct supported_device {
{0x0412, INTEL_TYPE_IVBG, "Haswell Desktop"},
{0x0416, INTEL_TYPE_IVBGM, "Haswell Mobile"},
{0x0d26, INTEL_TYPE_IVBGM, "Haswell Mobile"},
{0x0a16, INTEL_TYPE_IVBGM, "Haswell Mobile"},
{0x0155, INTEL_TYPE_VLVG, "ValleyView Desktop"},
{0x0f30, INTEL_TYPE_VLVGM, "ValleyView Mobile"},