intel_extreme: Add initial work for DDI ports
This commit is contained in:
parent
3d1bd895ad
commit
ca95e9dad9
@ -162,6 +162,12 @@ struct DeviceType {
|
||||
return InFamily(INTEL_FAMILY_SER5);
|
||||
}
|
||||
|
||||
bool HasDDI() const
|
||||
{
|
||||
// Intel Digital Display Interface
|
||||
return InGroup(INTEL_GROUP_HAS) || (Generation() >= 8);
|
||||
}
|
||||
|
||||
int Generation() const
|
||||
{
|
||||
if (InFamily(INTEL_FAMILY_7xx))
|
||||
@ -542,6 +548,18 @@ struct intel_free_graphics_memory {
|
||||
#define GEN4_HDMI_PORT_C (0x1160 | REGS_SOUTH_TRANSCODER_PORT)
|
||||
#define CHV_HDMI_PORT_D (0x116C | REGS_SOUTH_TRANSCODER_PORT)
|
||||
|
||||
// DDI Buffer Control (This replaces DP on Haswell+)
|
||||
#define DDI_BUF_CTL_A (0x4000 | REGS_NORTH_PIPE_AND_PORT)
|
||||
#define DDI_BUF_CTL_B (0x4100 | REGS_NORTH_PIPE_AND_PORT)
|
||||
#define DDI_BUF_CTL_ENABLE (1 << 31)
|
||||
#define DDI_BUF_TRANS_SELECT(n) ((n) << 24)
|
||||
#define DDI_BUF_EMP_MASK (0xf << 24)
|
||||
#define DDI_BUF_PORT_REVERSAL (1 << 16)
|
||||
#define DDI_BUF_IS_IDLE (1 << 7)
|
||||
#define DDI_A_4_LANES (1 << 4)
|
||||
#define DDI_PORT_WIDTH(width) (((width) - 1) << 1)
|
||||
#define DDI_INIT_DISPLAY_DETECTED (1 << 0)
|
||||
|
||||
// DP_A always @ 6xxxx, DP_B-DP_D move with PCH
|
||||
#define INTEL_DISPLAY_PORT_A (0x4000 | REGS_NORTH_PIPE_AND_PORT)
|
||||
#define INTEL_DISPLAY_PORT_B (0x4100 | REGS_SOUTH_TRANSCODER_PORT)
|
||||
|
@ -984,3 +984,100 @@ EmbeddedDisplayPort::IsConnected()
|
||||
// No EDID? The modesetting code falls back to VBIOS panel_mode
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Digital Display Port
|
||||
|
||||
|
||||
DigitalDisplayInterface::DigitalDisplayInterface(port_index index,
|
||||
const char* baseName)
|
||||
:
|
||||
Port(index, baseName)
|
||||
{
|
||||
// As of Haswell, Intel decided to change eDP ports to a "DDI" bus...
|
||||
// on a dare because the hardware engineers were drunk one night.
|
||||
}
|
||||
|
||||
|
||||
addr_t
|
||||
DigitalDisplayInterface::_PortRegister()
|
||||
{
|
||||
switch (PortIndex()) {
|
||||
case INTEL_PORT_A:
|
||||
return DDI_BUF_CTL_A;
|
||||
case INTEL_PORT_B:
|
||||
return DDI_BUF_CTL_B;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
addr_t
|
||||
DigitalDisplayInterface::_DDCRegister()
|
||||
{
|
||||
// TODO: No idea, does DDI have DDC?
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
DigitalDisplayInterface::IsConnected()
|
||||
{
|
||||
addr_t portRegister = _PortRegister();
|
||||
|
||||
TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
|
||||
portRegister);
|
||||
|
||||
if (portRegister == 0)
|
||||
return false;
|
||||
|
||||
if ((read32(portRegister) & DDI_INIT_DISPLAY_DETECTED) == 0) {
|
||||
TRACE("%s: %s link not detected\n", __func__, PortName());
|
||||
return false;
|
||||
}
|
||||
|
||||
HasEDID();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DigitalDisplayInterface::SetDisplayMode(display_mode* target, uint32 colorMode)
|
||||
{
|
||||
TRACE("%s: %s %dx%d\n", __func__, PortName(), target->virtual_width,
|
||||
target->virtual_height);
|
||||
|
||||
if (fPipe == NULL) {
|
||||
ERROR("%s: Setting display mode without assigned pipe!\n", __func__);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// Train FDI if it exists
|
||||
FDILink* link = fPipe->FDI();
|
||||
if (link != NULL)
|
||||
link->Train(target);
|
||||
|
||||
pll_divisors divisors;
|
||||
compute_pll_divisors(target, &divisors, false);
|
||||
|
||||
uint32 extraPLLFlags = 0;
|
||||
if (gInfo->shared_info->device_type.Generation() >= 3)
|
||||
extraPLLFlags |= DISPLAY_PLL_MODE_NORMAL;
|
||||
|
||||
// Program general pipe config
|
||||
fPipe->Configure(target);
|
||||
|
||||
// Program pipe PLL's
|
||||
fPipe->ConfigureClocks(divisors, target->timing.pixel_clock, extraPLLFlags);
|
||||
|
||||
// Program target display mode
|
||||
fPipe->ConfigureTimings(target);
|
||||
|
||||
// Set fCurrentMode to our set display mode
|
||||
memcpy(&fCurrentMode, target, sizeof(display_mode));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -199,4 +199,25 @@ virtual uint32 Type() const
|
||||
virtual bool IsConnected();
|
||||
};
|
||||
|
||||
|
||||
class DigitalDisplayInterface : public Port {
|
||||
public:
|
||||
DigitalDisplayInterface(
|
||||
port_index index = INTEL_PORT_A,
|
||||
const char* baseName = "Digital Display Interface");
|
||||
|
||||
virtual uint32 Type() const
|
||||
{ return INTEL_PORT_TYPE_DVI; }
|
||||
|
||||
virtual bool IsConnected();
|
||||
|
||||
virtual status_t SetDisplayMode(display_mode* mode,
|
||||
uint32 colorMode);
|
||||
|
||||
protected:
|
||||
virtual addr_t _DDCRegister();
|
||||
virtual addr_t _PortRegister();
|
||||
};
|
||||
|
||||
|
||||
#endif // INTEL_PORTS_H
|
||||
|
@ -306,9 +306,37 @@ probe_ports()
|
||||
delete displayPort;
|
||||
}
|
||||
|
||||
// Digital Display Interface
|
||||
if (gInfo->shared_info->device_type.HasDDI()) {
|
||||
for (int i = INTEL_PORT_A; i <= INTEL_PORT_B; i++) {
|
||||
Port* ddiPort
|
||||
= new(std::nothrow) DigitalDisplayInterface((port_index)i);
|
||||
|
||||
if (ddiPort == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
if (ddiPort->IsConnected())
|
||||
gInfo->ports[gInfo->port_count++] = ddiPort;
|
||||
else
|
||||
delete ddiPort;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure DP_A isn't already taken (or DDI)
|
||||
if (!has_connected_port((port_index)INTEL_PORT_A, INTEL_PORT_TYPE_ANY)) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
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
|
||||
// Ensure port not already claimed by something like DDI
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -346,15 +374,6 @@ probe_ports()
|
||||
} 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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user