22,14 → 22,15 |
* |
* Authors: Dave Airlie |
* Alex Deucher |
* Jerome Glisse |
*/ |
#include "drmP.h" |
#include "radeon_drm.h" |
#include <drm/drmP.h> |
#include <drm/radeon_drm.h> |
#include "radeon.h" |
|
#include "atom.h" |
#include "atom-bits.h" |
#include "drm_dp_helper.h" |
#include <drm/drm_dp_helper.h> |
|
/* move these to drm_dp_helper.c/h */ |
#define DP_LINK_CONFIGURATION_SIZE 9 |
63,12 → 64,12 |
|
memset(&args, 0, sizeof(args)); |
|
base = (unsigned char *)rdev->mode_info.atom_context->scratch; |
base = (unsigned char *)(rdev->mode_info.atom_context->scratch + 1); |
|
memcpy(base, send, send_bytes); |
|
args.v1.lpAuxRequest = 0; |
args.v1.lpDataOut = 16; |
args.v1.lpAuxRequest = 0 + 4; |
args.v1.lpDataOut = 16 + 4; |
args.v1.ucDataOutLen = 0; |
args.v1.ucChannelID = chan->rec.i2c_id; |
args.v1.ucDelay = delay / 10; |
115,6 → 116,7 |
u8 msg[20]; |
int msg_bytes = send_bytes + 4; |
u8 ack; |
unsigned retry; |
|
if (send_bytes > 16) |
return -1; |
125,13 → 127,15 |
msg[3] = (msg_bytes << 4) | (send_bytes - 1); |
memcpy(&msg[4], send, send_bytes); |
|
while (1) { |
for (retry = 0; retry < 4; retry++) { |
ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus, |
msg, msg_bytes, NULL, 0, delay, &ack); |
if (ret < 0) |
if (ret == -EBUSY) |
continue; |
else if (ret < 0) |
return ret; |
if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) |
break; |
return send_bytes; |
else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER) |
udelay(400); |
else |
138,7 → 142,7 |
return -EIO; |
} |
|
return send_bytes; |
return -EIO; |
} |
|
static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector, |
149,6 → 153,7 |
int msg_bytes = 4; |
u8 ack; |
int ret; |
unsigned retry; |
|
msg[0] = address; |
msg[1] = address >> 8; |
155,20 → 160,24 |
msg[2] = AUX_NATIVE_READ << 4; |
msg[3] = (msg_bytes << 4) | (recv_bytes - 1); |
|
while (1) { |
for (retry = 0; retry < 4; retry++) { |
ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus, |
msg, msg_bytes, recv, recv_bytes, delay, &ack); |
if (ret == 0) |
return -EPROTO; |
if (ret < 0) |
if (ret == -EBUSY) |
continue; |
else if (ret < 0) |
return ret; |
if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) |
return ret; |
else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER) |
udelay(400); |
else if (ret == 0) |
return -EPROTO; |
else |
return -EIO; |
} |
|
return -EIO; |
} |
|
static void radeon_write_dpcd_reg(struct radeon_connector *radeon_connector, |
232,7 → 241,9 |
for (retry = 0; retry < 4; retry++) { |
ret = radeon_process_aux_ch(auxch, |
msg, msg_bytes, reply, reply_bytes, 0, &ack); |
if (ret < 0) { |
if (ret == -EBUSY) |
continue; |
else if (ret < 0) { |
DRM_DEBUG_KMS("aux_ch failed %d\n", ret); |
return ret; |
} |
273,7 → 284,7 |
} |
} |
|
DRM_ERROR("aux i2c too many retries, giving up\n"); |
DRM_DEBUG_KMS("aux i2c too many retries, giving up\n"); |
return -EREMOTEIO; |
} |
|
450,7 → 461,7 |
u8 dpcd[DP_DPCD_SIZE], |
int pix_clock) |
{ |
int bpp = convert_bpc_to_bpp(connector->display_info.bpc); |
int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector)); |
int max_link_rate = dp_get_max_link_rate(dpcd); |
int max_lane_num = dp_get_max_lane_number(dpcd); |
int lane_num; |
469,10 → 480,11 |
u8 dpcd[DP_DPCD_SIZE], |
int pix_clock) |
{ |
int bpp = convert_bpc_to_bpp(connector->display_info.bpc); |
int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector)); |
int lane_num, max_pix_clock; |
|
if (radeon_connector_encoder_is_dp_bridge(connector)) |
if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) == |
ENCODER_OBJECT_ID_NUTMEG) |
return 270000; |
|
lane_num = radeon_dp_get_dp_lane_number(connector, dpcd, pix_clock); |
519,6 → 531,23 |
dig_connector->dp_i2c_bus->rec.i2c_id, 0); |
} |
|
static void radeon_dp_probe_oui(struct radeon_connector *radeon_connector) |
{ |
struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; |
u8 buf[3]; |
|
if (!(dig_connector->dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT)) |
return; |
|
if (radeon_dp_aux_native_read(radeon_connector, DP_SINK_OUI, buf, 3, 0)) |
DRM_DEBUG_KMS("Sink OUI: %02hx%02hx%02hx\n", |
buf[0], buf[1], buf[2]); |
|
if (radeon_dp_aux_native_read(radeon_connector, DP_BRANCH_OUI, buf, 3, 0)) |
DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n", |
buf[0], buf[1], buf[2]); |
} |
|
bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector) |
{ |
struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; |
532,6 → 561,9 |
for (i = 0; i < 8; i++) |
DRM_DEBUG_KMS("%02x ", msg[i]); |
DRM_DEBUG_KMS("\n"); |
|
radeon_dp_probe_oui(radeon_connector); |
|
return true; |
} |
dig_connector->dpcd[0] = 0; |
538,26 → 570,41 |
return false; |
} |
|
static void radeon_dp_set_panel_mode(struct drm_encoder *encoder, |
int radeon_dp_get_panel_mode(struct drm_encoder *encoder, |
struct drm_connector *connector) |
{ |
struct drm_device *dev = encoder->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
int panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; |
u16 dp_bridge = radeon_connector_encoder_get_dp_bridge_encoder_id(connector); |
u8 tmp; |
|
if (!ASIC_IS_DCE4(rdev)) |
return; |
return panel_mode; |
|
if (radeon_connector_encoder_is_dp_bridge(connector)) |
if (dp_bridge != ENCODER_OBJECT_ID_NONE) { |
/* DP bridge chips */ |
tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP); |
if (tmp & 1) |
panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; |
else if ((dp_bridge == ENCODER_OBJECT_ID_NUTMEG) || |
(dp_bridge == ENCODER_OBJECT_ID_TRAVIS)) |
panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE; |
else |
panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; |
} else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { |
/* eDP */ |
tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP); |
if (tmp & 1) |
panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; |
} |
|
atombios_dig_encoder_setup(encoder, |
ATOM_ENCODER_CMD_SETUP_PANEL_MODE, |
panel_mode); |
return panel_mode; |
} |
|
void radeon_dp_set_link_config(struct drm_connector *connector, |
struct drm_display_mode *mode) |
const struct drm_display_mode *mode) |
{ |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
struct radeon_connector_atom_dig *dig_connector; |
603,16 → 650,25 |
ret = radeon_dp_aux_native_read(radeon_connector, DP_LANE0_1_STATUS, |
link_status, DP_LINK_STATUS_SIZE, 100); |
if (ret <= 0) { |
DRM_ERROR("displayport link status failed\n"); |
return false; |
} |
|
DRM_DEBUG_KMS("link status %02x %02x %02x %02x %02x %02x\n", |
link_status[0], link_status[1], link_status[2], |
link_status[3], link_status[4], link_status[5]); |
DRM_DEBUG_KMS("link status %*ph\n", 6, link_status); |
return true; |
} |
|
bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector) |
{ |
u8 link_status[DP_LINK_STATUS_SIZE]; |
struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; |
|
if (!radeon_dp_get_link_status(radeon_connector, link_status)) |
return false; |
if (dp_channel_eq_ok(link_status, dig->dp_lane_count)) |
return false; |
return true; |
} |
|
struct radeon_dp_link_train_info { |
struct radeon_device *rdev; |
struct drm_encoder *encoder; |
679,6 → 735,8 |
|
static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info) |
{ |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(dp_info->encoder); |
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
u8 tmp; |
|
/* power up the sink */ |
694,11 → 752,15 |
radeon_write_dpcd_reg(dp_info->radeon_connector, |
DP_DOWNSPREAD_CTRL, 0); |
|
radeon_dp_set_panel_mode(dp_info->encoder, dp_info->connector); |
if ((dp_info->connector->connector_type == DRM_MODE_CONNECTOR_eDP) && |
(dig->panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE)) { |
radeon_write_dpcd_reg(dp_info->radeon_connector, DP_EDP_CONFIGURATION_SET, 1); |
} |
|
/* set the lane count on the sink */ |
tmp = dp_info->dp_lane_count; |
if (dp_info->dpcd[0] >= 0x11) |
if (dp_info->dpcd[DP_DPCD_REV] >= 0x11 && |
dp_info->dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP) |
tmp |= DP_LANE_COUNT_ENHANCED_FRAME_EN; |
radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LANE_COUNT_SET, tmp); |
|
764,8 → 826,10 |
else |
mdelay(dp_info->rd_interval * 4); |
|
if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status)) |
if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status)) { |
DRM_ERROR("displayport link status failed\n"); |
break; |
} |
|
if (dp_clock_recovery_ok(dp_info->link_status, dp_info->dp_lane_count)) { |
clock_recovery = true; |
827,8 → 891,10 |
else |
mdelay(dp_info->rd_interval * 4); |
|
if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status)) |
if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status)) { |
DRM_ERROR("displayport link status failed\n"); |
break; |
} |
|
if (dp_channel_eq_ok(dp_info->link_status, dp_info->dp_lane_count)) { |
channel_eq = true; |