* reformulate display and connector storage to match AtomBIOS requirements

* each active gDisplay references a gConnector index
* add atombios DAC sense.. this really won't be the main call used...
  AtomBIOS expects you to attempt an EDID read to detect connected displays
* remove old manual DACSense
* next we attempt to add ddc / edid


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42705 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Alexander von Gluck IV
2011-09-01 15:27:57 +00:00
parent 67eb6cdee8
commit e53d637520
7 changed files with 174 additions and 164 deletions
@@ -141,7 +141,7 @@ struct pll_info {
typedef struct {
bool valid;
uint16 line_mux;
uint16 devices;
uint16 connector_flags;
uint32 connector_type;
uint16 connector_object_id;
uint32 encoder_type;
@@ -153,8 +153,7 @@ typedef struct {
typedef struct {
bool active;
uint32 connection_type;
uint8 connection_id;
uint32 connector_index; // matches connector id in connector_info
register_info *regs;
bool found_ranges;
uint32 vfreq_max;
+58 -52
View File
@@ -23,69 +23,75 @@ extern "C" void _sPrintf(const char *format, ...);
bool
DACSense(uint8 dacIndex)
dac_sense(uint32 connector_id)
{
uint32 dacOffset = dacIndex == 1 ? REG_DACB_OFFSET : REG_DACA_OFFSET;
uint16 flags = gConnector[connector_id]->connector_flags;
// Backup current DAC values
uint32 compEnable = Read32(OUT, dacOffset + DACA_COMPARATOR_ENABLE);
uint32 control1 = Read32(OUT, dacOffset + DACA_CONTROL1);
uint32 control2 = Read32(OUT, dacOffset + DACA_CONTROL2);
uint32 detectControl = Read32(OUT, dacOffset + DACA_AUTODETECT_CONTROL);
uint32 enable = Read32(OUT, dacOffset + DACA_ENABLE);
if (flags & (ATOM_DEVICE_CRT_SUPPORT
| ATOM_DEVICE_CV_SUPPORT
| ATOM_DEVICE_TV_SUPPORT)) {
Write32(OUT, dacOffset + DACA_ENABLE, 1);
// Acknowledge autodetect
Write32Mask(OUT, dacOffset + DACA_AUTODETECT_INT_CONTROL, 0x01, 0x01);
Write32Mask(OUT, dacOffset + DACA_AUTODETECT_CONTROL, 0, 0x00000003);
Write32Mask(OUT, dacOffset + DACA_CONTROL2, 0, 0x00000001);
Write32Mask(OUT, dacOffset + DACA_CONTROL2, 0, 0x00ff0000);
DAC_LOAD_DETECTION_PS_ALLOCATION args;
int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection);
uint8 frev, crev;
memset(&args, 0, sizeof(args));
Write32(OUT, dacOffset + DACA_FORCE_DATA, 0);
Write32Mask(OUT, dacOffset + DACA_CONTROL2, 0x00000001, 0x0000001);
if (!atom_parse_cmd_header(gAtomContext, index, &frev, &crev))
return false;
Write32Mask(OUT, dacOffset + DACA_COMPARATOR_ENABLE,
0x00070000, 0x00070101);
Write32(OUT, dacOffset + DACA_CONTROL1, 0x00050802);
Write32Mask(OUT, dacOffset + DACA_POWERDOWN, 0, 0x00000001);
// Shutdown Bandgap voltage reference
args.sDacload.ucMisc = 0;
snooze(5);
if ((flags & ENCODER_OBJECT_ID_INTERNAL_DAC1)
|| (flags & ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1))
args.sDacload.ucDacType = ATOM_DAC_A;
else
args.sDacload.ucDacType = ATOM_DAC_B;
Write32Mask(OUT, dacOffset + DACA_POWERDOWN, 0, 0x01010100);
// Shutdown RGB
if (flags & ATOM_DEVICE_CRT1_SUPPORT) {
args.sDacload.usDeviceID
= B_HOST_TO_LENDIAN_INT16(ATOM_DEVICE_CRT1_SUPPORT);
} else if (flags & ATOM_DEVICE_CRT2_SUPPORT) {
args.sDacload.usDeviceID
= B_HOST_TO_LENDIAN_INT16(ATOM_DEVICE_CRT2_SUPPORT);
} else if (flags & ATOM_DEVICE_CV_SUPPORT) {
args.sDacload.usDeviceID
= B_HOST_TO_LENDIAN_INT16(ATOM_DEVICE_CV_SUPPORT);
if (crev >= 3)
args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
} else if (flags & ATOM_DEVICE_TV1_SUPPORT) {
args.sDacload.usDeviceID
= B_HOST_TO_LENDIAN_INT16(ATOM_DEVICE_TV1_SUPPORT);
if (crev >= 3)
args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
}
Write32(OUT, dacOffset + DACA_FORCE_DATA, 0x1e6);
// 486 out of 1024
snooze(200);
atom_execute_table(gAtomContext, index, (uint32*)&args);
Write32Mask(OUT, dacOffset + DACA_POWERDOWN, 0x01010100, 0x01010100);
// Enable RGB
snooze(88);
uint32 bios_0_scratch;
Write32Mask(OUT, dacOffset + DACA_POWERDOWN, 0, 0x01010100);
// Shutdown RGB
bios_0_scratch = Read32(OUT, R600_BIOS_0_SCRATCH);
Write32Mask(OUT, dacOffset + DACA_COMPARATOR_ENABLE,
0x00000100, 0x00000100);
snooze(100);
// Get detected RGB channels
// If only G is found, it could be a monochrome monitor, but we
// don't bother checking.
uint8 out = (Read32(OUT, dacOffset + DACA_COMPARATOR_OUTPUT) & 0x0E) >> 1;
// Restore stored DAC values
Write32Mask(OUT, dacOffset + DACA_COMPARATOR_ENABLE,
compEnable, 0x00FFFFFF);
Write32(OUT, dacOffset + DACA_CONTROL1, control1);
Write32Mask(OUT, dacOffset + DACA_CONTROL2, control2, 0x000001FF);
Write32Mask(OUT, dacOffset + DACA_AUTODETECT_CONTROL,
detectControl, 0x000000FF);
Write32Mask(OUT, dacOffset + DACA_ENABLE, enable, 0x000000FF);
return (out == 0x7);
if (flags & ATOM_DEVICE_CRT1_SUPPORT) {
if (bios_0_scratch & ATOM_S0_CRT1_MASK)
return true;
}
if (flags & ATOM_DEVICE_CRT2_SUPPORT) {
if (bios_0_scratch & ATOM_S0_CRT2_MASK)
return true;
}
if (flags & ATOM_DEVICE_CV_SUPPORT) {
if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A))
return true;
}
if (flags & ATOM_DEVICE_TV1_SUPPORT) {
if (bios_0_scratch
& (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A))
return true; /* CTV */
else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A))
return true; /* STV */
}
}
return false;
}
+1 -1
View File
@@ -22,7 +22,7 @@
#define FORMAT_TvCV 0x3
bool DACSense(uint8 dacIndex);
bool dac_sense(uint32 connector_id);
void DACGetElectrical(uint8 type, uint8 dac, uint8 *bandgap, uint8 *whitefine);
void DACSet(uint8 dacIndex, uint32 crtid);
void DACPower(uint8 dacIndex, int mode);
+84 -88
View File
@@ -197,7 +197,7 @@ detect_crt_ranges(uint32 crtid)
{
edid1_info *edid = &gInfo->shared_info->edid_info;
// TODO : VESA edid is just for primary monitor?
// TODO : use radeon ddc to get to connector EDID instead of VESA
// Scan each VESA EDID description for monitor ranges
for (uint32 index = 0; index < EDID1_NUM_DETAILED_MONITOR_DESC; index++) {
@@ -292,7 +292,7 @@ detect_connectors_legacy()
gConnector[i]->connector_type = VIDEO_CONNECTOR_VGA;
gConnector[i]->valid = true;
gConnector[i]->devices = (1 << i);
gConnector[i]->connector_flags = (1 << i);
// TODO : add the encoder
#if 0
@@ -383,8 +383,9 @@ detect_connectors()
uint32 connector_type;
uint16 connector_object_id;
uint16 connector_flags = B_LENDIAN_TO_HOST_INT16(path->usDeviceTag);
if (device_support & B_LENDIAN_TO_HOST_INT16(path->usDeviceTag)) {
if (device_support & connector_flags) {
uint8 con_obj_id = (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId)
& OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
@@ -395,8 +396,7 @@ detect_connectors()
// = (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId)
// & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
if (B_LENDIAN_TO_HOST_INT16(path->usDeviceTag)
== ATOM_DEVICE_CV_SUPPORT) {
if (connector_flags == ATOM_DEVICE_CV_SUPPORT) {
TRACE("%s: Path #%" B_PRId32 ": skipping component video.\n",
__func__, i);
continue;
@@ -465,15 +465,13 @@ detect_connectors()
}
uint32 encoder_id = (encoder_obj & OBJECT_ID_MASK)
>> OBJECT_ID_SHIFT;
uint32 encoder_support
= B_LENDIAN_TO_HOST_INT16(path->usDeviceTag);
switch(encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_LVDS:
case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
if (encoder_support
if (connector_flags
& ATOM_DEVICE_LCD_SUPPORT) {
encoder_type = VIDEO_ENCODER_LVDS;
// radeon_atombios_get_lvds_info
@@ -499,10 +497,10 @@ detect_connectors()
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
if (encoder_support
if (connector_flags
& ATOM_DEVICE_LCD_SUPPORT) {
encoder_type = VIDEO_ENCODER_LVDS;
} else if (encoder_support
} else if (connector_flags
& ATOM_DEVICE_CRT_SUPPORT) {
encoder_type = VIDEO_ENCODER_DAC;
} else {
@@ -519,10 +517,10 @@ detect_connectors()
case ENCODER_OBJECT_ID_HDMI_SI1930:
case ENCODER_OBJECT_ID_TRAVIS:
case ENCODER_OBJECT_ID_NUTMEG:
if (encoder_support
if (connector_flags
& ATOM_DEVICE_LCD_SUPPORT) {
encoder_type = VIDEO_ENCODER_LVDS;
} else if (encoder_support
} else if (connector_flags
& ATOM_DEVICE_CRT_SUPPORT) {
encoder_type = VIDEO_ENCODER_DAC;
} else {
@@ -550,6 +548,8 @@ detect_connectors()
i, decode_encoder_name(encoder_type));
gConnector[connector_index]->valid = true;
gConnector[connector_index]->connector_flags = connector_flags;
gConnector[connector_index]->connector_type = connector_type;
gConnector[connector_index]->connector_object_id
= connector_object_id;
@@ -581,52 +581,35 @@ detect_displays()
gDisplay[id]->found_ranges = false;
}
uint32 index = 0;
uint32 displayIndex = 0;
for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
if (gConnector[id]->valid == false)
continue;
if (displayIndex >= MAX_DISPLAY)
continue;
// Probe for DAC monitors connected
for (uint32 id = 0; id < 2; id++) {
if (DACSense(id)) {
gDisplay[index]->active = true;
gDisplay[index]->connection_type = ATOM_ENCODER_MODE_CRT;
gDisplay[index]->connection_id = id;
init_registers(gDisplay[index]->regs, index);
if (detect_crt_ranges(index) == B_OK)
gDisplay[index]->found_ranges = true;
if (index < MAX_DISPLAY)
index++;
else
return B_OK;
bool found = false;
switch(gConnector[id]->encoder_type) {
case VIDEO_ENCODER_DAC:
found = dac_sense(id);
break;
default:
found = false;
}
}
// Probe for TMDS monitors connected
for (uint32 id = 0; id < 1; id++) {
if (TMDSSense(id)) {
gDisplay[index]->active = true;
gDisplay[index]->connection_type = ATOM_ENCODER_MODE_DVI;
// or ATOM_ENCODER_MODE_HDMI?
gDisplay[index]->connection_id = id;
init_registers(gDisplay[index]->regs, index);
if (detect_crt_ranges(index) == B_OK)
gDisplay[index]->found_ranges = true;
if (found == true) {
gDisplay[displayIndex]->active = true;
// set this display as active
gDisplay[displayIndex]->connector_index = id;
// set physical connector index from gConnector
init_registers(gDisplay[displayIndex]->regs, displayIndex);
if (index < MAX_DISPLAY)
index++;
else
return B_OK;
if (detect_crt_ranges(displayIndex) == B_OK)
gDisplay[displayIndex]->found_ranges = true;
displayIndex++;
}
}
// No monitors? Lets assume LVDS for now
if (index == 0) {
gDisplay[index]->active = true;
gDisplay[index]->connection_type = ATOM_ENCODER_MODE_LVDS;
gDisplay[index]->connection_id = 1;
// 0 : LVDSA ; 1 : LVDSB / TDMSB
init_registers(gDisplay[index]->regs, index);
}
return B_OK;
}
@@ -639,44 +622,13 @@ debug_displays()
TRACE("Display #%" B_PRIu32 " active = %s\n",
id, gDisplay[id]->active ? "true" : "false");
if (gDisplay[id]->active) {
switch (gDisplay[id]->connection_type) {
case ATOM_ENCODER_MODE_DP:
TRACE(" + connection: DP\n");
break;
case ATOM_ENCODER_MODE_LVDS:
TRACE(" + connection: LVDS\n");
break;
case ATOM_ENCODER_MODE_DVI:
TRACE(" + connection: DVI\n");
break;
case ATOM_ENCODER_MODE_HDMI:
TRACE(" + connection: HDMI\n");
break;
case ATOM_ENCODER_MODE_SDVO:
TRACE(" + connection: SDVO\n");
break;
case ATOM_ENCODER_MODE_DP_AUDIO:
TRACE(" + connection: DP AUDIO\n");
break;
case ATOM_ENCODER_MODE_TV:
TRACE(" + connection: TV\n");
break;
case ATOM_ENCODER_MODE_CV:
TRACE(" + connection: CV\n");
break;
case ATOM_ENCODER_MODE_CRT:
TRACE(" + connection: CRT\n");
break;
case ATOM_ENCODER_MODE_DVO:
TRACE(" + connection: DVO\n");
break;
default:
TRACE(" + connection: UNKNOWN\n");
}
uint32 connector_index = gDisplay[id]->connector_index;
TRACE(" + connection index: % " B_PRIu8 "\n",
gDisplay[id]->connection_id);
if (gDisplay[id]->active) {
uint32 connector_type = gConnector[connector_index]->connector_type;
uint32 encoder_type = gConnector[connector_index]->encoder_type;
TRACE(" + connector: %s\n", decode_connector_name(connector_type));
TRACE(" + encoder: %s\n", decode_encoder_name(encoder_type));
TRACE(" + limits: Vert Min/Max: %" B_PRIu32 "/%" B_PRIu32"\n",
gDisplay[id]->vfreq_min, gDisplay[id]->vfreq_max);
@@ -689,6 +641,50 @@ debug_displays()
}
uint32
display_get_encoder_mode(uint32 connector_index)
{
uint32 connector_type = gConnector[connector_index]->connector_type;
switch (connector_type) {
case VIDEO_CONNECTOR_DVII:
case VIDEO_CONNECTOR_HDMIB: /* HDMI-B is DL-DVI; analog works fine */
// TODO : if audio detected on edid and DCE4, ATOM_ENCODER_MODE_DVI
// if audio detected on edid not DCE4, ATOM_ENCODER_MODE_HDMI
// if (gConnector[connector_index]->use_digital)
// return ATOM_ENCODER_MODE_DVI;
// else
return ATOM_ENCODER_MODE_CRT;
break;
case VIDEO_CONNECTOR_DVID:
case VIDEO_CONNECTOR_HDMIA:
default:
// TODO : if audio detected on edid and DCE4, ATOM_ENCODER_MODE_DVI
// if audio detected on edid not DCE4, ATOM_ENCODER_MODE_HDMI
return ATOM_ENCODER_MODE_DVI;
case VIDEO_CONNECTOR_LVDS:
return ATOM_ENCODER_MODE_LVDS;
case VIDEO_CONNECTOR_DP:
// dig_connector = radeon_connector->con_priv;
// if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT)
// || (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
// return ATOM_ENCODER_MODE_DP;
// }
// TODO : if audio detected on edid and DCE4, ATOM_ENCODER_MODE_DVI
// if audio detected on edid not DCE4, ATOM_ENCODER_MODE_HDMI
return ATOM_ENCODER_MODE_DVI;
case VIDEO_CONNECTOR_EDP:
return ATOM_ENCODER_MODE_DP;
case VIDEO_CONNECTOR_DVIA:
case VIDEO_CONNECTOR_VGA:
return ATOM_ENCODER_MODE_CRT;
case VIDEO_CONNECTOR_COMPOSITE:
case VIDEO_CONNECTOR_SVIDEO:
case VIDEO_CONNECTOR_9DIN:
return ATOM_ENCODER_MODE_TV;
}
}
void
display_crtc_lock(uint8 crtc_id, int command)
{
@@ -64,6 +64,7 @@ status_t detect_crt_ranges(uint32 crtid);
status_t detect_displays();
void debug_displays();
uint32 display_get_encoder_mode(uint32 connector_index);
void display_crtc_lock(uint8 crtc_id, int command);
void display_crtc_blank(uint8 crtc_id, int command);
void display_crtc_scale(uint8 crtc_id, display_mode *mode);
+24 -19
View File
@@ -109,8 +109,13 @@ radeon_set_display_mode(display_mode *mode)
continue;
}
pll_set(gDisplay[id]->connection_id,
mode->timing.pixel_clock, id);
uint32 connector_index = gDisplay[id]->connector_index;
// uint32 connector_type = gConnector[connector_index]->connector_type;
uint32 encoder_type = gConnector[connector_index]->encoder_type;
// TODO : the first id is the pll we use... this won't work for
// more then two monitors
pll_set(id, mode->timing.pixel_clock, id);
// Program CRT Controller
display_crtc_set_dtd(id, mode);
@@ -119,16 +124,16 @@ radeon_set_display_mode(display_mode *mode)
display_crtc_scale(id, mode);
// Program connector controllers
switch (gDisplay[id]->connection_type) {
case ATOM_ENCODER_MODE_CRT:
DACSet(gDisplay[id]->connection_id, id);
switch (encoder_type) {
case VIDEO_ENCODER_DAC:
case VIDEO_ENCODER_TVDAC:
// DACSet(connector_index, id);
break;
case ATOM_ENCODER_MODE_DVI:
case ATOM_ENCODER_MODE_HDMI:
TMDSSet(gDisplay[id]->connection_id, mode);
case VIDEO_ENCODER_TMDS:
// TMDSSet(connector_index, mode);
break;
case ATOM_ENCODER_MODE_LVDS:
LVDSSet(gDisplay[id]->connection_id, mode);
case VIDEO_ENCODER_LVDS:
// LVDSSet(connector_index, mode);
break;
}
@@ -139,17 +144,17 @@ radeon_set_display_mode(display_mode *mode)
//PLLPower(gDisplay[id]->connection_id, RHD_POWER_ON);
// Power connector controllers
switch (gDisplay[id]->connection_type) {
case ATOM_ENCODER_MODE_CRT:
DACPower(gDisplay[id]->connection_id, RHD_POWER_ON);
switch (encoder_type) {
case VIDEO_ENCODER_DAC:
case VIDEO_ENCODER_TVDAC:
// DACPower(connector_index, RHD_POWER_ON);
break;
case ATOM_ENCODER_MODE_DVI:
case ATOM_ENCODER_MODE_HDMI:
TMDSPower(gDisplay[id]->connection_id, RHD_POWER_ON);
case VIDEO_ENCODER_TMDS:
// TMDSPower(connector_index, RHD_POWER_ON);
break;
case ATOM_ENCODER_MODE_LVDS:
LVDSSet(gDisplay[id]->connection_id, mode);
LVDSPower(gDisplay[id]->connection_id, RHD_POWER_ON);
case VIDEO_ENCODER_LVDS:
// LVDSSet(connector_index, mode);
// LVDSPower(connector_index, RHD_POWER_ON);
break;
}
+4 -1
View File
@@ -10,6 +10,7 @@
#include "accelerant_protos.h"
#include "accelerant.h"
#include "bios.h"
#include "display.h"
#include "utility.h"
#include "pll.h"
@@ -187,6 +188,8 @@ pll_set(uint8 pll_id, uint32 pixelClock, uint8 crtc_id)
uint8 crev;
atom_parse_cmd_header(gAtomContext, index, &frev, &crev);
uint32 connector_index = gDisplay[crtc_id]->connector_index;
switch (crev) {
case 1:
args.v1.usPixelClock = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
@@ -220,7 +223,7 @@ pll_set(uint8 pll_id, uint32 pixelClock, uint8 crtc_id)
// args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC;
args.v3.ucTransmitterId = crtc_id;
// TODO : transmitter id is now CRTC id?
args.v3.ucEncoderMode = gDisplay[crtc_id]->connection_type;
args.v3.ucEncoderMode = display_get_encoder_mode(connector_index);
break;
default:
TRACE("%s: ERROR: table version %d.%d TODO\n", __func__,