diff options
-rw-r--r-- | src/atombios_output.c | 236 | ||||
-rw-r--r-- | src/radeon_atombios.c | 66 | ||||
-rw-r--r-- | src/radeon_output.c | 1 | ||||
-rw-r--r-- | src/radeon_probe.h | 2 |
4 files changed, 276 insertions, 29 deletions
diff --git a/src/atombios_output.c b/src/atombios_output.c index 6a769b0a..b56d8a02 100644 --- a/src/atombios_output.c +++ b/src/atombios_output.c @@ -645,9 +645,58 @@ atombios_output_dig_encoder_setup(xf86OutputPtr output, int action) } +static int +atombios_dce4_output_dig_encoder_setup(xf86OutputPtr output, int action) +{ + RADEONOutputPrivatePtr radeon_output = output->driver_private; + RADEONInfoPtr info = RADEONPTR(output->scrn); + radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); + DIG_ENCODER_CONTROL_PARAMETERS_V3 disp_data; + AtomBiosArgRec data; + unsigned char *space; + int index; + int clock = radeon_output->pixel_clock; + + if (radeon_encoder == NULL) + return ATOM_NOT_IMPLEMENTED; + + memset(&disp_data,0, sizeof(disp_data)); + + index = GetIndexIntoMasterTable(COMMAND, DIGxEncoderControl); + + disp_data.ucAction = action; + disp_data.usPixelClock = cpu_to_le16(clock / 10); + disp_data.ucEncoderMode = atombios_get_encoder_mode(output); + disp_data.acConfig.ucDigSel = radeon_output->dig_encoder; + + if (disp_data.ucEncoderMode == ATOM_ENCODER_MODE_DP) { + if (dp_link_clock_for_mode_clock(radeon_output, clock) == 27000) + disp_data.acConfig.ucDPLinkRate = 1; + disp_data.ucLaneNum = dp_lanes_for_mode_clock(radeon_output, clock); + } else if (clock > 165000) + disp_data.ucLaneNum = 8; + else + disp_data.ucLaneNum = 4; + + disp_data.ucBitPerColor = PANEL_8BIT_PER_COLOR; + + data.exec.index = index; + data.exec.dataSpace = (void *)&space; + data.exec.pspace = &disp_data; + + if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + ErrorF("Output DIG%d encoder setup success\n", radeon_output->dig_encoder); + return ATOM_SUCCESS; + } + + ErrorF("Output DIG%d setup failed\n", radeon_output->dig_encoder); + return ATOM_NOT_IMPLEMENTED; +} + union dig_transmitter_control { DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1; DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2; + DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 v3; }; static int @@ -668,7 +717,7 @@ atombios_output_dig_transmitter_setup(xf86OutputPtr output, int action, uint8_t memset(&disp_data,0, sizeof(disp_data)); - if (IS_DCE32_VARIANT) + if (IS_DCE32_VARIANT || IS_DCE4_VARIANT) index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); else { switch (radeon_encoder->encoder_id) { @@ -685,7 +734,65 @@ atombios_output_dig_transmitter_setup(xf86OutputPtr output, int action, uint8_t disp_data.v1.ucAction = action; - if (IS_DCE32_VARIANT) { + if (IS_DCE4_VARIANT) { + if (action == ATOM_TRANSMITTER_ACTION_INIT) { + disp_data.v3.usInitInfo = radeon_output->connector_object_id; + } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { + disp_data.v3.asMode.ucLaneSel = lane_num; + disp_data.v3.asMode.ucLaneSet = lane_set; + } else { + if (radeon_output->MonType == MT_DP) { + disp_data.v3.usPixelClock = + cpu_to_le16(dp_link_clock_for_mode_clock(radeon_output, clock)); + } else if (clock > 165000) { + disp_data.v3.usPixelClock = cpu_to_le16((clock / 2) / 10); + disp_data.v3.acConfig.fDualLinkConnector = 1; + } else { + disp_data.v3.usPixelClock = cpu_to_le16(clock / 10); + } + } + + if (radeon_output->MonType == MT_DP) + disp_data.v3.ucLaneNum = dp_lanes_for_mode_clock(radeon_output, clock); + else if (clock > 165000) + disp_data.v3.ucLaneNum = 8; + else + disp_data.v3.ucLaneNum = 4; + + if (radeon_output->linkb) + disp_data.v3.acConfig.ucLinkSel = 1; + + //if (radeon_output->dig_encoder) + // disp_data.v2.acConfig.ucEncoderSel = 1; + + // XXX select the PLL + if (radeon_output->dig_encoder) + disp_data.v3.acConfig.ucRefClkSource = 1; // PLL2 + else + disp_data.v3.acConfig.ucRefClkSource = 0; // PLL1 + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + disp_data.v3.acConfig.ucTransmitterSel = 0; + num = 0; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + disp_data.v3.acConfig.ucTransmitterSel = 1; + num = 1; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + disp_data.v3.acConfig.ucTransmitterSel = 2; + num = 2; + break; + } + + if (radeon_output->MonType == MT_DP) + disp_data.v3.acConfig.fCoherentMode = 1; /* DP requires coherent */ + else if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) { + if (radeon_output->coherent_mode) + disp_data.v3.acConfig.fCoherentMode = 1; + } + } else if (IS_DCE32_VARIANT) { if (action == ATOM_TRANSMITTER_ACTION_INIT) { disp_data.v2.usInitInfo = radeon_output->connector_object_id; } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { @@ -736,8 +843,8 @@ atombios_output_dig_transmitter_setup(xf86OutputPtr output, int action, uint8_t if (action == ATOM_TRANSMITTER_ACTION_INIT) { disp_data.v1.usInitInfo = radeon_output->connector_object_id; } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { - disp_data.v2.asMode.ucLaneSel = lane_num; - disp_data.v2.asMode.ucLaneSet = lane_set; + disp_data.v1.asMode.ucLaneSel = lane_num; + disp_data.v1.asMode.ucLaneSet = lane_set; } else { if (radeon_output->MonType == MT_DP) disp_data.v1.usPixelClock = @@ -1443,10 +1550,26 @@ atombios_set_output_crtc_source(xf86OutputPtr output) case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - if (radeon_output->dig_encoder) - crtc_src_param2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; - else - crtc_src_param2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; + switch (radeon_output->dig_encoder) { + case 0: + crtc_src_param2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; + break; + case 1: + crtc_src_param2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; + break; + case 2: + crtc_src_param2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID; + break; + case 3: + crtc_src_param2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID; + break; + case 4: + crtc_src_param2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID; + break; + case 5: + crtc_src_param2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID; + break; + } break; case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) @@ -1517,7 +1640,9 @@ atombios_apply_output_quirks(xf86OutputPtr output, DisplayModePtr mode) OUTREG(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, AVIVO_D1MODE_INTERLEAVE_EN); } - if (IS_DCE32_VARIANT && (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT))) { + if (IS_DCE32_VARIANT && + (!IS_DCE4_VARIANT) && + (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT))) { radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); if (radeon_encoder == NULL) return; @@ -1536,6 +1661,7 @@ atombios_pick_dig_encoder(xf86OutputPtr output) xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(output->scrn); RADEONOutputPrivatePtr radeon_output = output->driver_private; RADEONInfoPtr info = RADEONPTR(output->scrn); + radeon_encoder_ptr radeon_encoder = NULL; Bool is_lvtma = FALSE; int i, mode; uint32_t dig_enc_use_mask = 0; @@ -1547,6 +1673,35 @@ atombios_pick_dig_encoder(xf86OutputPtr output) mode == ATOM_ENCODER_MODE_CV) return; + if (IS_DCE4_VARIANT) { + radeon_encoder = radeon_get_encoder(output); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + if (radeon_output->linkb) + radeon_output->dig_encoder = 1; + else + radeon_output->dig_encoder = 0; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + if (radeon_output->linkb) + radeon_output->dig_encoder = 3; + else + radeon_output->dig_encoder = 2; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + if (radeon_output->linkb) + radeon_output->dig_encoder = 5; + else + radeon_output->dig_encoder = 4; + break; + default: + ErrorF("Unknown encoder\n"); + break; + } + return; + } + if (IS_DCE32_VARIANT) { RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private; radeon_output->dig_encoder = radeon_crtc->crtc_id; @@ -1555,8 +1710,8 @@ atombios_pick_dig_encoder(xf86OutputPtr output) for (i = 0; i < xf86_config->num_output; i++) { xf86OutputPtr test = xf86_config->output[i]; - radeon_encoder_ptr radeon_encoder = radeon_get_encoder(test); RADEONOutputPrivatePtr radeon_test = test->driver_private; + radeon_encoder = radeon_get_encoder(test); if (!radeon_encoder || !test->crtc) continue; @@ -1614,10 +1769,14 @@ atombios_output_mode_set(xf86OutputPtr output, case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: /* disable encoder and transmitter */ - atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); - atombios_output_dig_encoder_setup(output, ATOM_DISABLE); - /* setup and enable the encoder and transmitter */ + atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); + if (IS_DCE4_VARIANT) + atombios_dce4_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_SETUP); + else { + atombios_output_dig_encoder_setup(output, ATOM_DISABLE); + atombios_output_dig_encoder_setup(output, ATOM_ENABLE); + } atombios_output_dig_encoder_setup(output, ATOM_ENABLE); atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_INIT, 0, 0); atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); @@ -1878,13 +2037,18 @@ static inline int atom_dp_get_encoder_id(xf86OutputPtr output) return ret; } +union aux_channel_transaction { + PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1; + PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2; +}; + Bool RADEONProcessAuxCH(xf86OutputPtr output, uint8_t *req_bytes, uint8_t num_bytes, uint8_t *read_byte, uint8_t read_buf_len, uint8_t delay) { RADEONOutputPrivatePtr radeon_output = output->driver_private; RADEONInfoPtr info = RADEONPTR(output->scrn); - PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION args; + union aux_channel_transaction args; AtomBiosArgRec data; unsigned char *space; unsigned char *base; @@ -1899,29 +2063,31 @@ RADEONProcessAuxCH(xf86OutputPtr output, uint8_t *req_bytes, uint8_t num_bytes, memcpy(base, req_bytes, num_bytes); - args.lpAuxRequest = 0; - args.lpDataOut = 16; - args.ucDataOutLen = 0; - args.ucChannelID = radeon_output->ucI2cId; - args.ucDelay = delay / 10; /* 10 usec */ + args.v1.lpAuxRequest = 0; + args.v1.lpDataOut = 16; + args.v1.ucDataOutLen = 0; + args.v1.ucChannelID = radeon_output->ucI2cId; + args.v1.ucDelay = delay / 10; /* 10 usec */ + if (IS_DCE4_VARIANT) + args.v2.ucHPD_ID = radeon_output->hpd_id; data.exec.index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction); data.exec.dataSpace = (void *)&space; data.exec.pspace = &args; RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data); - if (args.ucReplyStatus) { + if (args.v1.ucReplyStatus) { ErrorF("failed to get auxch %02x%02x %02x %02x %02x\n", - req_bytes[1], req_bytes[0], req_bytes[2], req_bytes[3],args.ucReplyStatus); + req_bytes[1], req_bytes[0], req_bytes[2], req_bytes[3], args.v1.ucReplyStatus); return FALSE; } - if (args.ucDataOutLen && read_byte && read_buf_len) { - if (read_buf_len < args.ucDataOutLen) { - ErrorF("%s: Buffer too small for return answer %d %d\n", __func__, read_buf_len, args.ucDataOutLen); + if (args.v1.ucDataOutLen && read_byte && read_buf_len) { + if (read_buf_len < args.v1.ucDataOutLen) { + ErrorF("%s: Buffer too small for return answer %d %d\n", __func__, read_buf_len, args.v1.ucDataOutLen); return FALSE; } { - int len = read_buf_len < args.ucDataOutLen ? read_buf_len : args.ucDataOutLen; + int len = read_buf_len < args.v1.ucDataOutLen ? read_buf_len : args.v1.ucDataOutLen; memcpy(read_byte, base+16, len); } } @@ -2463,6 +2629,7 @@ static void dp_update_dpvs_emph(xf86OutputPtr output, uint8_t train_set[4]) static void do_displayport_link_train(xf86OutputPtr output) { ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); RADEONOutputPrivatePtr radeon_output = output->driver_private; int enc_id = atom_dp_get_encoder_id(output); Bool clock_recovery; @@ -2504,8 +2671,13 @@ static void do_displayport_link_train(xf86OutputPtr output) &ss_cntl); /* start local training start */ - RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_START, enc_id, 0); - RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_PATTERN_SEL, enc_id, 0); + if (IS_DCE4_VARIANT) { + atombios_dce4_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_LINK_TRAINING_START); + atombios_dce4_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1); + } else { + RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_START, enc_id, 0); + RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_PATTERN_SEL, enc_id, 0); + } usleep(400); dp_set_training(output, DP_TRAINING_PATTERN_1); @@ -2560,7 +2732,10 @@ static void do_displayport_link_train(xf86OutputPtr output) tries = 0; channel_eq = FALSE; dp_set_training(output, DP_TRAINING_PATTERN_2); - RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_PATTERN_SEL, enc_id, 1); + if (IS_DCE4_VARIANT) + atombios_dce4_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2); + else + RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_PATTERN_SEL, enc_id, 1); for (;;) { usleep(400); @@ -2591,7 +2766,10 @@ static void do_displayport_link_train(xf86OutputPtr output) "channel eq failed\n"); dp_set_training(output, DP_TRAINING_PATTERN_DISABLE); - RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_COMPLETE, enc_id, 0); + if (IS_DCE4_VARIANT) + atombios_dce4_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE); + else + RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_COMPLETE, enc_id, 0); } diff --git a/src/radeon_atombios.c b/src/radeon_atombios.c index d6c58bc3..7bf98153 100644 --- a/src/radeon_atombios.c +++ b/src/radeon_atombios.c @@ -1590,6 +1590,69 @@ rhdAtomParseI2CRecord(ScrnInfoPtr pScrn, atomBiosHandlePtr handle, return RADEONLookupGPIOLineForDDC(pScrn, Record->sucI2cId.bfI2C_LineMux); } +static uint8_t +radeon_lookup_hpd_id(ScrnInfoPtr pScrn, ATOM_HPD_INT_RECORD *record) +{ + RADEONInfoPtr info = RADEONPTR (pScrn); + unsigned short size; + uint8_t hpd = 0; + int i, num_indices; + struct _ATOM_GPIO_PIN_LUT *gpio_info; + ATOM_GPIO_PIN_ASSIGNMENT *pin; + atomDataTablesPtr atomDataPtr; + uint8_t crev, frev; + uint32_t reg; + + atomDataPtr = info->atomBIOS->atomDataPtr; + + if (!rhdAtomGetTableRevisionAndSize( + &(atomDataPtr->GPIO_Pin_LUT->sHeader), + &crev,&frev,&size)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No GPIO Pin Table found!\n"); + return hpd; + } + + num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / sizeof(ATOM_GPIO_PIN_ASSIGNMENT); + + if (IS_DCE4_VARIANT) + reg = EVERGREEN_DC_GPIO_HPD_A; + else + reg = AVIVO_DC_GPIO_HPD_A; + + gpio_info = atomDataPtr->GPIO_Pin_LUT; + for (i = 0; i < num_indices; i++) { + pin = &gpio_info->asGPIO_Pin[i]; + if (record->ucHPDIntGPIOID == pin->ucGPIO_ID) { + if ((pin->usGpioPin_AIndex * 4) == reg) { + switch (pin->ucGpioPinBitShift) { + case 0: + default: + hpd = 0; + break; + case 8: + hpd = 1; + break; + case 16: + hpd = 2; + break; + case 24: + hpd = 3; + break; + case 26: + hpd = 4; + break; + case 28: + hpd = 5; + break; + } + break; + } + } + } + + return hpd; +} + static void RADEONApplyATOMQuirks(ScrnInfoPtr pScrn, int index) { RADEONInfoPtr info = RADEONPTR (pScrn); @@ -1935,6 +1998,9 @@ RADEONGetATOMConnectorInfoFromBIOSObject (ScrnInfoPtr pScrn) (ATOM_I2C_RECORD *)Record, j); break; case ATOM_HPD_INT_RECORD_TYPE: + info->BiosConnector[i].hpd_id = + radeon_lookup_hpd_id(pScrn, + (ATOM_HPD_INT_RECORD *)Record); break; case ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE: break; diff --git a/src/radeon_output.c b/src/radeon_output.c index 3bc2f003..49df82fe 100644 --- a/src/radeon_output.c +++ b/src/radeon_output.c @@ -2969,6 +2969,7 @@ Bool RADEONSetupConnectors(ScrnInfoPtr pScrn) radeon_output->connector_id = info->BiosConnector[i].connector_object; radeon_output->connector_object_id = info->BiosConnector[i].connector_object_id; radeon_output->ucI2cId = info->BiosConnector[i].ucI2cId; + radeon_output->hpd_id = info->BiosConnector[i].hpd_id; /* Technically HDMI-B is a glorfied DL DVI so the bios is correct, * but this can be confusing to users when it comes to output names, diff --git a/src/radeon_probe.h b/src/radeon_probe.h index f374ab08..7cdf2de2 100644 --- a/src/radeon_probe.h +++ b/src/radeon_probe.h @@ -242,6 +242,7 @@ typedef struct { uint16_t connector_object; uint16_t connector_object_id; uint8_t ucI2cId; + uint8_t hpd_id; } RADEONBIOSConnector; typedef struct _RADEONOutputPrivateRec { @@ -297,6 +298,7 @@ typedef struct _RADEONOutputPrivateRec { uint8_t dpcd[8]; int dp_lane_count; int dp_clock; + uint8_t hpd_id; } RADEONOutputPrivateRec, *RADEONOutputPrivatePtr; struct avivo_pll_state { |