intel_extreme: skylake/DDI improvements. no resolution changing possible yet (missing DPLL code yet)
This commit is contained in:
@@ -307,7 +307,8 @@ enum pipe_index {
|
||||
INTEL_PIPE_ANY,
|
||||
INTEL_PIPE_A,
|
||||
INTEL_PIPE_B,
|
||||
INTEL_PIPE_C
|
||||
INTEL_PIPE_C,
|
||||
INTEL_PIPE_D
|
||||
};
|
||||
|
||||
//----------------- ioctl() interface ----------------
|
||||
@@ -543,6 +544,7 @@ struct intel_free_graphics_memory {
|
||||
|
||||
#define INTEL_DISPLAY_OFFSET 0x1000
|
||||
|
||||
// Note: on Skylake below registers are part of the transcoder
|
||||
#define INTEL_DISPLAY_A_HTOTAL (0x0000 | REGS_NORTH_PIPE_AND_PORT)
|
||||
#define INTEL_DISPLAY_A_HBLANK (0x0004 | REGS_NORTH_PIPE_AND_PORT)
|
||||
#define INTEL_DISPLAY_A_HSYNC (0x0008 | REGS_NORTH_PIPE_AND_PORT)
|
||||
@@ -569,6 +571,16 @@ struct intel_free_graphics_memory {
|
||||
#define INTEL_PIPE_A_LINK_N (0x0064 | REGS_NORTH_PLANE_CONTROL)
|
||||
#define INTEL_PIPE_B_LINK_N (0x1064 | REGS_NORTH_PLANE_CONTROL)
|
||||
|
||||
//DDI port link
|
||||
#define INTEL_DDI_PIPE_A_DATA_M (0x0030 | REGS_NORTH_PIPE_AND_PORT)
|
||||
#define INTEL_DDI_PIPE_B_DATA_M (0x1030 | REGS_NORTH_PIPE_AND_PORT)
|
||||
#define INTEL_DDI_PIPE_A_DATA_N (0x0034 | REGS_NORTH_PIPE_AND_PORT)
|
||||
#define INTEL_DDI_PIPE_B_DATA_N (0x1034 | REGS_NORTH_PIPE_AND_PORT)
|
||||
#define INTEL_DDI_PIPE_A_LINK_M (0x0040 | REGS_NORTH_PIPE_AND_PORT)
|
||||
#define INTEL_DDI_PIPE_B_LINK_M (0x1040 | REGS_NORTH_PIPE_AND_PORT)
|
||||
#define INTEL_DDI_PIPE_A_LINK_N (0x0044 | REGS_NORTH_PIPE_AND_PORT)
|
||||
#define INTEL_DDI_PIPE_B_LINK_N (0x1044 | REGS_NORTH_PIPE_AND_PORT)
|
||||
|
||||
// on PCH we also have to set the transcoder
|
||||
#define INTEL_TRANSCODER_A_HTOTAL (0x0000 | REGS_SOUTH_TRANSCODER_PORT)
|
||||
#define INTEL_TRANSCODER_A_HBLANK (0x0004 | REGS_SOUTH_TRANSCODER_PORT)
|
||||
@@ -661,6 +673,19 @@ struct intel_free_graphics_memory {
|
||||
#define PIPE_DDI_PORT_C 2
|
||||
#define PIPE_DDI_PORT_D 3
|
||||
#define PIPE_DDI_PORT_E 4
|
||||
#define PIPE_DDI_MODESEL_SHIFT 24
|
||||
#define PIPE_DDI_MODESEL_MODE(x) ((x) << PIPE_DDI_MODESEL_SHIFT)
|
||||
#define PIPE_DDI_MODESEL_MASK (7 << PIPE_DDI_MODESEL_SHIFT)
|
||||
#define PIPE_DDI_MODE_HDMI 0
|
||||
#define PIPE_DDI_MODE_DVI 1
|
||||
#define PIPE_DDI_MODE_DP_SST 2
|
||||
#define PIPE_DDI_MODE_DP_MST 3
|
||||
#define PIPE_DDI_DP_WIDTH_SHIFT 1
|
||||
#define PIPE_DDI_DP_WIDTH_SEL(x) ((x) << PIPE_DDI_DP_WIDTH_SHIFT)
|
||||
#define PIPE_DDI_DP_WIDTH_MASK (7 << PIPE_DDI_DP_WIDTH_SHIFT)
|
||||
#define PIPE_DDI_DP_WIDTH_1 0
|
||||
#define PIPE_DDI_DP_WIDTH_2 1
|
||||
#define PIPE_DDI_DP_WIDTH_4 2
|
||||
|
||||
// DP_A always @ 6xxxx, DP_B-DP_D move with PCH
|
||||
#define INTEL_DISPLAY_PORT_A (0x4000 | REGS_NORTH_PIPE_AND_PORT)
|
||||
@@ -992,6 +1017,12 @@ struct intel_free_graphics_memory {
|
||||
#define PCH_TRANS_CONF_B 0x1008
|
||||
#define PCH_TRANS_CONF_C 0x2008
|
||||
|
||||
// Transcoder - skylake DDI
|
||||
#define DDI_SKL_TRANS_CONF_A (0x0008 | REGS_NORTH_PLANE_CONTROL)
|
||||
#define DDI_SKL_TRANS_CONF_B (0x1008 | REGS_NORTH_PLANE_CONTROL)
|
||||
#define DDI_SKL_TRANS_CONF_C (0x2008 | REGS_NORTH_PLANE_CONTROL)
|
||||
#define DDI_SKL_TRANS_CONF_EDP (0xf008 | REGS_NORTH_PLANE_CONTROL)
|
||||
|
||||
#define TRANS_ENABLE (1 << 31)
|
||||
#define TRANS_ENABLED (1 << 30)
|
||||
|
||||
|
||||
@@ -42,6 +42,15 @@ PanelFitter::PanelFitter(pipe_index pipeIndex)
|
||||
if (pipeIndex == INTEL_PIPE_C) {
|
||||
fRegisterBase += 2 * PCH_PANEL_FITTER_PIPE_OFFSET;
|
||||
}
|
||||
TRACE("%s: requested fitter #%d\n", __func__, (int)pipeIndex);
|
||||
|
||||
uint32 fitCtl = read32(fRegisterBase + PCH_PANEL_FITTER_CONTROL);
|
||||
if (fitCtl & PANEL_FITTER_ENABLED) {
|
||||
TRACE("%s: this fitter is connected to pipe #%" B_PRIx32 "\n", __func__,
|
||||
((fitCtl & PANEL_FITTER_PIPE_MASK) >> 29) + 1);
|
||||
} else {
|
||||
TRACE("%s: this fitter is not setup by the BIOS\n", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -69,9 +69,25 @@ Pipe::Pipe(pipe_index pipeIndex)
|
||||
fPlaneOffset(0)
|
||||
{
|
||||
if (pipeIndex == INTEL_PIPE_B) {
|
||||
fPipeOffset = INTEL_DISPLAY_OFFSET;
|
||||
fPlaneOffset = INTEL_PLANE_OFFSET;
|
||||
}
|
||||
switch (pipeIndex) {
|
||||
case INTEL_PIPE_B:
|
||||
TRACE("Pipe B.\n");
|
||||
fPipeOffset = 0x1000;
|
||||
break;
|
||||
case INTEL_PIPE_C:
|
||||
TRACE("Pipe C.\n");
|
||||
fPipeOffset = 0x2000;
|
||||
break;
|
||||
case INTEL_PIPE_D:
|
||||
TRACE("Pipe D.\n");
|
||||
fPipeOffset = 0xf000;
|
||||
break;
|
||||
default:
|
||||
TRACE("Pipe A.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
// IvyBridge: Analog + Digital Ports behind FDI (on northbridge)
|
||||
// Haswell: Only VGA behind FDI (on northbridge)
|
||||
@@ -81,17 +97,18 @@ Pipe::Pipe(pipe_index pipeIndex)
|
||||
TRACE("%s: Pipe %s routed through FDI\n", __func__,
|
||||
(pipeIndex == INTEL_PIPE_A) ? "A" : "B");
|
||||
|
||||
fHasTranscoder = true;
|
||||
|
||||
// Program FDILink if PCH
|
||||
fFDILink = new(std::nothrow) FDILink(pipeIndex);
|
||||
// Program gen5(+) style panelfitter as well
|
||||
}
|
||||
if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) {
|
||||
// DDI also has transcoders
|
||||
fHasTranscoder = true;
|
||||
// Program gen5(+) style panelfitter as well (DDI has this as well..)
|
||||
fPanelFitter = new(std::nothrow) PanelFitter(pipeIndex);
|
||||
}
|
||||
|
||||
TRACE("Pipe %s. Pipe Base: 0x%" B_PRIxADDR
|
||||
" Plane Base: 0x% " B_PRIxADDR "\n", (pipeIndex == INTEL_PIPE_A)
|
||||
? "A" : "B", fPipeOffset, fPlaneOffset);
|
||||
TRACE("Pipe Base: 0x%" B_PRIxADDR " Plane Base: 0x% " B_PRIxADDR "\n",
|
||||
fPipeOffset, fPlaneOffset);
|
||||
}
|
||||
|
||||
|
||||
@@ -147,34 +164,58 @@ Pipe::_ConfigureTranscoder(display_mode* target)
|
||||
|
||||
TRACE("%s: fPipeOffset: 0x%" B_PRIx32"\n", __func__, fPipeOffset);
|
||||
|
||||
// update timing (fPipeOffset bumps the DISPLAY_A to B when needed)
|
||||
write32(INTEL_TRANSCODER_A_HTOTAL + fPipeOffset,
|
||||
((uint32)(target->timing.h_total - 1) << 16)
|
||||
| ((uint32)target->timing.h_display - 1));
|
||||
write32(INTEL_TRANSCODER_A_HBLANK + fPipeOffset,
|
||||
((uint32)(target->timing.h_total - 1) << 16)
|
||||
| ((uint32)target->timing.h_display - 1));
|
||||
write32(INTEL_TRANSCODER_A_HSYNC + fPipeOffset,
|
||||
((uint32)(target->timing.h_sync_end - 1) << 16)
|
||||
| ((uint32)target->timing.h_sync_start - 1));
|
||||
if (gInfo->shared_info->device_type.Generation() < 9) {
|
||||
// update timing (fPipeOffset bumps the DISPLAY_A to B when needed)
|
||||
write32(INTEL_TRANSCODER_A_HTOTAL + fPipeOffset,
|
||||
((uint32)(target->timing.h_total - 1) << 16)
|
||||
| ((uint32)target->timing.h_display - 1));
|
||||
write32(INTEL_TRANSCODER_A_HBLANK + fPipeOffset,
|
||||
((uint32)(target->timing.h_total - 1) << 16)
|
||||
| ((uint32)target->timing.h_display - 1));
|
||||
write32(INTEL_TRANSCODER_A_HSYNC + fPipeOffset,
|
||||
((uint32)(target->timing.h_sync_end - 1) << 16)
|
||||
| ((uint32)target->timing.h_sync_start - 1));
|
||||
|
||||
write32(INTEL_TRANSCODER_A_VTOTAL + fPipeOffset,
|
||||
((uint32)(target->timing.v_total - 1) << 16)
|
||||
| ((uint32)target->timing.v_display - 1));
|
||||
write32(INTEL_TRANSCODER_A_VBLANK + fPipeOffset,
|
||||
((uint32)(target->timing.v_total - 1) << 16)
|
||||
| ((uint32)target->timing.v_display - 1));
|
||||
write32(INTEL_TRANSCODER_A_VSYNC + fPipeOffset,
|
||||
((uint32)(target->timing.v_sync_end - 1) << 16)
|
||||
| ((uint32)target->timing.v_sync_start - 1));
|
||||
|
||||
#if 0
|
||||
// XXX: Is it ok to do these on non-digital?
|
||||
write32(INTEL_TRANSCODER_A_POS + fPipeOffset, 0);
|
||||
write32(INTEL_TRANSCODER_A_IMAGE_SIZE + fPipeOffset,
|
||||
((uint32)(target->timing.h_display - 1) << 16)
|
||||
write32(INTEL_TRANSCODER_A_VTOTAL + fPipeOffset,
|
||||
((uint32)(target->timing.v_total - 1) << 16)
|
||||
| ((uint32)target->timing.v_display - 1));
|
||||
#endif
|
||||
write32(INTEL_TRANSCODER_A_VBLANK + fPipeOffset,
|
||||
((uint32)(target->timing.v_total - 1) << 16)
|
||||
| ((uint32)target->timing.v_display - 1));
|
||||
write32(INTEL_TRANSCODER_A_VSYNC + fPipeOffset,
|
||||
((uint32)(target->timing.v_sync_end - 1) << 16)
|
||||
| ((uint32)target->timing.v_sync_start - 1));
|
||||
|
||||
#if 0
|
||||
// XXX: Is it ok to do these on non-digital?
|
||||
write32(INTEL_TRANSCODER_A_POS + fPipeOffset, 0);
|
||||
write32(INTEL_TRANSCODER_A_IMAGE_SIZE + fPipeOffset,
|
||||
((uint32)(target->timing.h_display - 1) << 16)
|
||||
| ((uint32)target->timing.v_display - 1));
|
||||
#endif
|
||||
} else {
|
||||
//on Skylake timing is already done in ConfigureTimings()
|
||||
|
||||
TRACE("%s: trans conf reg: 0x%" B_PRIx32"\n", __func__,
|
||||
read32(DDI_SKL_TRANS_CONF_A + fPipeOffset));
|
||||
TRACE("%s: trans DDI func ctl reg: 0x%" B_PRIx32"\n", __func__,
|
||||
read32(PIPE_DDI_FUNC_CTL_A + fPipeOffset));
|
||||
switch ((read32(PIPE_DDI_FUNC_CTL_A + fPipeOffset) & PIPE_DDI_MODESEL_MASK)
|
||||
>> PIPE_DDI_MODESEL_SHIFT) {
|
||||
case PIPE_DDI_MODE_DVI:
|
||||
TRACE("%s: Transcoder uses DVI mode\n", __func__);
|
||||
break;
|
||||
case PIPE_DDI_MODE_DP_SST:
|
||||
TRACE("%s: Transcoder uses DP SST mode\n", __func__);
|
||||
break;
|
||||
case PIPE_DDI_MODE_DP_MST:
|
||||
TRACE("%s: Transcoder uses DP MST mode\n", __func__);
|
||||
break;
|
||||
default:
|
||||
TRACE("%s: Transcoder uses HDMI mode\n", __func__);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -207,7 +248,8 @@ Pipe::ConfigureScalePos(display_mode* target)
|
||||
|
||||
// Set the plane size as well while we're at it (this is independant, we
|
||||
// could have a larger plane and scroll through it).
|
||||
if (gInfo->shared_info->device_type.Generation() <= 4) {
|
||||
if ((gInfo->shared_info->device_type.Generation() <= 4)
|
||||
|| gInfo->shared_info->device_type.HasDDI()) {
|
||||
// This is "reserved" on G35 and GMA965, but needed on 945 (for which
|
||||
// there is no public documentation), and I assume earlier devices as
|
||||
// well.
|
||||
@@ -240,6 +282,7 @@ Pipe::ConfigureTimings(display_mode* target, bool hardware)
|
||||
if (!fHasTranscoder || hardware)
|
||||
{
|
||||
// update timing (fPipeOffset bumps the DISPLAY_A to B when needed)
|
||||
// Note: on Skylake below registers are part of the transcoder
|
||||
write32(INTEL_DISPLAY_A_HTOTAL + fPipeOffset,
|
||||
((uint32)(target->timing.h_total - 1) << 16)
|
||||
| ((uint32)target->timing.h_display - 1));
|
||||
|
||||
@@ -126,8 +126,24 @@ Port::SetPipe(Pipe* pipe)
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
TRACE("%s: Assigning %s (0x%" B_PRIx32 ") to pipe %s\n", __func__,
|
||||
PortName(), portRegister, (pipe->Index() == INTEL_PIPE_A) ? "A" : "B");
|
||||
switch (pipe->Index()) {
|
||||
case INTEL_PIPE_B:
|
||||
TRACE("%s: Assigning %s (0x%" B_PRIx32 ") to pipe B\n", __func__,
|
||||
PortName(), portRegister);
|
||||
break;
|
||||
case INTEL_PIPE_C:
|
||||
TRACE("%s: Assigning %s (0x%" B_PRIx32 ") to pipe C\n", __func__,
|
||||
PortName(), portRegister);
|
||||
break;
|
||||
case INTEL_PIPE_D:
|
||||
TRACE("%s: Assigning %s (0x%" B_PRIx32 ") to pipe D\n", __func__,
|
||||
PortName(), portRegister);
|
||||
break;
|
||||
default:
|
||||
TRACE("%s: Assigning %s (0x%" B_PRIx32 ") to pipe A\n", __func__,
|
||||
PortName(), portRegister);
|
||||
break;
|
||||
}
|
||||
|
||||
uint32 portState = read32(portRegister);
|
||||
|
||||
@@ -257,7 +273,38 @@ Port::PipePreference()
|
||||
}
|
||||
|
||||
if (gInfo->shared_info->device_type.HasDDI()) {
|
||||
//fixme implement detection via PIPE_DDI_FUNC_CTL_x scan..
|
||||
// scan all our pipes to find the one connected to the current port
|
||||
uint32 pipeState = 0;
|
||||
for (uint32 pipeCnt = 0; pipeCnt < 4; pipeCnt++) {
|
||||
switch (pipeCnt) {
|
||||
case 0:
|
||||
pipeState = read32(PIPE_DDI_FUNC_CTL_A);
|
||||
break;
|
||||
case 1:
|
||||
pipeState = read32(PIPE_DDI_FUNC_CTL_B);
|
||||
break;
|
||||
case 2:
|
||||
pipeState = read32(PIPE_DDI_FUNC_CTL_C);
|
||||
break;
|
||||
default:
|
||||
pipeState = read32(PIPE_DDI_FUNC_CTL_EDP);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((((pipeState & PIPE_DDI_SELECT_MASK) >> PIPE_DDI_SELECT_SHIFT) + 1)
|
||||
== (uint32)PortIndex()) {
|
||||
switch (pipeCnt) {
|
||||
case 0:
|
||||
return INTEL_PIPE_A;
|
||||
case 1:
|
||||
return INTEL_PIPE_B;
|
||||
case 2:
|
||||
return INTEL_PIPE_C;
|
||||
default:
|
||||
return INTEL_PIPE_D;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return INTEL_PIPE_ANY;
|
||||
@@ -1283,11 +1330,14 @@ DigitalDisplayInterface::Power(bool enabled)
|
||||
|
||||
fPipe->Enable(enabled);
|
||||
|
||||
//nogo currently.. (kills output forever)
|
||||
#if 0
|
||||
addr_t portRegister = _PortRegister();
|
||||
uint32 state = read32(portRegister);
|
||||
write32(portRegister,
|
||||
enabled ? (state | DDI_BUF_CTL_ENABLE) : (state & ~DDI_BUF_CTL_ENABLE));
|
||||
read32(portRegister);
|
||||
#endif
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -1334,9 +1384,119 @@ DigitalDisplayInterface::IsConnected()
|
||||
TRACE("%s: %s Maximum Lanes: %" B_PRId8 "\n", __func__,
|
||||
PortName(), fMaxLanes);
|
||||
|
||||
return HasEDID();
|
||||
// fetch EDID but determine 'in use' later (below) so we also catch screens that fail EDID
|
||||
HasEDID();
|
||||
|
||||
// scan all our pipes to find the one connected to the current port and check it's enabled
|
||||
uint32 pipeState = 0;
|
||||
for (uint32 pipeCnt = 0; pipeCnt < 4; pipeCnt++) {
|
||||
switch (pipeCnt) {
|
||||
case 0:
|
||||
pipeState = read32(PIPE_DDI_FUNC_CTL_A);
|
||||
break;
|
||||
case 1:
|
||||
pipeState = read32(PIPE_DDI_FUNC_CTL_B);
|
||||
break;
|
||||
case 2:
|
||||
pipeState = read32(PIPE_DDI_FUNC_CTL_C);
|
||||
break;
|
||||
default:
|
||||
pipeState = read32(PIPE_DDI_FUNC_CTL_EDP);
|
||||
break;
|
||||
}
|
||||
|
||||
if (((((pipeState & PIPE_DDI_SELECT_MASK) >> PIPE_DDI_SELECT_SHIFT) + 1) == (uint32)PortIndex())
|
||||
&& (pipeState & PIPE_DDI_FUNC_CTL_ENABLE)) {
|
||||
TRACE("%s: Connected\n", __func__);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE("%s: Not connected\n", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
status_t
|
||||
DigitalDisplayInterface::_SetPortLinkGen8(display_mode* target)
|
||||
{
|
||||
// Khz / 10. ( each output octet encoded as 10 bits.
|
||||
//uint32 linkBandwidth = gInfo->shared_info->fdi_link_frequency * 1000 / 10; //=270000 khz
|
||||
//fixme: always so?
|
||||
uint32 linkBandwidth = 270000; //khz
|
||||
uint32 fPipeOffset = 0;
|
||||
switch (fPipe->Index()) {
|
||||
case INTEL_PIPE_B:
|
||||
fPipeOffset = 0x1000;
|
||||
break;
|
||||
case INTEL_PIPE_C:
|
||||
fPipeOffset = 0x2000;
|
||||
break;
|
||||
case INTEL_PIPE_D:
|
||||
fPipeOffset = 0xf000;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
TRACE("%s: DDI M1 data before: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_DDI_PIPE_A_DATA_M + fPipeOffset));
|
||||
TRACE("%s: DDI N1 data before: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_DDI_PIPE_A_DATA_N + fPipeOffset));
|
||||
TRACE("%s: DDI M1 link before: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_DDI_PIPE_A_LINK_M + fPipeOffset));
|
||||
TRACE("%s: DDI N1 link before: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_DDI_PIPE_A_LINK_N + fPipeOffset));
|
||||
|
||||
uint32 bitsPerPixel = 24; //fixme: always so?
|
||||
uint32 lanes = 4;
|
||||
// Only DP modes supports less than 4 lanes: read current config
|
||||
uint32 pipeFunc = read32(PIPE_DDI_FUNC_CTL_A + fPipeOffset);
|
||||
if (((pipeFunc & PIPE_DDI_MODESEL_MASK) >> PIPE_DDI_MODESEL_SHIFT) >= PIPE_DDI_MODE_DP_SST) {
|
||||
lanes = 1 << ((pipeFunc & PIPE_DDI_DP_WIDTH_MASK) >> PIPE_DDI_DP_WIDTH_SHIFT);
|
||||
TRACE("%s: DDI in DP mode with %" B_PRIx32 " lanes in use\n", __func__, lanes);
|
||||
} else {
|
||||
TRACE("%s: DDI in non-DP mode with %" B_PRIx32 " lanes in use\n", __func__, lanes);
|
||||
}
|
||||
|
||||
//Setup Data M/N
|
||||
uint64 linkspeed = lanes * linkBandwidth * 8;
|
||||
uint64 ret_n = 1;
|
||||
while(ret_n < linkspeed) {
|
||||
ret_n *= 2;
|
||||
}
|
||||
if (ret_n > 0x800000) {
|
||||
ret_n = 0x800000;
|
||||
}
|
||||
uint64 ret_m = target->timing.pixel_clock * ret_n * bitsPerPixel / linkspeed;
|
||||
while ((ret_n > 0xffffff) || (ret_m > 0xffffff)) {
|
||||
ret_m >>= 1;
|
||||
ret_n >>= 1;
|
||||
}
|
||||
//Set TU size bits (to default, max) before link training so that error detection works
|
||||
write32(INTEL_DDI_PIPE_A_DATA_M + fPipeOffset, ret_m | FDI_PIPE_MN_TU_SIZE_MASK);
|
||||
write32(INTEL_DDI_PIPE_A_DATA_N + fPipeOffset, ret_n);
|
||||
|
||||
//Setup Link M/N
|
||||
linkspeed = linkBandwidth;
|
||||
ret_n = 1;
|
||||
while(ret_n < linkspeed) {
|
||||
ret_n *= 2;
|
||||
}
|
||||
if (ret_n > 0x800000) {
|
||||
ret_n = 0x800000;
|
||||
}
|
||||
ret_m = target->timing.pixel_clock * ret_n / linkspeed;
|
||||
while ((ret_n > 0xffffff) || (ret_m > 0xffffff)) {
|
||||
ret_m >>= 1;
|
||||
ret_n >>= 1;
|
||||
}
|
||||
write32(INTEL_DDI_PIPE_A_LINK_M + fPipeOffset, ret_m);
|
||||
//Writing Link N triggers all four registers to be activated also (on next VBlank)
|
||||
write32(INTEL_DDI_PIPE_A_LINK_N + fPipeOffset, ret_n);
|
||||
|
||||
TRACE("%s: DDI M1 data after: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_DDI_PIPE_A_DATA_M + fPipeOffset));
|
||||
TRACE("%s: DDI N1 data after: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_DDI_PIPE_A_DATA_N + fPipeOffset));
|
||||
TRACE("%s: DDI M1 link after: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_DDI_PIPE_A_LINK_M + fPipeOffset));
|
||||
TRACE("%s: DDI N1 link after: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_DDI_PIPE_A_LINK_N + fPipeOffset));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t
|
||||
DigitalDisplayInterface::SetDisplayMode(display_mode* target, uint32 colorMode)
|
||||
@@ -1379,6 +1539,7 @@ DigitalDisplayInterface::SetDisplayMode(display_mode* target, uint32 colorMode)
|
||||
|
||||
// Program target display mode
|
||||
fPipe->ConfigureTimings(target);
|
||||
_SetPortLinkGen8(target);
|
||||
|
||||
// Set fCurrentMode to our set display mode
|
||||
memcpy(&fCurrentMode, target, sizeof(display_mode));
|
||||
|
||||
@@ -226,6 +226,8 @@ virtual addr_t _DDCRegister();
|
||||
virtual addr_t _PortRegister();
|
||||
private:
|
||||
uint8 fMaxLanes;
|
||||
|
||||
status_t _SetPortLinkGen8(display_mode* target);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -289,7 +289,7 @@ probe_ports()
|
||||
|
||||
// Digital Display Interface (for DP, HDMI and DVI)
|
||||
if (gInfo->shared_info->device_type.HasDDI()) {
|
||||
for (int i = INTEL_PORT_B; i <= INTEL_PORT_D; i++) {
|
||||
for (int i = INTEL_PORT_B; i <= INTEL_PORT_E; i++) {
|
||||
TRACE("Probing DDI %d\n", i);
|
||||
|
||||
Port* ddiPort
|
||||
@@ -431,7 +431,7 @@ assign_pipes()
|
||||
|
||||
pipe_index preference = gInfo->ports[i]->PipePreference();
|
||||
if (preference != INTEL_PIPE_ANY) {
|
||||
int index = (preference == INTEL_PIPE_B) ? 1 : 0;
|
||||
int index = (int)preference - 1;
|
||||
if (assigned[index]) {
|
||||
TRACE("Pipe %d is already assigned, it will drive multiple "
|
||||
"displays\n", index);
|
||||
|
||||
Reference in New Issue
Block a user