intel_extreme: More FDI training work
* IvyBridge or higher can auto-train. * Linux doesn't use this feature, however manual FDI link training is *really* complex... lets try auto-training first.
This commit is contained in:
@@ -230,6 +230,8 @@ struct intel_shared_info {
|
||||
addr_t frame_buffer;
|
||||
uint32 frame_buffer_offset;
|
||||
|
||||
uint32 fdi_link_frequency; // In Mhz
|
||||
|
||||
bool got_vbt;
|
||||
bool single_head_locked;
|
||||
|
||||
@@ -721,11 +723,15 @@ struct intel_free_graphics_memory {
|
||||
#define FDI_RX_ENABLE (1 << 31)
|
||||
#define FDI_RX_PLL_ENABLED (1 << 13)
|
||||
|
||||
#define FDI_FS_ERRC_ENABLE (1 << 27)
|
||||
#define FDI_FE_ERRC_ENABLE (1 << 26)
|
||||
|
||||
#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
|
||||
|
||||
#define FDI_RX_ENHANCE_FRAME_ENABLE (1 << 6)
|
||||
#define FDI_RX_CLOCK_MASK (1 << 4)
|
||||
#define FDI_RX_CLOCK_RAW (0 << 4)
|
||||
#define FDI_RX_CLOCK_PCD (1 << 4)
|
||||
@@ -734,8 +740,55 @@ struct intel_free_graphics_memory {
|
||||
#define PCH_FDI_TX_PIPE_OFFSET 0x01000
|
||||
#define PCH_FDI_TX_CONTROL 0x100
|
||||
#define FDI_TX_ENABLE (1 << 31)
|
||||
#define FDI_TX_ENHANCE_FRAME_ENABLE (1 << 18)
|
||||
#define FDI_TX_PLL_ENABLED (1 << 14)
|
||||
|
||||
#define FDI_PLL_BIOS_0 0x46000
|
||||
#define FDI_PLL_FB_CLOCK_MASK 0xff
|
||||
#define FDI_PLL_BIOS_1 0x46004
|
||||
#define FDI_PLL_BIOS_2 0x46008
|
||||
|
||||
#define FDI_LINK_TRAIN_PATTERN_1 (0 << 28)
|
||||
#define FDI_LINK_TRAIN_PATTERN_2 (1 << 28)
|
||||
#define FDI_LINK_TRAIN_PATTERN_IDLE (2 << 28)
|
||||
#define FDI_LINK_TRAIN_NONE (3 << 28)
|
||||
#define FDI_LINK_TRAIN_VOLTAGE_0_4V (0 << 25)
|
||||
#define FDI_LINK_TRAIN_VOLTAGE_0_6V (1 << 25)
|
||||
#define FDI_LINK_TRAIN_VOLTAGE_0_8V (2 << 25)
|
||||
#define FDI_LINK_TRAIN_VOLTAGE_1_2V (3 << 25)
|
||||
#define FDI_LINK_TRAIN_PRE_EMPHASIS_NONE (0 << 22)
|
||||
#define FDI_LINK_TRAIN_PRE_EMPHASIS_1_5X (1 << 22)
|
||||
#define FDI_LINK_TRAIN_PRE_EMPHASIS_2X (2 << 22)
|
||||
#define FDI_LINK_TRAIN_PRE_EMPHASIS_3X (3 << 22)
|
||||
|
||||
#define FDI_AUTO_TRAINING (1 << 10)
|
||||
#define FDI_AUTO_TRAIN_DONE (1 << 1)
|
||||
|
||||
// SNB A-stepping
|
||||
#define FDI_LINK_TRAIN_400MV_0DB_SNB_A (0x38 << 22)
|
||||
#define FDI_LINK_TRAIN_400MV_6DB_SNB_A (0x02 << 22)
|
||||
#define FDI_LINK_TRAIN_600MV_3_5DB_SNB_A (0x01 << 22)
|
||||
#define FDI_LINK_TRAIN_800MV_0DB_SNB_A (0x00 << 22)
|
||||
|
||||
// SNB B-stepping
|
||||
#define FDI_LINK_TRAIN_400MV_0DB_SNB_B (0x00 << 22)
|
||||
#define FDI_LINK_TRAIN_400MV_6DB_SNB_B (0x3a << 22)
|
||||
#define FDI_LINK_TRAIN_600MV_3_5DB_SNB_B (0x39 << 22)
|
||||
#define FDI_LINK_TRAIN_800MV_0DB_SNB_B (0x38 << 22)
|
||||
#define FDI_LINK_TRAIN_VOL_EMP_MASK (0x3f << 22)
|
||||
|
||||
#define FDI_LINK_TRAIN_PATTERN_1_CPT (0 << 8)
|
||||
#define FDI_LINK_TRAIN_PATTERN_2_CPT (1 << 8)
|
||||
#define FDI_LINK_TRAIN_PATTERN_IDLE_CPT (2 << 8)
|
||||
#define FDI_LINK_TRAIN_NORMAL_CPT (3 << 8)
|
||||
#define FDI_LINK_TRAIN_PATTERN_MASK_CPT (3 << 8)
|
||||
|
||||
// IvyBridge changes it up because... they hate developers?
|
||||
#define FDI_LINK_TRAIN_PATTERN_1_IVB (0 << 8)
|
||||
#define FDI_LINK_TRAIN_PATTERN_2_IVB (1 << 8)
|
||||
#define FDI_LINK_TRAIN_PATTERN_IDLE_IVB (2 << 8)
|
||||
#define FDI_LINK_TRAIN_NONE_IVB (3 << 8)
|
||||
|
||||
// CPU Panel Fitters - These are for IronLake and up and are the CPU internal
|
||||
// panel fitters.
|
||||
#define PCH_PANEL_FITTER_BASE_REGISTER 0x68000
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
/*
|
||||
* Copyright 2011, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2011-2015, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz, [email protected]
|
||||
* Alexander von Gluck IV, [email protected]
|
||||
*/
|
||||
|
||||
|
||||
@@ -216,6 +217,135 @@ FDILink::FDILink(pipe_index pipeIndex)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FDILink::Train(display_mode* target)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
uint32 bitsPerPixel;
|
||||
switch (target->space) {
|
||||
case B_RGB32_LITTLE:
|
||||
bitsPerPixel = 32;
|
||||
break;
|
||||
case B_RGB16_LITTLE:
|
||||
bitsPerPixel = 16;
|
||||
break;
|
||||
case B_RGB15_LITTLE:
|
||||
bitsPerPixel = 15;
|
||||
break;
|
||||
case B_CMAP8:
|
||||
default:
|
||||
bitsPerPixel = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
// Khz / 10. ( each output octet encoded as 10 bits.
|
||||
uint32 linkBandwidth = gInfo->shared_info->fdi_link_frequency * 1000 / 10;
|
||||
uint32 bps = target->timing.pixel_clock * bitsPerPixel * 21 / 20;
|
||||
|
||||
uint32 lanes = bps / (linkBandwidth * 8);
|
||||
|
||||
TRACE("%s: FDI Link Lanes: %" B_PRIu32 "\n", __func__, lanes);
|
||||
|
||||
// Over IVB supports AutoTraining of FDI
|
||||
if (gInfo->shared_info->device_type.Generation() >= 7)
|
||||
return _AutoTrain(lanes);
|
||||
|
||||
//return _ManualTrain(lanes);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FDILink::_ManualTrain(uint32 lanes)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
// This all needs review
|
||||
|
||||
// Enable FDI clocks
|
||||
Receiver().EnablePLL();
|
||||
Receiver().SwitchClock(true);
|
||||
Transmitter().EnablePLL();
|
||||
|
||||
ERROR("TODO: Generation 5 FDI Link Training\n");
|
||||
|
||||
// Enable pipes
|
||||
Transmitter().Enable();
|
||||
Receiver().Enable();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FDILink::_AutoTrain(uint32 lanes)
|
||||
{
|
||||
CALLED();
|
||||
uint32 txControl = Transmitter().Base() + PCH_FDI_TX_CONTROL;
|
||||
uint32 rxControl = Receiver().Base() + PCH_FDI_RX_CONTROL;
|
||||
|
||||
uint32 buffer = read32(txControl);
|
||||
buffer &= ~(7 << 19);
|
||||
buffer |= (lanes - 1) << 19;
|
||||
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB))
|
||||
buffer &= ~FDI_LINK_TRAIN_NONE_IVB;
|
||||
else
|
||||
buffer &= ~FDI_LINK_TRAIN_NONE;
|
||||
write32(txControl, buffer);
|
||||
|
||||
static const int snb_b_fdi_train_param[] = {
|
||||
FDI_LINK_TRAIN_400MV_0DB_SNB_B,
|
||||
FDI_LINK_TRAIN_400MV_6DB_SNB_B,
|
||||
FDI_LINK_TRAIN_600MV_3_5DB_SNB_B,
|
||||
FDI_LINK_TRAIN_800MV_0DB_SNB_B,
|
||||
};
|
||||
|
||||
bool trained = false;
|
||||
|
||||
for (uint32 i = 0; i < (sizeof(snb_b_fdi_train_param)
|
||||
/ sizeof(snb_b_fdi_train_param[0])); i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
buffer = read32(txControl);
|
||||
buffer |= FDI_AUTO_TRAINING;
|
||||
buffer &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
|
||||
buffer |= snb_b_fdi_train_param[i];
|
||||
write32(txControl, buffer | FDI_TX_ENABLE);
|
||||
|
||||
write32(rxControl, read32(rxControl) | FDI_RX_ENABLE);
|
||||
|
||||
spin(5);
|
||||
|
||||
buffer = read32(txControl);
|
||||
if ((buffer & FDI_AUTO_TRAIN_DONE) != 0) {
|
||||
TRACE("%s: FDI auto train complete!\n", __func__);
|
||||
trained = true;
|
||||
break;
|
||||
}
|
||||
|
||||
write32(txControl, read32(txControl) & ~FDI_TX_ENABLE);
|
||||
write32(rxControl, read32(rxControl) & ~FDI_RX_ENABLE);
|
||||
read32(rxControl);
|
||||
|
||||
spin(31);
|
||||
}
|
||||
}
|
||||
|
||||
if (!trained) {
|
||||
ERROR("%s: FDI auto train failed!\n", __func__);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// Enable ecc
|
||||
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB)) {
|
||||
write32(rxControl, read32(rxControl)
|
||||
| FDI_FS_ERRC_ENABLE | FDI_FE_ERRC_ENABLE);
|
||||
read32(rxControl);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
FDILink::~FDILink()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
/*
|
||||
* Copyright 2011, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2011-2015, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz, [email protected]
|
||||
* Alexander von Gluck IV, [email protected]
|
||||
*/
|
||||
#ifndef INTEL_FDI_H
|
||||
#define INTEL_FDI_H
|
||||
@@ -24,6 +25,9 @@ public:
|
||||
void EnablePLL();
|
||||
void DisablePLL();
|
||||
|
||||
uint32 Base()
|
||||
{ return fRegisterBase; };
|
||||
|
||||
private:
|
||||
uint32 fRegisterBase;
|
||||
};
|
||||
@@ -43,6 +47,9 @@ public:
|
||||
|
||||
void SwitchClock(bool toPCDClock);
|
||||
|
||||
uint32 Base()
|
||||
{ return fRegisterBase; };
|
||||
|
||||
protected:
|
||||
uint32 fRegisterBase;
|
||||
};
|
||||
@@ -58,7 +65,12 @@ public:
|
||||
FDIReceiver& Receiver()
|
||||
{ return fReceiver; };
|
||||
|
||||
status_t Train(display_mode* target);
|
||||
|
||||
private:
|
||||
status_t _ManualTrain(uint32 lanes);
|
||||
status_t _AutoTrain(uint32 lanes);
|
||||
|
||||
FDITransmitter fTransmitter;
|
||||
FDIReceiver fReceiver;
|
||||
};
|
||||
|
||||
@@ -262,11 +262,8 @@ AnalogPort::SetDisplayMode(display_mode* target, uint32 colorMode)
|
||||
|
||||
// Train FDI if it exists
|
||||
FDILink* link = fDisplayPipe->FDI();
|
||||
if (link != NULL) {
|
||||
link->Receiver().EnablePLL();
|
||||
link->Receiver().SwitchClock(true);
|
||||
link->Transmitter().EnablePLL();
|
||||
}
|
||||
if (link != NULL)
|
||||
link->Train(target);
|
||||
|
||||
pll_divisors divisors;
|
||||
compute_pll_divisors(target, &divisors, false);
|
||||
@@ -677,11 +674,8 @@ DigitalPort::SetDisplayMode(display_mode* target, uint32 colorMode)
|
||||
|
||||
// Train FDI if it exists
|
||||
FDILink* link = fDisplayPipe->FDI();
|
||||
if (link != NULL) {
|
||||
link->Receiver().EnablePLL();
|
||||
link->Receiver().SwitchClock(true);
|
||||
link->Transmitter().EnablePLL();
|
||||
}
|
||||
if (link != NULL)
|
||||
link->Train(target);
|
||||
|
||||
pll_divisors divisors;
|
||||
compute_pll_divisors(target, &divisors, false);
|
||||
|
||||
@@ -472,6 +472,18 @@ intel_extreme_init(intel_info &info)
|
||||
|
||||
init_interrupt_handler(info);
|
||||
|
||||
if (info.device_type.HasPlatformControlHub()) {
|
||||
if (info.device_type.Generation() == 5) {
|
||||
info.shared_info->fdi_link_frequency = (read32(info, FDI_PLL_BIOS_0)
|
||||
& FDI_PLL_FB_CLOCK_MASK) + 2;
|
||||
info.shared_info->fdi_link_frequency *= 100;
|
||||
} else {
|
||||
info.shared_info->fdi_link_frequency = 2700;
|
||||
}
|
||||
} else {
|
||||
info.shared_info->fdi_link_frequency = 0;
|
||||
}
|
||||
|
||||
TRACE("%s: completed successfully!\n", __func__);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user