Skip to content

Commit

Permalink
drm/radeon: use the new drm helpers for dp aux
Browse files Browse the repository at this point in the history
Switch to the new dp helpers.  The main difference is
that the DP helpers don't allow an adjustable delay in
the aux transaction, but I don't know that this is
necessary.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Acked-by: Christian König <christian.koenig@amd.com>
  • Loading branch information
Alex Deucher authored and Christian König committed Mar 25, 2014
1 parent 743b1e3 commit 496263b
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 107 deletions.
192 changes: 88 additions & 104 deletions drivers/gpu/drm/radeon/atombios_dp.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,94 +142,62 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
return recv_bytes;
}

static int radeon_dp_aux_native_write(struct radeon_connector *radeon_connector,
u16 address, u8 *send, u8 send_bytes, u8 delay)
{
struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
int ret;
u8 msg[20];
int msg_bytes = send_bytes + 4;
u8 ack;
unsigned retry;

if (send_bytes > 16)
return -1;
#define HEADER_SIZE 4

msg[0] = address;
msg[1] = address >> 8;
msg[2] = DP_AUX_NATIVE_WRITE << 4;
msg[3] = (msg_bytes << 4) | (send_bytes - 1);
memcpy(&msg[4], send, send_bytes);

for (retry = 0; retry < 7; retry++) {
ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
msg, msg_bytes, NULL, 0, delay, &ack);
if (ret == -EBUSY)
continue;
else if (ret < 0)
return ret;
ack >>= 4;
if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK)
return send_bytes;
else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER)
usleep_range(400, 500);
else
return -EIO;
}

return -EIO;
}

static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector,
u16 address, u8 *recv, int recv_bytes, u8 delay)
static ssize_t
radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
{
struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
u8 msg[4];
int msg_bytes = 4;
u8 ack;
struct radeon_i2c_chan *chan =
container_of(aux, struct radeon_i2c_chan, aux);
int ret;
unsigned retry;

msg[0] = address;
msg[1] = address >> 8;
msg[2] = DP_AUX_NATIVE_READ << 4;
msg[3] = (msg_bytes << 4) | (recv_bytes - 1);

for (retry = 0; retry < 7; retry++) {
ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
msg, msg_bytes, recv, recv_bytes, delay, &ack);
if (ret == -EBUSY)
continue;
else if (ret < 0)
return ret;
ack >>= 4;
if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK)
return ret;
else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER)
usleep_range(400, 500);
else if (ret == 0)
return -EPROTO;
else
return -EIO;
u8 tx_buf[20];
size_t tx_size;
u8 ack, delay = 0;

if (WARN_ON(msg->size > 16))
return -E2BIG;

tx_buf[0] = msg->address & 0xff;
tx_buf[1] = msg->address >> 8;
tx_buf[2] = msg->request << 4;
tx_buf[3] = msg->size - 1;

switch (msg->request & ~DP_AUX_I2C_MOT) {
case DP_AUX_NATIVE_WRITE:
case DP_AUX_I2C_WRITE:
tx_size = HEADER_SIZE + msg->size;
tx_buf[3] |= tx_size << 4;
memcpy(tx_buf + HEADER_SIZE, msg->buffer, msg->size);
ret = radeon_process_aux_ch(chan,
tx_buf, tx_size, NULL, 0, delay, &ack);
if (ret >= 0)
/* Return payload size. */
ret = msg->size;
break;
case DP_AUX_NATIVE_READ:
case DP_AUX_I2C_READ:
tx_size = HEADER_SIZE;
tx_buf[3] |= tx_size << 4;
ret = radeon_process_aux_ch(chan,
tx_buf, tx_size, msg->buffer, msg->size, delay, &ack);
break;
default:
ret = -EINVAL;
break;
}

return -EIO;
}
if (ret > 0)
msg->reply = ack >> 4;

static void radeon_write_dpcd_reg(struct radeon_connector *radeon_connector,
u16 reg, u8 val)
{
radeon_dp_aux_native_write(radeon_connector, reg, &val, 1, 0);
return ret;
}

static u8 radeon_read_dpcd_reg(struct radeon_connector *radeon_connector,
u16 reg)
void radeon_dp_aux_init(struct radeon_connector *radeon_connector)
{
u8 val = 0;

radeon_dp_aux_native_read(radeon_connector, reg, &val, 1, 0);
struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;

return val;
dig_connector->dp_i2c_bus->aux.dev = radeon_connector->base.kdev;
dig_connector->dp_i2c_bus->aux.transfer = radeon_dp_aux_transfer;
}

int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
Expand Down Expand Up @@ -468,11 +436,11 @@ static void radeon_dp_probe_oui(struct radeon_connector *radeon_connector)
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))
if (drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_SINK_OUI, buf, 3))
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))
if (drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_BRANCH_OUI, buf, 3))
DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n",
buf[0], buf[1], buf[2]);
}
Expand All @@ -483,8 +451,8 @@ bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector)
u8 msg[DP_DPCD_SIZE];
int ret, i;

ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCD_REV, msg,
DP_DPCD_SIZE, 0);
ret = drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_DPCD_REV, msg,
DP_DPCD_SIZE);
if (ret > 0) {
memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE);
DRM_DEBUG_KMS("DPCD: ");
Expand All @@ -506,16 +474,23 @@ int radeon_dp_get_panel_mode(struct drm_encoder *encoder,
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct radeon_connector_atom_dig *dig_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 panel_mode;

if (!radeon_connector->con_priv)
return panel_mode;

dig_connector = radeon_connector->con_priv;

if (dp_bridge != ENCODER_OBJECT_ID_NONE) {
/* DP bridge chips */
tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP);
drm_dp_dpcd_readb(&dig_connector->dp_i2c_bus->aux,
DP_EDP_CONFIGURATION_CAP, &tmp);
if (tmp & 1)
panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE;
else if ((dp_bridge == ENCODER_OBJECT_ID_NUTMEG) ||
Expand All @@ -525,7 +500,8 @@ int radeon_dp_get_panel_mode(struct drm_encoder *encoder,
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);
drm_dp_dpcd_readb(&dig_connector->dp_i2c_bus->aux,
DP_EDP_CONFIGURATION_CAP, &tmp);
if (tmp & 1)
panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE;
}
Expand Down Expand Up @@ -576,9 +552,15 @@ int radeon_dp_mode_valid_helper(struct drm_connector *connector,
static bool radeon_dp_get_link_status(struct radeon_connector *radeon_connector,
u8 link_status[DP_LINK_STATUS_SIZE])
{
struct radeon_connector_atom_dig *dig_connector;
int ret;
ret = radeon_dp_aux_native_read(radeon_connector, DP_LANE0_1_STATUS,
link_status, DP_LINK_STATUS_SIZE, 100);

if (!radeon_connector->con_priv)
return false;
dig_connector = radeon_connector->con_priv;

ret = drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_LANE0_1_STATUS,
link_status, DP_LINK_STATUS_SIZE);
if (ret <= 0) {
return false;
}
Expand Down Expand Up @@ -612,7 +594,7 @@ void radeon_dp_set_rx_power_state(struct drm_connector *connector,

/* power up/down the sink */
if (dig_connector->dpcd[0] >= 0x11) {
radeon_write_dpcd_reg(radeon_connector,
drm_dp_dpcd_writeb(&dig_connector->dp_i2c_bus->aux,
DP_SET_POWER, power_state);
usleep_range(1000, 2000);
}
Expand All @@ -633,6 +615,7 @@ struct radeon_dp_link_train_info {
u8 link_status[DP_LINK_STATUS_SIZE];
u8 tries;
bool use_dpencoder;
struct drm_dp_aux *aux;
};

static void radeon_dp_update_vs_emph(struct radeon_dp_link_train_info *dp_info)
Expand All @@ -643,8 +626,8 @@ static void radeon_dp_update_vs_emph(struct radeon_dp_link_train_info *dp_info)
0, dp_info->train_set[0]); /* sets all lanes at once */

/* set the vs/emph on the sink */
radeon_dp_aux_native_write(dp_info->radeon_connector, DP_TRAINING_LANE0_SET,
dp_info->train_set, dp_info->dp_lane_count, 0);
drm_dp_dpcd_write(dp_info->aux, DP_TRAINING_LANE0_SET,
dp_info->train_set, dp_info->dp_lane_count);
}

static void radeon_dp_set_tp(struct radeon_dp_link_train_info *dp_info, int tp)
Expand Down Expand Up @@ -679,7 +662,7 @@ static void radeon_dp_set_tp(struct radeon_dp_link_train_info *dp_info, int tp)
}

/* enable training pattern on the sink */
radeon_write_dpcd_reg(dp_info->radeon_connector, DP_TRAINING_PATTERN_SET, tp);
drm_dp_dpcd_writeb(dp_info->aux, DP_TRAINING_PATTERN_SET, tp);
}

static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info)
Expand All @@ -693,26 +676,26 @@ static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info)

/* possibly enable downspread on the sink */
if (dp_info->dpcd[3] & 0x1)
radeon_write_dpcd_reg(dp_info->radeon_connector,
DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5);
drm_dp_dpcd_writeb(dp_info->aux,
DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5);
else
radeon_write_dpcd_reg(dp_info->radeon_connector,
DP_DOWNSPREAD_CTRL, 0);
drm_dp_dpcd_writeb(dp_info->aux,
DP_DOWNSPREAD_CTRL, 0);

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);
drm_dp_dpcd_writeb(dp_info->aux, DP_EDP_CONFIGURATION_SET, 1);
}

/* set the lane count on the sink */
tmp = dp_info->dp_lane_count;
if (drm_dp_enhanced_frame_cap(dp_info->dpcd))
tmp |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LANE_COUNT_SET, tmp);
drm_dp_dpcd_writeb(dp_info->aux, DP_LANE_COUNT_SET, tmp);

/* set the link rate on the sink */
tmp = drm_dp_link_rate_to_bw_code(dp_info->dp_clock);
radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LINK_BW_SET, tmp);
drm_dp_dpcd_writeb(dp_info->aux, DP_LINK_BW_SET, tmp);

/* start training on the source */
if (ASIC_IS_DCE4(dp_info->rdev) || !dp_info->use_dpencoder)
Expand All @@ -723,9 +706,9 @@ static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info)
dp_info->dp_clock, dp_info->enc_id, 0);

/* disable the training pattern on the sink */
radeon_write_dpcd_reg(dp_info->radeon_connector,
DP_TRAINING_PATTERN_SET,
DP_TRAINING_PATTERN_DISABLE);
drm_dp_dpcd_writeb(dp_info->aux,
DP_TRAINING_PATTERN_SET,
DP_TRAINING_PATTERN_DISABLE);

return 0;
}
Expand All @@ -735,9 +718,9 @@ static int radeon_dp_link_train_finish(struct radeon_dp_link_train_info *dp_info
udelay(400);

/* disable the training pattern on the sink */
radeon_write_dpcd_reg(dp_info->radeon_connector,
DP_TRAINING_PATTERN_SET,
DP_TRAINING_PATTERN_DISABLE);
drm_dp_dpcd_writeb(dp_info->aux,
DP_TRAINING_PATTERN_SET,
DP_TRAINING_PATTERN_DISABLE);

/* disable the training pattern on the source */
if (ASIC_IS_DCE4(dp_info->rdev) || !dp_info->use_dpencoder)
Expand Down Expand Up @@ -914,7 +897,7 @@ void radeon_dp_link_train(struct drm_encoder *encoder,
else
dp_info.enc_id |= ATOM_DP_CONFIG_LINK_A;

tmp = radeon_read_dpcd_reg(radeon_connector, DP_MAX_LANE_COUNT);
drm_dp_dpcd_readb(&dig_connector->dp_i2c_bus->aux, DP_MAX_LANE_COUNT, &tmp);
if (ASIC_IS_DCE5(rdev) && (tmp & DP_TPS3_SUPPORTED))
dp_info.tp3_supported = true;
else
Expand All @@ -927,6 +910,7 @@ void radeon_dp_link_train(struct drm_encoder *encoder,
dp_info.radeon_connector = radeon_connector;
dp_info.dp_lane_count = dig_connector->dp_lane_count;
dp_info.dp_clock = dig_connector->dp_clock;
dp_info.aux = &dig_connector->dp_i2c_bus->aux;

if (radeon_dp_link_train_init(&dp_info))
goto done;
Expand Down
17 changes: 14 additions & 3 deletions drivers/gpu/drm/radeon/radeon_connectors.c
Original file line number Diff line number Diff line change
Expand Up @@ -1595,6 +1595,7 @@ radeon_add_atom_connector(struct drm_device *dev,
uint32_t subpixel_order = SubPixelNone;
bool shared_ddc = false;
bool is_dp_bridge = false;
bool has_aux = false;

if (connector_type == DRM_MODE_CONNECTOR_Unknown)
return;
Expand Down Expand Up @@ -1672,7 +1673,9 @@ radeon_add_atom_connector(struct drm_device *dev,
radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch");
else
radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch");
if (!radeon_dig_connector->dp_i2c_bus)
if (radeon_dig_connector->dp_i2c_bus)
has_aux = true;
else
DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
if (!radeon_connector->ddc_bus)
Expand Down Expand Up @@ -1895,7 +1898,9 @@ radeon_add_atom_connector(struct drm_device *dev,
if (!radeon_dig_connector->dp_i2c_bus)
DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
if (!radeon_connector->ddc_bus)
if (radeon_connector->ddc_bus)
has_aux = true;
else
DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
}
subpixel_order = SubPixelHorizontalRGB;
Expand Down Expand Up @@ -1939,7 +1944,9 @@ radeon_add_atom_connector(struct drm_device *dev,
if (i2c_bus->valid) {
/* add DP i2c bus */
radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch");
if (!radeon_dig_connector->dp_i2c_bus)
if (radeon_dig_connector->dp_i2c_bus)
has_aux = true;
else
DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
if (!radeon_connector->ddc_bus)
Expand Down Expand Up @@ -2000,6 +2007,10 @@ radeon_add_atom_connector(struct drm_device *dev,

connector->display_info.subpixel_order = subpixel_order;
drm_sysfs_connector_add(connector);

if (has_aux)
radeon_dp_aux_init(radeon_connector);

return;

failed:
Expand Down
Loading

0 comments on commit 496263b

Please sign in to comment.