diff --git a/src/add-ons/accelerants/radeon_hd/accelerant.h b/src/add-ons/accelerants/radeon_hd/accelerant.h index 1d38516c98..96edf4f794 100644 --- a/src/add-ons/accelerants/radeon_hd/accelerant.h +++ b/src/add-ons/accelerants/radeon_hd/accelerant.h @@ -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; diff --git a/src/add-ons/accelerants/radeon_hd/dac.cpp b/src/add-ons/accelerants/radeon_hd/dac.cpp index d45306b4c8..94307f2c72 100644 --- a/src/add-ons/accelerants/radeon_hd/dac.cpp +++ b/src/add-ons/accelerants/radeon_hd/dac.cpp @@ -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; } diff --git a/src/add-ons/accelerants/radeon_hd/dac.h b/src/add-ons/accelerants/radeon_hd/dac.h index 9aa34f3b8a..2176170e82 100644 --- a/src/add-ons/accelerants/radeon_hd/dac.h +++ b/src/add-ons/accelerants/radeon_hd/dac.h @@ -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); diff --git a/src/add-ons/accelerants/radeon_hd/display.cpp b/src/add-ons/accelerants/radeon_hd/display.cpp index 344bf30042..596e750068 100644 --- a/src/add-ons/accelerants/radeon_hd/display.cpp +++ b/src/add-ons/accelerants/radeon_hd/display.cpp @@ -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) { diff --git a/src/add-ons/accelerants/radeon_hd/display.h b/src/add-ons/accelerants/radeon_hd/display.h index f5a9f084ad..517a28d6f6 100644 --- a/src/add-ons/accelerants/radeon_hd/display.h +++ b/src/add-ons/accelerants/radeon_hd/display.h @@ -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); diff --git a/src/add-ons/accelerants/radeon_hd/mode.cpp b/src/add-ons/accelerants/radeon_hd/mode.cpp index c48420a011..417d7690ec 100644 --- a/src/add-ons/accelerants/radeon_hd/mode.cpp +++ b/src/add-ons/accelerants/radeon_hd/mode.cpp @@ -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; } diff --git a/src/add-ons/accelerants/radeon_hd/pll.cpp b/src/add-ons/accelerants/radeon_hd/pll.cpp index e912d1828c..5305de61a0 100644 --- a/src/add-ons/accelerants/radeon_hd/pll.cpp +++ b/src/add-ons/accelerants/radeon_hd/pll.cpp @@ -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__,