static void dp_set_tp(uint32 connectorIndex, int trainingPattern) { TRACE("%s\n", __func__); radeon_shared_info &info = *gInfo->shared_info; dp_info* dp = &gConnector[connectorIndex]->dpInfo; int rawTrainingPattern = 0; /* set training pattern on the source */ if (info.dceMajor >= 4 || !dp->trainingUseEncoder) { switch (trainingPattern) { case DP_TRAIN_PATTERN_1: rawTrainingPattern = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1; break; case DP_TRAIN_PATTERN_2: rawTrainingPattern = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2; break; case DP_TRAIN_PATTERN_3: rawTrainingPattern = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3; break; } // TODO: PixelClock 0 ok? encoder_dig_setup(connectorIndex, 0, rawTrainingPattern); } else { ERROR("%s: TODO: dp_encoder_service\n", __func__); return; #if 0 switch (trainingPattern) { case DP_TRAINING_PATTERN_1: rawTrainingPattern = 0; break; case DP_TRAINING_PATTERN_2: rawTrainingPattern = 1; break; } radeon_dp_encoder_service(dp_info->rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL, dp_info->dp_clock, dp_info->enc_id, rawTrainingPattern); #endif } // Enable training pattern on the sink dpcd_reg_write(dp->auxPin, DP_TRAIN, trainingPattern); }
status_t radeon_set_display_mode(display_mode* mode) { radeon_shared_info &info = *gInfo->shared_info; // Set mode on each display for (uint8 id = 0; id < MAX_DISPLAY; id++) { if (gDisplay[id]->attached == false) continue; uint32 connectorIndex = gDisplay[id]->connectorIndex; dp_info *dpInfo = &gConnector[connectorIndex]->dpInfo; // Determine DP lanes if DP if (connector_is_dp(connectorIndex)) dpInfo->laneCount = dp_get_lane_count(dpInfo, mode); // *** crtc and encoder prep encoder_output_lock(true); encoder_dpms_set(id, B_DPMS_OFF); display_crtc_lock(id, ATOM_ENABLE); display_crtc_dpms(id, B_DPMS_OFF); // *** Set up encoder -> crtc routing encoder_assign_crtc(id); // *** CRT controler mode set // TODO: program SS pll_set(ATOM_PPLL1, mode->timing.pixel_clock, id); // TODO: check if ATOM_PPLL1 is used and use ATOM_PPLL2 if so display_crtc_set_dtd(id, mode); display_crtc_fb_set(id, mode); // atombios_overscan_setup display_crtc_scale(id, mode); // *** encoder mode set encoder_mode_set(id); // *** CRT controler commit display_crtc_dpms(id, B_DPMS_ON); display_crtc_lock(id, ATOM_DISABLE); // *** encoder commit // handle DisplayPort link training if (connector_is_dp(connectorIndex)) { if (info.dceMajor >= 4) encoder_dig_setup(connectorIndex, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); dp_link_train(id, mode); if (info.dceMajor >= 4) encoder_dig_setup(connectorIndex, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0); } encoder_dpms_set(id, B_DPMS_ON); encoder_output_lock(false); } // for debugging TRACE("D1CRTC_STATUS Value: 0x%X\n", Read32(CRT, AVIVO_D1CRTC_STATUS)); TRACE("D2CRTC_STATUS Value: 0x%X\n", Read32(CRT, AVIVO_D2CRTC_STATUS)); TRACE("D1CRTC_CONTROL Value: 0x%X\n", Read32(CRT, AVIVO_D1CRTC_CONTROL)); TRACE("D2CRTC_CONTROL Value: 0x%X\n", Read32(CRT, AVIVO_D2CRTC_CONTROL)); TRACE("D1GRPH_ENABLE Value: 0x%X\n", Read32(CRT, AVIVO_D1GRPH_ENABLE)); TRACE("D2GRPH_ENABLE Value: 0x%X\n", Read32(CRT, AVIVO_D2GRPH_ENABLE)); TRACE("D1SCL_ENABLE Value: 0x%X\n", Read32(CRT, AVIVO_D1SCL_SCALER_ENABLE)); TRACE("D2SCL_ENABLE Value: 0x%X\n", Read32(CRT, AVIVO_D2SCL_SCALER_ENABLE)); TRACE("D1CRTC_BLANK_CONTROL Value: 0x%X\n", Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL)); TRACE("D2CRTC_BLANK_CONTROL Value: 0x%X\n", Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL)); return B_OK; }
status_t dp_link_train(uint8 crtcID) { TRACE("%s\n", __func__); uint32 connectorIndex = gDisplay[crtcID]->connectorIndex; dp_info* dp = &gConnector[connectorIndex]->dpInfo; display_mode* mode = &gDisplay[crtcID]->currentMode; if (dp->valid != true) { ERROR("%s: started on invalid DisplayPort connector #%" B_PRIu32 "\n", __func__, connectorIndex); return B_ERROR; } int index = GetIndexIntoMasterTable(COMMAND, DPEncoderService); // Table version uint8 tableMajor; uint8 tableMinor; dp->trainingUseEncoder = true; if (atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor) == B_OK) { if (tableMinor > 1) { // The AtomBIOS DPEncoderService greater then 1.1 can't program the // training pattern properly. dp->trainingUseEncoder = false; } } uint32 linkEnumeration = gConnector[connectorIndex]->encoder.linkEnumeration; uint32 gpioID = gConnector[connectorIndex]->gpioID; uint32 hwPin = gGPIOInfo[gpioID]->hwPin; uint32 dpEncoderID = 0; if (encoder_pick_dig(connectorIndex) > 0) dpEncoderID |= ATOM_DP_CONFIG_DIG2_ENCODER; else dpEncoderID |= ATOM_DP_CONFIG_DIG1_ENCODER; if (linkEnumeration == GRAPH_OBJECT_ENUM_ID2) dpEncoderID |= ATOM_DP_CONFIG_LINK_B; else dpEncoderID |= ATOM_DP_CONFIG_LINK_A; dp->trainingReadInterval = dpcd_reg_read(hwPin, DP_TRAINING_AUX_RD_INTERVAL); uint8 sandbox = dpcd_reg_read(hwPin, DP_MAX_LANE_COUNT); radeon_shared_info &info = *gInfo->shared_info; //bool dpTPS3Supported = false; //if (info.dceMajor >= 5 && (sandbox & DP_TPS3_SUPPORTED) != 0) // dpTPS3Supported = true; // *** DisplayPort link training initialization // Power up the DP sink if (dp->config[0] >= DP_DPCD_REV_11) dpcd_reg_write(hwPin, DP_SET_POWER, DP_SET_POWER_D0); // Possibly enable downspread on the sink if ((dp->config[3] & 0x1) != 0) dpcd_reg_write(hwPin, DP_DOWNSPREAD_CTRL, DP_DOWNSPREAD_CTRL_AMP_EN); else dpcd_reg_write(hwPin, DP_DOWNSPREAD_CTRL, 0); encoder_dig_setup(connectorIndex, mode->timing.pixel_clock, ATOM_ENCODER_CMD_SETUP_PANEL_MODE); // TODO: Doesn't this overwrite important dpcd info? sandbox = dp->laneCount; if ((dp->config[0] >= DP_DPCD_REV_11) && (dp->config[2] & DP_ENHANCED_FRAME_CAP_EN)) sandbox |= DP_ENHANCED_FRAME_EN; dpcd_reg_write(hwPin, DP_LANE_COUNT, sandbox); // Set the link rate on the DP sink sandbox = dp_encode_link_rate(dp->linkRate); dpcd_reg_write(hwPin, DP_LINK_RATE, sandbox); // Start link training on source if (info.dceMajor >= 4 || !dp->trainingUseEncoder) { encoder_dig_setup(connectorIndex, mode->timing.pixel_clock, ATOM_ENCODER_CMD_DP_LINK_TRAINING_START); } else { ERROR("%s: TODO: cannot use AtomBIOS DPEncoderService on card!\n", __func__); } // Disable the training pattern on the sink dpcd_reg_write(hwPin, DP_TRAIN, DP_TRAIN_PATTERN_DISABLED); dp_link_train_cr(connectorIndex); dp_link_train_ce(connectorIndex); // *** DisplayPort link training finish snooze(400); // Disable the training pattern on the sink dpcd_reg_write(hwPin, DP_TRAIN, DP_TRAIN_PATTERN_DISABLED); // Disable the training pattern on the source if (info.dceMajor >= 4 || !dp->trainingUseEncoder) { encoder_dig_setup(connectorIndex, mode->timing.pixel_clock, ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE); } else { ERROR("%s: TODO: cannot use AtomBIOS DPEncoderService on card!\n", __func__); } return B_OK; }
status_t radeon_set_display_mode(display_mode* mode) { radeon_shared_info &info = *gInfo->shared_info; // Set mode on each display for (uint8 id = 0; id < MAX_DISPLAY; id++) { if (gDisplay[id]->attached == false) continue; uint32 connectorIndex = gDisplay[id]->connectorIndex; // Determine DP lanes if DP if (connector_is_dp(connectorIndex)) { dp_info *dpInfo = &gConnector[connectorIndex]->dpInfo; dpInfo->laneCount = dp_get_lane_count(connectorIndex, mode); dpInfo->linkRate = dp_get_link_rate(connectorIndex, mode); } // *** crtc and encoder prep encoder_output_lock(true); encoder_dpms_set(id, B_DPMS_OFF); display_crtc_lock(id, ATOM_ENABLE); display_crtc_dpms(id, B_DPMS_OFF); // *** Set up encoder -> crtc routing encoder_assign_crtc(id); // *** CRT controler mode set // Set up PLL for connector pll_pick(connectorIndex); pll_info* pll = &gConnector[connectorIndex]->encoder.pll; TRACE("%s: pll %d selected for connector %" B_PRIu32 "\n", __func__, pll->id, connectorIndex); pll_set(mode, id); display_crtc_set_dtd(id, mode); display_crtc_fb_set(id, mode); // atombios_overscan_setup display_crtc_scale(id, mode); // *** encoder mode set encoder_mode_set(id); // *** CRT controler commit display_crtc_dpms(id, B_DPMS_ON); display_crtc_lock(id, ATOM_DISABLE); // *** encoder commit // handle DisplayPort link training if (connector_is_dp(connectorIndex)) { if (info.dceMajor >= 4) encoder_dig_setup(connectorIndex, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); dp_link_train(connectorIndex, mode); if (info.dceMajor >= 4) encoder_dig_setup(connectorIndex, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0); } encoder_dpms_set(id, B_DPMS_ON); encoder_output_lock(false); } // for debugging // debug_dp_info(); TRACE("D1CRTC_STATUS Value: 0x%X\n", Read32(CRT, AVIVO_D1CRTC_STATUS)); TRACE("D2CRTC_STATUS Value: 0x%X\n", Read32(CRT, AVIVO_D2CRTC_STATUS)); TRACE("D1CRTC_CONTROL Value: 0x%X\n", Read32(CRT, AVIVO_D1CRTC_CONTROL)); TRACE("D2CRTC_CONTROL Value: 0x%X\n", Read32(CRT, AVIVO_D2CRTC_CONTROL)); TRACE("D1GRPH_ENABLE Value: 0x%X\n", Read32(CRT, AVIVO_D1GRPH_ENABLE)); TRACE("D2GRPH_ENABLE Value: 0x%X\n", Read32(CRT, AVIVO_D2GRPH_ENABLE)); TRACE("D1SCL_ENABLE Value: 0x%X\n", Read32(CRT, AVIVO_D1SCL_SCALER_ENABLE)); TRACE("D2SCL_ENABLE Value: 0x%X\n", Read32(CRT, AVIVO_D2SCL_SCALER_ENABLE)); TRACE("D1CRTC_BLANK_CONTROL Value: 0x%X\n", Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL)); TRACE("D2CRTC_BLANK_CONTROL Value: 0x%X\n", Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL)); return B_OK; }