Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rework of the intel-extreme driver. Don't expect anything special yet.
- Loading branch information
Showing
27 changed files
with
3,876 additions
and
1,343 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
485 changes: 386 additions & 99 deletions
485
headers/private/graphics/intel_extreme/intel_extreme.h
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
364 changes: 364 additions & 0 deletions
364
src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,364 @@ | ||
/* | ||
* Copyright 2011-2015, Haiku, Inc. All Rights Reserved. | ||
* Distributed under the terms of the MIT License. | ||
* | ||
* Authors: | ||
* Michael Lotz, mmlr@mlotz.ch | ||
* Alexander von Gluck IV, kallisti5@unixzen.com | ||
*/ | ||
|
||
|
||
#include "FlexibleDisplayInterface.h" | ||
|
||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <Debug.h> | ||
#include <KernelExport.h> | ||
|
||
#include "accelerant.h" | ||
#include "intel_extreme.h" | ||
|
||
|
||
#undef TRACE | ||
#define TRACE_FDI | ||
#ifdef TRACE_FDI | ||
# define TRACE(x...) _sPrintf("intel_extreme: " x) | ||
#else | ||
# define TRACE(x...) | ||
#endif | ||
|
||
#define ERROR(x...) _sPrintf("intel_extreme: " x) | ||
#define CALLED() TRACE("CALLED %s\n", __PRETTY_FUNCTION__) | ||
|
||
|
||
// #pragma mark - FDITransmitter | ||
|
||
|
||
FDITransmitter::FDITransmitter(pipe_index pipeIndex) | ||
: | ||
fRegisterBase(PCH_FDI_TX_BASE_REGISTER) | ||
{ | ||
if (pipeIndex == INTEL_PIPE_B) | ||
fRegisterBase += PCH_FDI_TX_PIPE_OFFSET * 1; | ||
} | ||
|
||
|
||
FDITransmitter::~FDITransmitter() | ||
{ | ||
} | ||
|
||
|
||
void | ||
FDITransmitter::Enable() | ||
{ | ||
CALLED(); | ||
uint32 targetRegister = fRegisterBase + PCH_FDI_TX_CONTROL; | ||
uint32 value = read32(targetRegister); | ||
|
||
write32(targetRegister, value | FDI_TX_ENABLE); | ||
read32(targetRegister); | ||
spin(150); | ||
} | ||
|
||
|
||
void | ||
FDITransmitter::Disable() | ||
{ | ||
CALLED(); | ||
uint32 targetRegister = fRegisterBase + PCH_FDI_TX_CONTROL; | ||
uint32 value = read32(targetRegister); | ||
|
||
write32(targetRegister, value & ~FDI_TX_ENABLE); | ||
read32(targetRegister); | ||
spin(150); | ||
} | ||
|
||
|
||
bool | ||
FDITransmitter::IsPLLEnabled() | ||
{ | ||
CALLED(); | ||
return (read32(fRegisterBase + PCH_FDI_TX_CONTROL) & FDI_TX_PLL_ENABLED) | ||
!= 0; | ||
} | ||
|
||
|
||
void | ||
FDITransmitter::EnablePLL() | ||
{ | ||
CALLED(); | ||
uint32 targetRegister = fRegisterBase + PCH_FDI_TX_CONTROL; | ||
uint32 value = read32(targetRegister); | ||
if ((value & FDI_TX_PLL_ENABLED) != 0) { | ||
// already enabled, possibly IronLake where it always is | ||
return; | ||
} | ||
|
||
write32(targetRegister, value | FDI_TX_PLL_ENABLED); | ||
read32(targetRegister); | ||
spin(100); // warmup 10us + dmi delay 20us, be generous | ||
} | ||
|
||
|
||
void | ||
FDITransmitter::DisablePLL() | ||
{ | ||
CALLED(); | ||
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_ILK)) { | ||
// on IronLake the FDI PLL is alaways enabled, so no point in trying... | ||
return; | ||
} | ||
|
||
uint32 targetRegister = fRegisterBase + PCH_FDI_TX_CONTROL; | ||
write32(targetRegister, read32(targetRegister) & ~FDI_TX_PLL_ENABLED); | ||
read32(targetRegister); | ||
spin(100); | ||
} | ||
|
||
|
||
// #pragma mark - FDIReceiver | ||
|
||
|
||
FDIReceiver::FDIReceiver(pipe_index pipeIndex) | ||
: | ||
fRegisterBase(PCH_FDI_RX_BASE_REGISTER) | ||
{ | ||
if (pipeIndex == INTEL_PIPE_B) | ||
fRegisterBase += PCH_FDI_RX_PIPE_OFFSET * 1; | ||
} | ||
|
||
|
||
FDIReceiver::~FDIReceiver() | ||
{ | ||
} | ||
|
||
|
||
void | ||
FDIReceiver::Enable() | ||
{ | ||
CALLED(); | ||
uint32 targetRegister = fRegisterBase + PCH_FDI_RX_CONTROL; | ||
uint32 value = read32(targetRegister); | ||
|
||
write32(targetRegister, value | FDI_RX_ENABLE); | ||
read32(targetRegister); | ||
spin(150); | ||
} | ||
|
||
|
||
void | ||
FDIReceiver::Disable() | ||
{ | ||
CALLED(); | ||
uint32 targetRegister = fRegisterBase + PCH_FDI_RX_CONTROL; | ||
uint32 value = read32(targetRegister); | ||
|
||
write32(targetRegister, value & ~FDI_RX_ENABLE); | ||
read32(targetRegister); | ||
spin(150); | ||
} | ||
|
||
|
||
bool | ||
FDIReceiver::IsPLLEnabled() | ||
{ | ||
CALLED(); | ||
return (read32(fRegisterBase + PCH_FDI_RX_CONTROL) & FDI_RX_PLL_ENABLED) | ||
!= 0; | ||
} | ||
|
||
|
||
void | ||
FDIReceiver::EnablePLL() | ||
{ | ||
CALLED(); | ||
uint32 targetRegister = fRegisterBase + PCH_FDI_RX_CONTROL; | ||
uint32 value = read32(targetRegister); | ||
if ((value & FDI_RX_PLL_ENABLED) != 0) | ||
return; | ||
|
||
write32(targetRegister, value | FDI_RX_PLL_ENABLED); | ||
read32(targetRegister); | ||
spin(200); // warmup 10us + dmi delay 20us, be generous | ||
} | ||
|
||
|
||
void | ||
FDIReceiver::DisablePLL() | ||
{ | ||
CALLED(); | ||
uint32 targetRegister = fRegisterBase + PCH_FDI_RX_CONTROL; | ||
write32(targetRegister, read32(targetRegister) & ~FDI_RX_PLL_ENABLED); | ||
read32(targetRegister); | ||
spin(100); | ||
} | ||
|
||
|
||
void | ||
FDIReceiver::SwitchClock(bool toPCDClock) | ||
{ | ||
CALLED(); | ||
uint32 targetRegister = fRegisterBase + PCH_FDI_RX_CONTROL; | ||
write32(targetRegister, (read32(targetRegister) & ~FDI_RX_CLOCK_MASK) | ||
| (toPCDClock ? FDI_RX_CLOCK_PCD : FDI_RX_CLOCK_RAW)); | ||
read32(targetRegister); | ||
spin(200); | ||
} | ||
|
||
|
||
// #pragma mark - FDILink | ||
|
||
|
||
FDILink::FDILink(pipe_index pipeIndex) | ||
: | ||
fTransmitter(pipeIndex), | ||
fReceiver(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); | ||
|
||
// Enable FDI clocks | ||
Receiver().EnablePLL(); | ||
Receiver().SwitchClock(true); | ||
Transmitter().EnablePLL(); | ||
|
||
status_t result = B_ERROR; | ||
|
||
// Over IVB supports AutoTraining of FDI | ||
if (gInfo->shared_info->device_type.Generation() >= 7) { | ||
result = _AutoTrain(lanes); | ||
if (result != B_OK) { | ||
ERROR("%s: FDI auto-training fault. Attempting manual train.\n", | ||
__func__); | ||
return _ManualTrain(lanes); | ||
} | ||
return B_OK; | ||
} | ||
return _ManualTrain(lanes); | ||
} | ||
|
||
|
||
status_t | ||
FDILink::_ManualTrain(uint32 lanes) | ||
{ | ||
CALLED(); | ||
|
||
// This needs completed | ||
ERROR("TODO: Manual 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); | ||
|
||
// Clear port width selection and set number of lanes | ||
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, we fall out of autotraining | ||
if (trained) | ||
break; | ||
} | ||
|
||
if (!trained) { | ||
ERROR("%s: FDI auto train failed!\n", __func__); | ||
return B_ERROR; | ||
} | ||
|
||
// Enable ecc on IVB | ||
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() | ||
{ | ||
} |
Oops, something went wrong.