#define DP_LINK_STATUS_SIZE 6
bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes,
- int num_bytes, u8 *read_byte,
+ int num_bytes, u8 *read_byte,
u8 read_buf_len, u8 delay)
{
struct drm_device *dev = chan->dev;
PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION args;
int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);
unsigned char *base;
-
+
memset(&args, 0, sizeof(args));
-
+
base = (unsigned char *)rdev->mode_info.atom_context->scratch;
memcpy(base, req_bytes, num_bytes);
args.lpDataOut = 16;
args.ucDataOutLen = 0;
args.ucChannelID = chan->i2c_id;
- args.ucDelay = delay;
+ args.ucDelay = delay / 10;
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
return ret;
}
-void radeon_dp_getdpcp(struct radeon_connector *radeon_connector)
+void radeon_dp_getdpcd(struct radeon_connector *radeon_connector)
{
struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
u8 msg[25];
int ret;
- ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCP_REV, 0, 8, msg);
+ ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCD_REV, 0, 8, msg);
if (ret) {
- memcpy(radeon_dig_connector->dpcp, msg, 8);
- {
+ memcpy(radeon_dig_connector->dpcd, msg, 8);
+ {
int i;
- printk("DPCP: ");
+ printk("DPCD: ");
for (i = 0; i < 8; i++)
printk("%02x ", msg[i]);
printk("\n");
}
}
- radeon_dig_connector->dpcp[0] = 0;
+ radeon_dig_connector->dpcd[0] = 0;
return;
}
static void dp_set_power(struct radeon_connector *radeon_connector, u8 power_state)
{
struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
- if (radeon_dig_connector->dpcp[0] >= 0x11) {
- radeon_dp_aux_native_write(radeon_connector, 0x600, 1,
+ if (radeon_dig_connector->dpcd[0] >= 0x11) {
+ radeon_dp_aux_native_write(radeon_connector, DP_SET_POWER, 1,
&power_state);
}
}
}
}
+/*
+ * DIG Encoder/Transmitter Setup
+ *
+ * DCE 3.0/3.1
+ * - 2 DIG transmitter blocks. UNIPHY (links A and B) and LVTMA.
+ * Supports up to 3 digital outputs
+ * - 2 DIG encoder blocks.
+ * DIG1 can drive UNIPHY link A or link B
+ * DIG2 can drive UNIPHY link B or LVTMA
+ *
+ * DCE 3.2
+ * - 3 DIG transmitter blocks. UNIPHY0/1/2 (links A and B).
+ * Supports up to 5 digital outputs
+ * - 2 DIG encoder blocks.
+ * DIG1/2 can drive UNIPHY0/1/2 link A or link B
+ *
+ * Routing
+ * crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links)
+ * Examples:
+ * crtc0 -> dig2 -> LVTMA links A+B -> TMDS/HDMI
+ * crtc1 -> dig1 -> UNIPHY0 link B -> DP
+ * crtc0 -> dig1 -> UNIPHY2 link A -> LVDS
+ * crtc1 -> dig2 -> UNIPHY1 link B+A -> TMDS/HDMI
+ */
static void
atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
{
} else {
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
- index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
+ /* XXX doesn't really matter which dig encoder we pick as long as it's
+ * not already in use
+ */
+ if (dig_connector->linkb)
+ index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
+ else
+ index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
num = 1;
break;
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+ /* Only dig2 encoder can drive LVTMA */
index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
num = 2;
break;
}
}
- if (radeon_encoder->pixel_clock > 165000) {
- args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA_B;
+ if (radeon_encoder->pixel_clock > 165000)
args.ucLaneNum = 8;
- } else {
- if (dig_connector->linkb)
- args.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
- else
- args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
+ else
args.ucLaneNum = 4;
- }
+
+ if (dig_connector->linkb)
+ args.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
+ else
+ args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
args.ucEncoderMode = atombios_get_encoder_mode(encoder);
};
static void
-atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action)
+atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
args.v1.ucAction = action;
if (action == ATOM_TRANSMITTER_ACTION_INIT) {
args.v1.usInitInfo = radeon_connector->connector_object_id;
+ } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
+ args.v1.asMode.ucLaneSel = lane_num;
+ args.v1.asMode.ucLaneSet = lane_set;
} else {
if (radeon_encoder->pixel_clock > 165000)
args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10);
args.v2.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10);
if (dig->dig_block)
args.v2.acConfig.ucEncoderSel = 1;
+ if (dig_connector->linkb)
+ args.v2.acConfig.ucLinkSel = 1;
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
- args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
+ /* XXX doesn't really matter which dig encoder we pick as long as it's
+ * not already in use
+ */
+ if (dig_connector->linkb)
+ args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER;
+ else
+ args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
if (rdev->flags & RADEON_IS_IGP) {
if (radeon_encoder->pixel_clock > 165000) {
- args.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK |
- ATOM_TRANSMITTER_CONFIG_LINKA_B);
if (dig_connector->igp_lane_info & 0x3)
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7;
else if (dig_connector->igp_lane_info & 0xc)
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15;
} else {
- args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA;
if (dig_connector->igp_lane_info & 0x1)
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3;
else if (dig_connector->igp_lane_info & 0x2)
else if (dig_connector->igp_lane_info & 0x8)
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15;
}
- } else {
- if (radeon_encoder->pixel_clock > 165000)
- args.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK |
- ATOM_TRANSMITTER_CONFIG_LINKA_B |
- ATOM_TRANSMITTER_CONFIG_LANE_0_7);
- else {
- if (dig_connector->linkb)
- args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
- else
- args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
- }
}
break;
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+ /* Only dig2 encoder can drive LVTMA */
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER;
- if (radeon_encoder->pixel_clock > 165000)
- args.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK |
- ATOM_TRANSMITTER_CONFIG_LINKA_B |
- ATOM_TRANSMITTER_CONFIG_LANE_0_7);
- else {
- if (dig_connector->linkb)
- args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
- else
- args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
- }
break;
}
+ if (radeon_encoder->pixel_clock > 165000)
+ args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK;
+
+ if (dig_connector->linkb)
+ args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB;
+ else
+ args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA;
+
if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
if (dig->coherent_mode)
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
}
-static void
-atombios_dig_transmitter_setup_vsemph(struct drm_encoder *encoder, u8 lane_num,
- u8 lane_set)
-{
- struct drm_device *dev = encoder->dev;
- struct radeon_device *rdev = dev->dev_private;
- struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- union dig_transmitter_control args;
- int index = 0, num = 0;
- uint8_t frev, crev;
- struct radeon_encoder_atom_dig *dig;
- struct drm_connector *connector;
- struct radeon_connector *radeon_connector;
- struct radeon_connector_atom_dig *dig_connector;
-
- connector = radeon_get_connector_for_encoder(encoder);
- if (!connector)
- return;
-
- radeon_connector = to_radeon_connector(connector);
-
- if (!radeon_encoder->enc_priv)
- return;
-
- dig = radeon_encoder->enc_priv;
-
- if (!radeon_connector->con_priv)
- return;
-
- dig_connector = radeon_connector->con_priv;
-
- memset(&args, 0, sizeof(args));
-
- if (ASIC_IS_DCE32(rdev))
- index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
- else {
- switch (radeon_encoder->encoder_id) {
- case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
- index = GetIndexIntoMasterTable(COMMAND, DIG1TransmitterControl);
- break;
- case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
- index = GetIndexIntoMasterTable(COMMAND, DIG2TransmitterControl);
- break;
- }
- }
-
- atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev);
-
- args.v1.ucAction = ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH;
- args.v1.asMode.ucLaneSel = lane_num;
- args.v1.asMode.ucLaneSet = lane_set;
-
- if (ASIC_IS_DCE32(rdev)) {
- args.v2.acConfig.fDPConnector = 1;
-
- if (dig->dig_block)
- args.v2.acConfig.ucEncoderSel = 1;
-
- switch (radeon_encoder->encoder_id) {
- case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
- args.v2.acConfig.ucTransmitterSel = 0;
- num = 0;
- break;
- case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
- args.v2.acConfig.ucTransmitterSel = 1;
- num = 1;
- break;
- case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
- args.v2.acConfig.ucTransmitterSel = 2;
- num = 2;
- break;
- }
- } else {
- args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL;
-
- switch (radeon_encoder->encoder_id) {
- case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
- args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
- if (dig_connector->linkb)
- args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
- else
- args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
- }
- }
-
- atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
-
- if (ASIC_IS_DCE32(rdev))
- DRM_INFO("Output UNIPHY%d transmitter VSEMPH setup success\n", num);
- else
- DRM_INFO("Output DIG%d transmitter VSEMPH setup success\n", num);
-}
-
static void
atombios_yuv_setup(struct drm_encoder *encoder, bool enable)
{
args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
else
args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
- } else
- args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
+ } else {
+ struct drm_connector *connector;
+ struct radeon_connector *radeon_connector;
+ struct radeon_connector_atom_dig *dig_connector;
+
+ connector = radeon_get_connector_for_encoder(encoder);
+ if (!connector)
+ return;
+ radeon_connector = to_radeon_connector(connector);
+ if (!radeon_connector->con_priv)
+ return;
+ dig_connector = radeon_connector->con_priv;
+
+ /* XXX doesn't really matter which dig encoder we pick as long as it's
+ * not already in use
+ */
+ if (dig_connector->linkb)
+ args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
+ else
+ args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
+ }
break;
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID;
break;
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+ /* Only dig2 encoder can drive LVTMA */
args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
break;
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
/* disable the encoder and transmitter */
- atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE);
+ atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
atombios_dig_encoder_setup(encoder, ATOM_DISABLE);
/* setup and enable the encoder and transmitter */
atombios_dig_encoder_setup(encoder, ATOM_ENABLE);
- atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT);
- atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP);
- atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE);
+ atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
+ atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0);
+ atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
break;
case ENCODER_OBJECT_ID_INTERNAL_DDI:
atombios_ddia_setup(encoder, ATOM_ENABLE);