1
0
Fork 0

Merge remote branch 'korg/drm-radeon-dp' into drm-linus

This merges the radeon KMS DisplayPort and hotplug detect support.

Tested on RV635 DP card with a Dell 2408 monitor.

Conflicts:
	drivers/gpu/drm/drm_fb_helper.c
hifive-unleashed-5.1
Dave Airlie 2009-12-08 14:29:15 +10:00
commit 7b0a9e8302
24 changed files with 2657 additions and 323 deletions

View File

@ -49,7 +49,7 @@ radeon-y += radeon_device.o radeon_kms.o \
radeon_cs.o radeon_bios.o radeon_benchmark.o r100.o r300.o r420.o \
rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \
r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \
r600_blit_kms.o radeon_pm.o
r600_blit_kms.o radeon_pm.o atombios_dp.o
radeon-$(CONFIG_COMPAT) += radeon_ioc32.o

View File

@ -263,10 +263,10 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
case ATOM_ARG_FB:
idx = U8(*ptr);
(*ptr)++;
val = gctx->scratch[((gctx->fb_base + idx) / 4)];
if (print)
DEBUG("FB[0x%02X]", idx);
printk(KERN_INFO "FB access is not implemented.\n");
return 0;
break;
case ATOM_ARG_IMM:
switch (align) {
case ATOM_SRC_DWORD:
@ -488,9 +488,9 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
case ATOM_ARG_FB:
idx = U8(*ptr);
(*ptr)++;
gctx->scratch[((gctx->fb_base + idx) / 4)] = val;
DEBUG("FB[0x%02X]", idx);
printk(KERN_INFO "FB access is not implemented.\n");
return;
break;
case ATOM_ARG_PLL:
idx = U8(*ptr);
(*ptr)++;
@ -1214,3 +1214,28 @@ void atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev,
*crev = CU8(idx + 3);
return;
}
int atom_allocate_fb_scratch(struct atom_context *ctx)
{
int index = GetIndexIntoMasterTable(DATA, VRAM_UsageByFirmware);
uint16_t data_offset;
int usage_bytes;
struct _ATOM_VRAM_USAGE_BY_FIRMWARE *firmware_usage;
atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset);
firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset);
DRM_DEBUG("atom firmware requested %08x %dkb\n",
firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware,
firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb);
usage_bytes = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb * 1024;
if (usage_bytes == 0)
usage_bytes = 20 * 1024;
/* allocate some scratch memory */
ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL);
if (!ctx->scratch)
return -ENOMEM;
return 0;
}

View File

@ -132,6 +132,7 @@ struct atom_context {
uint8_t shift;
int cs_equal, cs_above;
int io_mode;
uint32_t *scratch;
};
extern int atom_debug;
@ -142,6 +143,7 @@ int atom_asic_init(struct atom_context *);
void atom_destroy(struct atom_context *);
void atom_parse_data_header(struct atom_context *ctx, int index, uint16_t *size, uint8_t *frev, uint8_t *crev, uint16_t *data_start);
void atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t *frev, uint8_t *crev);
int atom_allocate_fb_scratch(struct atom_context *ctx);
#include "atom-types.h"
#include "atombios.h"
#include "ObjectID.h"

View File

@ -2680,7 +2680,7 @@ typedef struct _ATOM_I2C_RECORD {
typedef struct _ATOM_HPD_INT_RECORD {
ATOM_COMMON_RECORD_HEADER sheader;
UCHAR ucHPDIntGPIOID; /* Corresponding block in GPIO_PIN_INFO table gives the pin info */
UCHAR ucPluggged_PinState;
UCHAR ucPlugged_PinState;
} ATOM_HPD_INT_RECORD;
typedef struct _ATOM_OUTPUT_PROTECTION_RECORD {

View File

@ -0,0 +1,790 @@
/*
* Copyright 2007-8 Advanced Micro Devices, Inc.
* Copyright 2008 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Dave Airlie
* Alex Deucher
*/
#include "drmP.h"
#include "radeon_drm.h"
#include "radeon.h"
#include "atom.h"
#include "atom-bits.h"
#include "drm_dp_helper.h"
/* move these to drm_dp_helper.c/h */
#define DP_LINK_CONFIGURATION_SIZE 9
#define DP_LINK_STATUS_SIZE 6
#define DP_DPCD_SIZE 8
static char *voltage_names[] = {
"0.4V", "0.6V", "0.8V", "1.2V"
};
static char *pre_emph_names[] = {
"0dB", "3.5dB", "6dB", "9.5dB"
};
static const int dp_clocks[] = {
54000, /* 1 lane, 1.62 Ghz */
90000, /* 1 lane, 2.70 Ghz */
108000, /* 2 lane, 1.62 Ghz */
180000, /* 2 lane, 2.70 Ghz */
216000, /* 4 lane, 1.62 Ghz */
360000, /* 4 lane, 2.70 Ghz */
};
static const int num_dp_clocks = sizeof(dp_clocks) / sizeof(int);
/* common helper functions */
static int dp_lanes_for_mode_clock(u8 dpcd[DP_DPCD_SIZE], int mode_clock)
{
int i;
u8 max_link_bw;
u8 max_lane_count;
if (!dpcd)
return 0;
max_link_bw = dpcd[DP_MAX_LINK_RATE];
max_lane_count = dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;
switch (max_link_bw) {
case DP_LINK_BW_1_62:
default:
for (i = 0; i < num_dp_clocks; i++) {
if (i % 2)
continue;
switch (max_lane_count) {
case 1:
if (i > 1)
return 0;
break;
case 2:
if (i > 3)
return 0;
break;
case 4:
default:
break;
}
if (dp_clocks[i] > mode_clock) {
if (i < 2)
return 1;
else if (i < 4)
return 2;
else
return 4;
}
}
break;
case DP_LINK_BW_2_7:
for (i = 0; i < num_dp_clocks; i++) {
switch (max_lane_count) {
case 1:
if (i > 1)
return 0;
break;
case 2:
if (i > 3)
return 0;
break;
case 4:
default:
break;
}
if (dp_clocks[i] > mode_clock) {
if (i < 2)
return 1;
else if (i < 4)
return 2;
else
return 4;
}
}
break;
}
return 0;
}
static int dp_link_clock_for_mode_clock(u8 dpcd[DP_DPCD_SIZE], int mode_clock)
{
int i;
u8 max_link_bw;
u8 max_lane_count;
if (!dpcd)
return 0;
max_link_bw = dpcd[DP_MAX_LINK_RATE];
max_lane_count = dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;
switch (max_link_bw) {
case DP_LINK_BW_1_62:
default:
for (i = 0; i < num_dp_clocks; i++) {
if (i % 2)
continue;
switch (max_lane_count) {
case 1:
if (i > 1)
return 0;
break;
case 2:
if (i > 3)
return 0;
break;
case 4:
default:
break;
}
if (dp_clocks[i] > mode_clock)
return 162000;
}
break;
case DP_LINK_BW_2_7:
for (i = 0; i < num_dp_clocks; i++) {
switch (max_lane_count) {
case 1:
if (i > 1)
return 0;
break;
case 2:
if (i > 3)
return 0;
break;
case 4:
default:
break;
}
if (dp_clocks[i] > mode_clock)
return (i % 2) ? 270000 : 162000;
}
}
return 0;
}
int dp_mode_valid(u8 dpcd[DP_DPCD_SIZE], int mode_clock)
{
int lanes = dp_lanes_for_mode_clock(dpcd, mode_clock);
int bw = dp_lanes_for_mode_clock(dpcd, mode_clock);
if ((lanes == 0) || (bw == 0))
return MODE_CLOCK_HIGH;
return MODE_OK;
}
static u8 dp_link_status(u8 link_status[DP_LINK_STATUS_SIZE], int r)
{
return link_status[r - DP_LANE0_1_STATUS];
}
static u8 dp_get_lane_status(u8 link_status[DP_LINK_STATUS_SIZE],
int lane)
{
int i = DP_LANE0_1_STATUS + (lane >> 1);
int s = (lane & 1) * 4;
u8 l = dp_link_status(link_status, i);
return (l >> s) & 0xf;
}
static bool dp_clock_recovery_ok(u8 link_status[DP_LINK_STATUS_SIZE],
int lane_count)
{
int lane;
u8 lane_status;
for (lane = 0; lane < lane_count; lane++) {
lane_status = dp_get_lane_status(link_status, lane);
if ((lane_status & DP_LANE_CR_DONE) == 0)
return false;
}
return true;
}
static bool dp_channel_eq_ok(u8 link_status[DP_LINK_STATUS_SIZE],
int lane_count)
{
u8 lane_align;
u8 lane_status;
int lane;
lane_align = dp_link_status(link_status,
DP_LANE_ALIGN_STATUS_UPDATED);
if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
return false;
for (lane = 0; lane < lane_count; lane++) {
lane_status = dp_get_lane_status(link_status, lane);
if ((lane_status & DP_CHANNEL_EQ_BITS) != DP_CHANNEL_EQ_BITS)
return false;
}
return true;
}
static u8 dp_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE],
int lane)
{
int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
int s = ((lane & 1) ?
DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT :
DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT);
u8 l = dp_link_status(link_status, i);
return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;
}
static u8 dp_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_SIZE],
int lane)
{
int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
int s = ((lane & 1) ?
DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT :
DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT);
u8 l = dp_link_status(link_status, i);
return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
}
/* XXX fix me -- chip specific */
#define DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_1200
static u8 dp_pre_emphasis_max(u8 voltage_swing)
{
switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
case DP_TRAIN_VOLTAGE_SWING_400:
return DP_TRAIN_PRE_EMPHASIS_6;
case DP_TRAIN_VOLTAGE_SWING_600:
return DP_TRAIN_PRE_EMPHASIS_6;
case DP_TRAIN_VOLTAGE_SWING_800:
return DP_TRAIN_PRE_EMPHASIS_3_5;
case DP_TRAIN_VOLTAGE_SWING_1200:
default:
return DP_TRAIN_PRE_EMPHASIS_0;
}
}
static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
int lane_count,
u8 train_set[4])
{
u8 v = 0;
u8 p = 0;
int lane;
for (lane = 0; lane < lane_count; lane++) {
u8 this_v = dp_get_adjust_request_voltage(link_status, lane);
u8 this_p = dp_get_adjust_request_pre_emphasis(link_status, lane);
DRM_DEBUG("requested signal parameters: lane %d voltage %s pre_emph %s\n",
lane,
voltage_names[this_v >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
pre_emph_names[this_p >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);
if (this_v > v)
v = this_v;
if (this_p > p)
p = this_p;
}
if (v >= DP_VOLTAGE_MAX)
v = DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED;
if (p >= dp_pre_emphasis_max(v))
p = dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
DRM_DEBUG("using signal parameters: voltage %s pre_emph %s\n",
voltage_names[(v & DP_TRAIN_VOLTAGE_SWING_MASK) >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
pre_emph_names[(p & DP_TRAIN_PRE_EMPHASIS_MASK) >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);
for (lane = 0; lane < 4; lane++)
train_set[lane] = v | p;
}
/* radeon aux chan functions */
bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes,
int num_bytes, u8 *read_byte,
u8 read_buf_len, u8 delay)
{
struct drm_device *dev = chan->dev;
struct radeon_device *rdev = dev->dev_private;
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.lpAuxRequest = 0;
args.lpDataOut = 16;
args.ucDataOutLen = 0;
args.ucChannelID = chan->rec.i2c_id;
args.ucDelay = delay / 10;
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
if (args.ucReplyStatus) {
DRM_DEBUG("failed to get auxch %02x%02x %02x %02x 0x%02x %02x\n",
req_bytes[1], req_bytes[0], req_bytes[2], req_bytes[3],
chan->rec.i2c_id, args.ucReplyStatus);
return false;
}
if (args.ucDataOutLen && read_byte && read_buf_len) {
if (read_buf_len < args.ucDataOutLen) {
DRM_ERROR("Buffer to small for return answer %d %d\n",
read_buf_len, args.ucDataOutLen);
return false;
}
{
int len = min(read_buf_len, args.ucDataOutLen);
memcpy(read_byte, base + 16, len);
}
}
return true;
}
bool radeon_dp_aux_native_write(struct radeon_connector *radeon_connector, uint16_t address,
uint8_t send_bytes, uint8_t *send)
{
struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
u8 msg[20];
u8 msg_len, dp_msg_len;
bool ret;
dp_msg_len = 4;
msg[0] = address;
msg[1] = address >> 8;
msg[2] = AUX_NATIVE_WRITE << 4;
dp_msg_len += send_bytes;
msg[3] = (dp_msg_len << 4) | (send_bytes - 1);
if (send_bytes > 16)
return false;
memcpy(&msg[4], send, send_bytes);
msg_len = 4 + send_bytes;
ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus, msg, msg_len, NULL, 0, 0);
return ret;
}
bool radeon_dp_aux_native_read(struct radeon_connector *radeon_connector, uint16_t address,
uint8_t delay, uint8_t expected_bytes,
uint8_t *read_p)
{
struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
u8 msg[20];
u8 msg_len, dp_msg_len;
bool ret = false;
msg_len = 4;
dp_msg_len = 4;
msg[0] = address;
msg[1] = address >> 8;
msg[2] = AUX_NATIVE_READ << 4;
msg[3] = (dp_msg_len) << 4;
msg[3] |= expected_bytes - 1;
ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus, msg, msg_len, read_p, expected_bytes, delay);
return ret;
}
/* radeon dp functions */
static u8 radeon_dp_encoder_service(struct radeon_device *rdev, int action, int dp_clock,
uint8_t ucconfig, uint8_t lane_num)
{
DP_ENCODER_SERVICE_PARAMETERS args;
int index = GetIndexIntoMasterTable(COMMAND, DPEncoderService);
memset(&args, 0, sizeof(args));
args.ucLinkClock = dp_clock / 10;
args.ucConfig = ucconfig;
args.ucAction = action;
args.ucLaneNum = lane_num;
args.ucStatus = 0;
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
return args.ucStatus;
}
u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector)
{
struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
struct drm_device *dev = radeon_connector->base.dev;
struct radeon_device *rdev = dev->dev_private;
return radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_GET_SINK_TYPE, 0,
dig_connector->dp_i2c_bus->rec.i2c_id, 0);
}
bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector)
{
struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
u8 msg[25];
int ret;
ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCD_REV, 0, 8, msg);
if (ret) {
memcpy(dig_connector->dpcd, msg, 8);
{
int i;
DRM_DEBUG("DPCD: ");
for (i = 0; i < 8; i++)
DRM_DEBUG("%02x ", msg[i]);
DRM_DEBUG("\n");
}
return true;
}
dig_connector->dpcd[0] = 0;
return false;
}
void radeon_dp_set_link_config(struct drm_connector *connector,
struct drm_display_mode *mode)
{
struct radeon_connector *radeon_connector;
struct radeon_connector_atom_dig *dig_connector;
if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
return;
radeon_connector = to_radeon_connector(connector);
if (!radeon_connector->con_priv)
return;
dig_connector = radeon_connector->con_priv;
dig_connector->dp_clock =
dp_link_clock_for_mode_clock(dig_connector->dpcd, mode->clock);
dig_connector->dp_lane_count =
dp_lanes_for_mode_clock(dig_connector->dpcd, mode->clock);
}
int radeon_dp_mode_valid_helper(struct radeon_connector *radeon_connector,
struct drm_display_mode *mode)
{
struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
return dp_mode_valid(dig_connector->dpcd, mode->clock);
}
static bool atom_dp_get_link_status(struct radeon_connector *radeon_connector,
u8 link_status[DP_LINK_STATUS_SIZE])
{
int ret;
ret = radeon_dp_aux_native_read(radeon_connector, DP_LANE0_1_STATUS, 100,
DP_LINK_STATUS_SIZE, link_status);
if (!ret) {
DRM_ERROR("displayport link status failed\n");
return false;
}
DRM_DEBUG("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]);
return true;
}
bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector)
{
struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
u8 link_status[DP_LINK_STATUS_SIZE];
if (!atom_dp_get_link_status(radeon_connector, link_status))
return false;
if (dp_channel_eq_ok(link_status, dig_connector->dp_lane_count))
return false;
return true;
}
static void dp_set_power(struct radeon_connector *radeon_connector, u8 power_state)
{
struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
if (dig_connector->dpcd[0] >= 0x11) {
radeon_dp_aux_native_write(radeon_connector, DP_SET_POWER, 1,
&power_state);
}
}
static void dp_set_downspread(struct radeon_connector *radeon_connector, u8 downspread)
{
radeon_dp_aux_native_write(radeon_connector, DP_DOWNSPREAD_CTRL, 1,
&downspread);
}
static void dp_set_link_bw_lanes(struct radeon_connector *radeon_connector,
u8 link_configuration[DP_LINK_CONFIGURATION_SIZE])
{
radeon_dp_aux_native_write(radeon_connector, DP_LINK_BW_SET, 2,
link_configuration);
}
static void dp_update_dpvs_emph(struct radeon_connector *radeon_connector,
struct drm_encoder *encoder,
u8 train_set[4])
{
struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
int i;
for (i = 0; i < dig_connector->dp_lane_count; i++)
atombios_dig_transmitter_setup(encoder,
ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH,
i, train_set[i]);
radeon_dp_aux_native_write(radeon_connector, DP_TRAINING_LANE0_SET,
dig_connector->dp_lane_count, train_set);
}
static void dp_set_training(struct radeon_connector *radeon_connector,
u8 training)
{
radeon_dp_aux_native_write(radeon_connector, DP_TRAINING_PATTERN_SET,
1, &training);
}
void dp_link_train(struct drm_encoder *encoder,
struct drm_connector *connector)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig;
struct radeon_connector *radeon_connector;
struct radeon_connector_atom_dig *dig_connector;
int enc_id = 0;
bool clock_recovery, channel_eq;
u8 link_status[DP_LINK_STATUS_SIZE];
u8 link_configuration[DP_LINK_CONFIGURATION_SIZE];
u8 tries, voltage;
u8 train_set[4];
int i;
if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
return;
if (!radeon_encoder->enc_priv)
return;
dig = radeon_encoder->enc_priv;
radeon_connector = to_radeon_connector(connector);
if (!radeon_connector->con_priv)
return;
dig_connector = radeon_connector->con_priv;
if (ASIC_IS_DCE32(rdev)) {
if (dig->dig_block)
enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER;
else
enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER;
if (dig_connector->linkb)
enc_id |= ATOM_DP_CONFIG_LINK_B;
else
enc_id |= ATOM_DP_CONFIG_LINK_A;
} else {
if (dig_connector->linkb)
enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER | ATOM_DP_CONFIG_LINK_B;
else
enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER | ATOM_DP_CONFIG_LINK_A;
}
memset(link_configuration, 0, DP_LINK_CONFIGURATION_SIZE);
if (dig_connector->dp_clock == 270000)
link_configuration[0] = DP_LINK_BW_2_7;
else
link_configuration[0] = DP_LINK_BW_1_62;
link_configuration[1] = dig_connector->dp_lane_count;
if (dig_connector->dpcd[0] >= 0x11)
link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
/* power up the sink */
dp_set_power(radeon_connector, DP_SET_POWER_D0);
/* disable the training pattern on the sink */
dp_set_training(radeon_connector, DP_TRAINING_PATTERN_DISABLE);
/* set link bw and lanes on the sink */
dp_set_link_bw_lanes(radeon_connector, link_configuration);
/* disable downspread on the sink */
dp_set_downspread(radeon_connector, 0);
/* start training on the source */
radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_START,
dig_connector->dp_clock, enc_id, 0);
/* set training pattern 1 on the source */
radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL,
dig_connector->dp_clock, enc_id, 0);
/* set initial vs/emph */
memset(train_set, 0, 4);
udelay(400);
/* set training pattern 1 on the sink */
dp_set_training(radeon_connector, DP_TRAINING_PATTERN_1);
dp_update_dpvs_emph(radeon_connector, encoder, train_set);
/* clock recovery loop */
clock_recovery = false;
tries = 0;
voltage = 0xff;
for (;;) {
udelay(100);
if (!atom_dp_get_link_status(radeon_connector, link_status))
break;
if (dp_clock_recovery_ok(link_status, dig_connector->dp_lane_count)) {
clock_recovery = true;
break;
}
for (i = 0; i < dig_connector->dp_lane_count; i++) {
if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
break;
}
if (i == dig_connector->dp_lane_count) {
DRM_ERROR("clock recovery reached max voltage\n");
break;
}
if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
++tries;
if (tries == 5) {
DRM_ERROR("clock recovery tried 5 times\n");
break;
}
} else
tries = 0;
voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
/* Compute new train_set as requested by sink */
dp_get_adjust_train(link_status, dig_connector->dp_lane_count, train_set);
dp_update_dpvs_emph(radeon_connector, encoder, train_set);
}
if (!clock_recovery)
DRM_ERROR("clock recovery failed\n");
else
DRM_DEBUG("clock recovery at voltage %d pre-emphasis %d\n",
train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
(train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK) >>
DP_TRAIN_PRE_EMPHASIS_SHIFT);
/* set training pattern 2 on the sink */
dp_set_training(radeon_connector, DP_TRAINING_PATTERN_2);
/* set training pattern 2 on the source */
radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL,
dig_connector->dp_clock, enc_id, 1);
/* channel equalization loop */
tries = 0;
channel_eq = false;
for (;;) {
udelay(400);
if (!atom_dp_get_link_status(radeon_connector, link_status))
break;
if (dp_channel_eq_ok(link_status, dig_connector->dp_lane_count)) {
channel_eq = true;
break;
}
/* Try 5 times */
if (tries > 5) {
DRM_ERROR("channel eq failed: 5 tries\n");
break;
}
/* Compute new train_set as requested by sink */
dp_get_adjust_train(link_status, dig_connector->dp_lane_count, train_set);
dp_update_dpvs_emph(radeon_connector, encoder, train_set);
tries++;
}
if (!channel_eq)
DRM_ERROR("channel eq failed\n");
else
DRM_DEBUG("channel eq at voltage %d pre-emphasis %d\n",
train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
(train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
>> DP_TRAIN_PRE_EMPHASIS_SHIFT);
/* disable the training pattern on the sink */
dp_set_training(radeon_connector, DP_TRAINING_PATTERN_DISABLE);
radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_COMPLETE,
dig_connector->dp_clock, enc_id, 0);
}
int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
uint8_t write_byte, uint8_t *read_byte)
{
struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
struct radeon_i2c_chan *auxch = (struct radeon_i2c_chan *)adapter;
int ret = 0;
uint16_t address = algo_data->address;
uint8_t msg[5];
uint8_t reply[2];
int msg_len, dp_msg_len;
int reply_bytes;
/* Set up the command byte */
if (mode & MODE_I2C_READ)
msg[2] = AUX_I2C_READ << 4;
else
msg[2] = AUX_I2C_WRITE << 4;
if (!(mode & MODE_I2C_STOP))
msg[2] |= AUX_I2C_MOT << 4;
msg[0] = address;
msg[1] = address >> 8;
reply_bytes = 1;
msg_len = 4;
dp_msg_len = 3;
switch (mode) {
case MODE_I2C_WRITE:
msg[4] = write_byte;
msg_len++;
dp_msg_len += 2;
break;
case MODE_I2C_READ:
dp_msg_len += 1;
break;
default:
break;
}
msg[3] = (dp_msg_len) << 4;
ret = radeon_process_aux_ch(auxch, msg, msg_len, reply, reply_bytes, 0);
if (ret) {
if (read_byte)
*read_byte = reply[0];
return reply_bytes;
}
return -EREMOTEIO;
}

View File

@ -65,6 +65,95 @@ MODULE_FIRMWARE(FIRMWARE_R520);
* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280
*/
/* hpd for digital panel detect/disconnect */
bool r100_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd)
{
bool connected = false;
switch (hpd) {
case RADEON_HPD_1:
if (RREG32(RADEON_FP_GEN_CNTL) & RADEON_FP_DETECT_SENSE)
connected = true;
break;
case RADEON_HPD_2:
if (RREG32(RADEON_FP2_GEN_CNTL) & RADEON_FP2_DETECT_SENSE)
connected = true;
break;
default:
break;
}
return connected;
}
void r100_hpd_set_polarity(struct radeon_device *rdev,
enum radeon_hpd_id hpd)
{
u32 tmp;
bool connected = r100_hpd_sense(rdev, hpd);
switch (hpd) {
case RADEON_HPD_1:
tmp = RREG32(RADEON_FP_GEN_CNTL);
if (connected)
tmp &= ~RADEON_FP_DETECT_INT_POL;
else
tmp |= RADEON_FP_DETECT_INT_POL;
WREG32(RADEON_FP_GEN_CNTL, tmp);
break;
case RADEON_HPD_2:
tmp = RREG32(RADEON_FP2_GEN_CNTL);
if (connected)
tmp &= ~RADEON_FP2_DETECT_INT_POL;
else
tmp |= RADEON_FP2_DETECT_INT_POL;
WREG32(RADEON_FP2_GEN_CNTL, tmp);
break;
default:
break;
}
}
void r100_hpd_init(struct radeon_device *rdev)
{
struct drm_device *dev = rdev->ddev;
struct drm_connector *connector;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
switch (radeon_connector->hpd.hpd) {
case RADEON_HPD_1:
rdev->irq.hpd[0] = true;
break;
case RADEON_HPD_2:
rdev->irq.hpd[1] = true;
break;
default:
break;
}
}
r100_irq_set(rdev);
}
void r100_hpd_fini(struct radeon_device *rdev)
{
struct drm_device *dev = rdev->ddev;
struct drm_connector *connector;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
switch (radeon_connector->hpd.hpd) {
case RADEON_HPD_1:
rdev->irq.hpd[0] = false;
break;
case RADEON_HPD_2:
rdev->irq.hpd[1] = false;
break;
default:
break;
}
}
}
/*
* PCI GART
*/
@ -163,6 +252,12 @@ int r100_irq_set(struct radeon_device *rdev)
if (rdev->irq.crtc_vblank_int[1]) {
tmp |= RADEON_CRTC2_VBLANK_MASK;
}
if (rdev->irq.hpd[0]) {
tmp |= RADEON_FP_DETECT_MASK;
}
if (rdev->irq.hpd[1]) {
tmp |= RADEON_FP2_DETECT_MASK;
}
WREG32(RADEON_GEN_INT_CNTL, tmp);
return 0;
}
@ -181,8 +276,9 @@ void r100_irq_disable(struct radeon_device *rdev)
static inline uint32_t r100_irq_ack(struct radeon_device *rdev)
{
uint32_t irqs = RREG32(RADEON_GEN_INT_STATUS);
uint32_t irq_mask = RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT |
RADEON_CRTC2_VBLANK_STAT;
uint32_t irq_mask = RADEON_SW_INT_TEST |
RADEON_CRTC_VBLANK_STAT | RADEON_CRTC2_VBLANK_STAT |
RADEON_FP_DETECT_STAT | RADEON_FP2_DETECT_STAT;
if (irqs) {
WREG32(RADEON_GEN_INT_STATUS, irqs);
@ -193,6 +289,7 @@ static inline uint32_t r100_irq_ack(struct radeon_device *rdev)
int r100_irq_process(struct radeon_device *rdev)
{
uint32_t status, msi_rearm;
bool queue_hotplug = false;
status = r100_irq_ack(rdev);
if (!status) {
@ -213,8 +310,18 @@ int r100_irq_process(struct radeon_device *rdev)
if (status & RADEON_CRTC2_VBLANK_STAT) {
drm_handle_vblank(rdev->ddev, 1);
}
if (status & RADEON_FP_DETECT_STAT) {
queue_hotplug = true;
DRM_DEBUG("HPD1\n");
}
if (status & RADEON_FP2_DETECT_STAT) {
queue_hotplug = true;
DRM_DEBUG("HPD2\n");
}
status = r100_irq_ack(rdev);
}
if (queue_hotplug)
queue_work(rdev->wq, &rdev->hotplug_work);
if (rdev->msi_enabled) {
switch (rdev->family) {
case CHIP_RS400:

View File

@ -716,6 +716,8 @@
#define AVIVO_DVOA_BIT_DEPTH_CONTROL 0x7988
#define AVIVO_DC_GPIO_HPD_A 0x7e94
#define AVIVO_GPIO_0 0x7e30
#define AVIVO_GPIO_1 0x7e40
#define AVIVO_GPIO_2 0x7e50

View File

@ -74,6 +74,281 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev);
void r600_gpu_init(struct radeon_device *rdev);
void r600_fini(struct radeon_device *rdev);
/* hpd for digital panel detect/disconnect */
bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd)
{
bool connected = false;
if (ASIC_IS_DCE3(rdev)) {
switch (hpd) {
case RADEON_HPD_1:
if (RREG32(DC_HPD1_INT_STATUS) & DC_HPDx_SENSE)
connected = true;
break;
case RADEON_HPD_2:
if (RREG32(DC_HPD2_INT_STATUS) & DC_HPDx_SENSE)
connected = true;
break;
case RADEON_HPD_3:
if (RREG32(DC_HPD3_INT_STATUS) & DC_HPDx_SENSE)
connected = true;
break;
case RADEON_HPD_4:
if (RREG32(DC_HPD4_INT_STATUS) & DC_HPDx_SENSE)
connected = true;
break;
/* DCE 3.2 */
case RADEON_HPD_5:
if (RREG32(DC_HPD5_INT_STATUS) & DC_HPDx_SENSE)
connected = true;
break;
case RADEON_HPD_6:
if (RREG32(DC_HPD6_INT_STATUS) & DC_HPDx_SENSE)
connected = true;
break;
default:
break;
}
} else {
switch (hpd) {
case RADEON_HPD_1:
if (RREG32(DC_HOT_PLUG_DETECT1_INT_STATUS) & DC_HOT_PLUG_DETECTx_SENSE)
connected = true;
break;
case RADEON_HPD_2:
if (RREG32(DC_HOT_PLUG_DETECT2_INT_STATUS) & DC_HOT_PLUG_DETECTx_SENSE)
connected = true;
break;
case RADEON_HPD_3:
if (RREG32(DC_HOT_PLUG_DETECT3_INT_STATUS) & DC_HOT_PLUG_DETECTx_SENSE)
connected = true;
break;
default:
break;
}
}
return connected;
}
void r600_hpd_set_polarity(struct radeon_device *rdev,
enum radeon_hpd_id hpd)
{
u32 tmp;
bool connected = r600_hpd_sense(rdev, hpd);
if (ASIC_IS_DCE3(rdev)) {
switch (hpd) {
case RADEON_HPD_1:
tmp = RREG32(DC_HPD1_INT_CONTROL);
if (connected)
tmp &= ~DC_HPDx_INT_POLARITY;
else
tmp |= DC_HPDx_INT_POLARITY;
WREG32(DC_HPD1_INT_CONTROL, tmp);
break;
case RADEON_HPD_2:
tmp = RREG32(DC_HPD2_INT_CONTROL);
if (connected)
tmp &= ~DC_HPDx_INT_POLARITY;
else
tmp |= DC_HPDx_INT_POLARITY;
WREG32(DC_HPD2_INT_CONTROL, tmp);
break;
case RADEON_HPD_3:
tmp = RREG32(DC_HPD3_INT_CONTROL);
if (connected)
tmp &= ~DC_HPDx_INT_POLARITY;
else
tmp |= DC_HPDx_INT_POLARITY;
WREG32(DC_HPD3_INT_CONTROL, tmp);
break;
case RADEON_HPD_4:
tmp = RREG32(DC_HPD4_INT_CONTROL);
if (connected)
tmp &= ~DC_HPDx_INT_POLARITY;
else
tmp |= DC_HPDx_INT_POLARITY;
WREG32(DC_HPD4_INT_CONTROL, tmp);
break;
case RADEON_HPD_5:
tmp = RREG32(DC_HPD5_INT_CONTROL);
if (connected)
tmp &= ~DC_HPDx_INT_POLARITY;
else
tmp |= DC_HPDx_INT_POLARITY;
WREG32(DC_HPD5_INT_CONTROL, tmp);
break;
/* DCE 3.2 */
case RADEON_HPD_6:
tmp = RREG32(DC_HPD6_INT_CONTROL);
if (connected)
tmp &= ~DC_HPDx_INT_POLARITY;
else
tmp |= DC_HPDx_INT_POLARITY;
WREG32(DC_HPD6_INT_CONTROL, tmp);
break;
default:
break;
}
} else {
switch (hpd) {
case RADEON_HPD_1:
tmp = RREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL);
if (connected)
tmp &= ~DC_HOT_PLUG_DETECTx_INT_POLARITY;
else
tmp |= DC_HOT_PLUG_DETECTx_INT_POLARITY;
WREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL, tmp);
break;
case RADEON_HPD_2:
tmp = RREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL);
if (connected)
tmp &= ~DC_HOT_PLUG_DETECTx_INT_POLARITY;
else
tmp |= DC_HOT_PLUG_DETECTx_INT_POLARITY;
WREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL, tmp);
break;
case RADEON_HPD_3:
tmp = RREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL);
if (connected)
tmp &= ~DC_HOT_PLUG_DETECTx_INT_POLARITY;
else
tmp |= DC_HOT_PLUG_DETECTx_INT_POLARITY;
WREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL, tmp);
break;
default:
break;
}
}
}
void r600_hpd_init(struct radeon_device *rdev)
{
struct drm_device *dev = rdev->ddev;
struct drm_connector *connector;
if (ASIC_IS_DCE3(rdev)) {
u32 tmp = DC_HPDx_CONNECTION_TIMER(0x9c4) | DC_HPDx_RX_INT_TIMER(0xfa);
if (ASIC_IS_DCE32(rdev))
tmp |= DC_HPDx_EN;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
switch (radeon_connector->hpd.hpd) {
case RADEON_HPD_1:
WREG32(DC_HPD1_CONTROL, tmp);
rdev->irq.hpd[0] = true;
break;
case RADEON_HPD_2:
WREG32(DC_HPD2_CONTROL, tmp);
rdev->irq.hpd[1] = true;
break;
case RADEON_HPD_3:
WREG32(DC_HPD3_CONTROL, tmp);
rdev->irq.hpd[2] = true;
break;
case RADEON_HPD_4:
WREG32(DC_HPD4_CONTROL, tmp);
rdev->irq.hpd[3] = true;
break;
/* DCE 3.2 */
case RADEON_HPD_5:
WREG32(DC_HPD5_CONTROL, tmp);
rdev->irq.hpd[4] = true;
break;
case RADEON_HPD_6:
WREG32(DC_HPD6_CONTROL, tmp);
rdev->irq.hpd[5] = true;
break;
default:
break;
}
}
} else {
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
switch (radeon_connector->hpd.hpd) {
case RADEON_HPD_1:
WREG32(DC_HOT_PLUG_DETECT1_CONTROL, DC_HOT_PLUG_DETECTx_EN);
rdev->irq.hpd[0] = true;
break;
case RADEON_HPD_2:
WREG32(DC_HOT_PLUG_DETECT2_CONTROL, DC_HOT_PLUG_DETECTx_EN);
rdev->irq.hpd[1] = true;
break;
case RADEON_HPD_3:
WREG32(DC_HOT_PLUG_DETECT3_CONTROL, DC_HOT_PLUG_DETECTx_EN);
rdev->irq.hpd[2] = true;
break;
default:
break;
}
}
}
r600_irq_set(rdev);
}
void r600_hpd_fini(struct radeon_device *rdev)
{
struct drm_device *dev = rdev->ddev;
struct drm_connector *connector;
if (ASIC_IS_DCE3(rdev)) {
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
switch (radeon_connector->hpd.hpd) {
case RADEON_HPD_1:
WREG32(DC_HPD1_CONTROL, 0);
rdev->irq.hpd[0] = false;
break;
case RADEON_HPD_2:
WREG32(DC_HPD2_CONTROL, 0);
rdev->irq.hpd[1] = false;
break;
case RADEON_HPD_3:
WREG32(DC_HPD3_CONTROL, 0);
rdev->irq.hpd[2] = false;
break;
case RADEON_HPD_4:
WREG32(DC_HPD4_CONTROL, 0);
rdev->irq.hpd[3] = false;
break;
/* DCE 3.2 */
case RADEON_HPD_5:
WREG32(DC_HPD5_CONTROL, 0);
rdev->irq.hpd[4] = false;
break;
case RADEON_HPD_6:
WREG32(DC_HPD6_CONTROL, 0);
rdev->irq.hpd[5] = false;
break;
default:
break;
}
}
} else {
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
switch (radeon_connector->hpd.hpd) {
case RADEON_HPD_1:
WREG32(DC_HOT_PLUG_DETECT1_CONTROL, 0);
rdev->irq.hpd[0] = false;
break;
case RADEON_HPD_2:
WREG32(DC_HOT_PLUG_DETECT2_CONTROL, 0);
rdev->irq.hpd[1] = false;
break;
case RADEON_HPD_3:
WREG32(DC_HOT_PLUG_DETECT3_CONTROL, 0);
rdev->irq.hpd[2] = false;
break;
default:
break;
}
}
}
}
/*
* R600 PCIE GART
*/
@ -2060,6 +2335,42 @@ static void r600_disable_interrupts(struct radeon_device *rdev)
rdev->ih.rptr = 0;
}
static void r600_disable_interrupt_state(struct radeon_device *rdev)
{
u32 tmp;
WREG32(CP_INT_CNTL, 0);
WREG32(GRBM_INT_CNTL, 0);
WREG32(DxMODE_INT_MASK, 0);
if (ASIC_IS_DCE3(rdev)) {
WREG32(DCE3_DACA_AUTODETECT_INT_CONTROL, 0);
WREG32(DCE3_DACB_AUTODETECT_INT_CONTROL, 0);
tmp = RREG32(DC_HPD1_INT_CONTROL) & DC_HPDx_INT_POLARITY;
WREG32(DC_HPD1_INT_CONTROL, tmp);
tmp = RREG32(DC_HPD2_INT_CONTROL) & DC_HPDx_INT_POLARITY;
WREG32(DC_HPD2_INT_CONTROL, tmp);
tmp = RREG32(DC_HPD3_INT_CONTROL) & DC_HPDx_INT_POLARITY;
WREG32(DC_HPD3_INT_CONTROL, tmp);
tmp = RREG32(DC_HPD4_INT_CONTROL) & DC_HPDx_INT_POLARITY;
WREG32(DC_HPD4_INT_CONTROL, tmp);
if (ASIC_IS_DCE32(rdev)) {
tmp = RREG32(DC_HPD5_INT_CONTROL) & DC_HPDx_INT_POLARITY;
WREG32(DC_HPD5_INT_CONTROL, 0);
tmp = RREG32(DC_HPD6_INT_CONTROL) & DC_HPDx_INT_POLARITY;
WREG32(DC_HPD6_INT_CONTROL, 0);
}
} else {
WREG32(DACA_AUTODETECT_INT_CONTROL, 0);
WREG32(DACB_AUTODETECT_INT_CONTROL, 0);
tmp = RREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL) & DC_HOT_PLUG_DETECTx_INT_POLARITY;
WREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL, 0);
tmp = RREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL) & DC_HOT_PLUG_DETECTx_INT_POLARITY;
WREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL, 0);
tmp = RREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL) & DC_HOT_PLUG_DETECTx_INT_POLARITY;
WREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL, 0);
}
}
int r600_irq_init(struct radeon_device *rdev)
{
int ret = 0;
@ -2122,9 +2433,7 @@ int r600_irq_init(struct radeon_device *rdev)
WREG32(IH_CNTL, ih_cntl);
/* force the active interrupt state to all disabled */
WREG32(CP_INT_CNTL, 0);
WREG32(GRBM_INT_CNTL, 0);
WREG32(DxMODE_INT_MASK, 0);
r600_disable_interrupt_state(rdev);
/* enable irqs */
r600_enable_interrupts(rdev);
@ -2141,13 +2450,29 @@ void r600_irq_fini(struct radeon_device *rdev)
int r600_irq_set(struct radeon_device *rdev)
{
uint32_t cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE;
uint32_t mode_int = 0;
u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE;
u32 mode_int = 0;
u32 hpd1, hpd2, hpd3, hpd4 = 0, hpd5 = 0, hpd6 = 0;
/* don't enable anything if the ih is disabled */
if (!rdev->ih.enabled)
return 0;
if (ASIC_IS_DCE3(rdev)) {
hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
if (ASIC_IS_DCE32(rdev)) {
hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
}
} else {
hpd1 = RREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd2 = RREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd3 = RREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL) & ~DC_HPDx_INT_EN;
}
if (rdev->irq.sw_int) {
DRM_DEBUG("r600_irq_set: sw int\n");
cp_int_cntl |= RB_INT_ENABLE;
@ -2160,39 +2485,137 @@ int r600_irq_set(struct radeon_device *rdev)
DRM_DEBUG("r600_irq_set: vblank 1\n");
mode_int |= D2MODE_VBLANK_INT_MASK;
}
if (rdev->irq.hpd[0]) {
DRM_DEBUG("r600_irq_set: hpd 1\n");
hpd1 |= DC_HPDx_INT_EN;
}
if (rdev->irq.hpd[1]) {
DRM_DEBUG("r600_irq_set: hpd 2\n");
hpd2 |= DC_HPDx_INT_EN;
}
if (rdev->irq.hpd[2]) {
DRM_DEBUG("r600_irq_set: hpd 3\n");
hpd3 |= DC_HPDx_INT_EN;
}
if (rdev->irq.hpd[3]) {
DRM_DEBUG("r600_irq_set: hpd 4\n");
hpd4 |= DC_HPDx_INT_EN;
}
if (rdev->irq.hpd[4]) {
DRM_DEBUG("r600_irq_set: hpd 5\n");
hpd5 |= DC_HPDx_INT_EN;
}
if (rdev->irq.hpd[5]) {
DRM_DEBUG("r600_irq_set: hpd 6\n");
hpd6 |= DC_HPDx_INT_EN;
}
WREG32(CP_INT_CNTL, cp_int_cntl);
WREG32(DxMODE_INT_MASK, mode_int);
if (ASIC_IS_DCE3(rdev)) {
WREG32(DC_HPD1_INT_CONTROL, hpd1);
WREG32(DC_HPD2_INT_CONTROL, hpd2);
WREG32(DC_HPD3_INT_CONTROL, hpd3);
WREG32(DC_HPD4_INT_CONTROL, hpd4);
if (ASIC_IS_DCE32(rdev)) {
WREG32(DC_HPD5_INT_CONTROL, hpd5);
WREG32(DC_HPD6_INT_CONTROL, hpd6);
}
} else {
WREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL, hpd1);
WREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL, hpd2);
WREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL, hpd3);
}
return 0;
}
static inline void r600_irq_ack(struct radeon_device *rdev, u32 disp_int)
static inline void r600_irq_ack(struct radeon_device *rdev,
u32 *disp_int,
u32 *disp_int_cont,
u32 *disp_int_cont2)
{
u32 tmp;
if (disp_int & LB_D1_VBLANK_INTERRUPT)
if (ASIC_IS_DCE3(rdev)) {
*disp_int = RREG32(DCE3_DISP_INTERRUPT_STATUS);
*disp_int_cont = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE);
*disp_int_cont2 = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE2);
} else {
*disp_int = RREG32(DISP_INTERRUPT_STATUS);
*disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE);
*disp_int_cont2 = 0;
}
if (*disp_int & LB_D1_VBLANK_INTERRUPT)
WREG32(D1MODE_VBLANK_STATUS, DxMODE_VBLANK_ACK);
if (disp_int & LB_D1_VLINE_INTERRUPT)
if (*disp_int & LB_D1_VLINE_INTERRUPT)
WREG32(D1MODE_VLINE_STATUS, DxMODE_VLINE_ACK);
if (disp_int & LB_D2_VBLANK_INTERRUPT)
if (*disp_int & LB_D2_VBLANK_INTERRUPT)
WREG32(D2MODE_VBLANK_STATUS, DxMODE_VBLANK_ACK);
if (disp_int & LB_D2_VLINE_INTERRUPT)
if (*disp_int & LB_D2_VLINE_INTERRUPT)
WREG32(D2MODE_VLINE_STATUS, DxMODE_VLINE_ACK);
if (*disp_int & DC_HPD1_INTERRUPT) {
if (ASIC_IS_DCE3(rdev)) {
tmp = RREG32(DC_HPD1_INT_CONTROL);
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HPD1_INT_CONTROL, tmp);
} else {
tmp = RREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL);
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL, tmp);
}
}
if (*disp_int & DC_HPD2_INTERRUPT) {
if (ASIC_IS_DCE3(rdev)) {
tmp = RREG32(DC_HPD2_INT_CONTROL);
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HPD2_INT_CONTROL, tmp);
} else {
tmp = RREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL);
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL, tmp);
}
}
if (*disp_int_cont & DC_HPD3_INTERRUPT) {
if (ASIC_IS_DCE3(rdev)) {
tmp = RREG32(DC_HPD3_INT_CONTROL);
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HPD3_INT_CONTROL, tmp);
} else {
tmp = RREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL);
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL, tmp);
}
}
if (*disp_int_cont & DC_HPD4_INTERRUPT) {
tmp = RREG32(DC_HPD4_INT_CONTROL);
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HPD4_INT_CONTROL, tmp);
}
if (ASIC_IS_DCE32(rdev)) {
if (*disp_int_cont2 & DC_HPD5_INTERRUPT) {
tmp = RREG32(DC_HPD5_INT_CONTROL);
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HPD5_INT_CONTROL, tmp);
}
if (*disp_int_cont2 & DC_HPD6_INTERRUPT) {
tmp = RREG32(DC_HPD5_INT_CONTROL);
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HPD6_INT_CONTROL, tmp);
}
}
}
void r600_irq_disable(struct radeon_device *rdev)
{
u32 disp_int;
u32 disp_int, disp_int_cont, disp_int_cont2;
r600_disable_interrupts(rdev);
/* Wait and acknowledge irq */
mdelay(1);
if (ASIC_IS_DCE3(rdev))
disp_int = RREG32(DCE3_DISP_INTERRUPT_STATUS);
else
disp_int = RREG32(DISP_INTERRUPT_STATUS);
r600_irq_ack(rdev, disp_int);
r600_irq_ack(rdev, &disp_int, &disp_int_cont, &disp_int_cont2);
r600_disable_interrupt_state(rdev);
}
static inline u32 r600_get_ih_wptr(struct radeon_device *rdev)
@ -2249,8 +2672,9 @@ int r600_irq_process(struct radeon_device *rdev)
u32 rptr = rdev->ih.rptr;
u32 src_id, src_data;
u32 last_entry = rdev->ih.ring_size - 16;
u32 ring_index, disp_int;
u32 ring_index, disp_int, disp_int_cont, disp_int_cont2;
unsigned long flags;
bool queue_hotplug = false;
DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr);
@ -2267,11 +2691,7 @@ int r600_irq_process(struct radeon_device *rdev)
restart_ih:
/* display interrupts */
if (ASIC_IS_DCE3(rdev))
disp_int = RREG32(DCE3_DISP_INTERRUPT_STATUS);
else
disp_int = RREG32(DISP_INTERRUPT_STATUS);
r600_irq_ack(rdev, disp_int);
r600_irq_ack(rdev, &disp_int, &disp_int_cont, &disp_int_cont2);
rdev->ih.wptr = wptr;
while (rptr != wptr) {
@ -2321,6 +2741,55 @@ restart_ih:
break;
}
break;
case 19: /* HPD/DAC hotplug */
switch (src_data) {
case 0:
if (disp_int & DC_HPD1_INTERRUPT) {
disp_int &= ~DC_HPD1_INTERRUPT;
queue_hotplug = true;
DRM_DEBUG("IH: HPD1\n");
}
break;
case 1:
if (disp_int & DC_HPD2_INTERRUPT) {
disp_int &= ~DC_HPD2_INTERRUPT;
queue_hotplug = true;
DRM_DEBUG("IH: HPD2\n");
}
break;
case 4:
if (disp_int_cont & DC_HPD3_INTERRUPT) {
disp_int_cont &= ~DC_HPD3_INTERRUPT;
queue_hotplug = true;
DRM_DEBUG("IH: HPD3\n");
}
break;
case 5:
if (disp_int_cont & DC_HPD4_INTERRUPT) {
disp_int_cont &= ~DC_HPD4_INTERRUPT;
queue_hotplug = true;
DRM_DEBUG("IH: HPD4\n");
}
break;
case 10:
if (disp_int_cont2 & DC_HPD5_INTERRUPT) {
disp_int_cont &= ~DC_HPD5_INTERRUPT;
queue_hotplug = true;
DRM_DEBUG("IH: HPD5\n");
}
break;
case 12:
if (disp_int_cont2 & DC_HPD6_INTERRUPT) {
disp_int_cont &= ~DC_HPD6_INTERRUPT;
queue_hotplug = true;
DRM_DEBUG("IH: HPD6\n");
}
break;
default:
DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data);
break;
}
break;
case 176: /* CP_INT in ring buffer */
case 177: /* CP_INT in IB1 */
case 178: /* CP_INT in IB2 */
@ -2345,6 +2814,8 @@ restart_ih:
wptr = r600_get_ih_wptr(rdev);
if (wptr != rdev->ih.wptr)
goto restart_ih;
if (queue_hotplug)
queue_work(rdev->wq, &rdev->hotplug_work);
rdev->ih.rptr = rptr;
WREG32(IH_RB_RPTR, rdev->ih.rptr);
spin_unlock_irqrestore(&rdev->ih.lock, flags);

View File

@ -558,6 +558,7 @@
# define DC_HOT_PLUG_DETECT2_INTERRUPT (1 << 19)
# define DC_I2C_SW_DONE_INTERRUPT (1 << 20)
# define DC_I2C_HW_DONE_INTERRUPT (1 << 21)
#define DISP_INTERRUPT_STATUS_CONTINUE 0x7ee8
#define DCE3_DISP_INTERRUPT_STATUS_CONTINUE 0x7de8
# define DC_HPD4_INTERRUPT (1 << 14)
# define DC_HPD4_RX_INTERRUPT (1 << 15)
@ -590,6 +591,18 @@
# define DC_HPD6_INTERRUPT (1 << 21)
# define DC_HPD6_RX_INTERRUPT (1 << 22)
#define DACA_AUTO_DETECT_CONTROL 0x7828
#define DACB_AUTO_DETECT_CONTROL 0x7a28
#define DCE3_DACA_AUTO_DETECT_CONTROL 0x7028
#define DCE3_DACB_AUTO_DETECT_CONTROL 0x7128
# define DACx_AUTODETECT_MODE(x) ((x) << 0)
# define DACx_AUTODETECT_MODE_NONE 0
# define DACx_AUTODETECT_MODE_CONNECT 1
# define DACx_AUTODETECT_MODE_DISCONNECT 2
# define DACx_AUTODETECT_FRAME_TIME_COUNTER(x) ((x) << 8)
/* bit 18 = R/C, 17 = G/Y, 16 = B/Comp */
# define DACx_AUTODETECT_CHECK_MASK(x) ((x) << 16)
#define DCE3_DACA_AUTODETECT_INT_CONTROL 0x7038
#define DCE3_DACB_AUTODETECT_INT_CONTROL 0x7138
#define DACA_AUTODETECT_INT_CONTROL 0x7838
@ -597,23 +610,62 @@
# define DACx_AUTODETECT_ACK (1 << 0)
# define DACx_AUTODETECT_INT_ENABLE (1 << 16)
#define DC_HOT_PLUG_DETECT1_CONTROL 0x7d00
#define DC_HOT_PLUG_DETECT2_CONTROL 0x7d10
#define DC_HOT_PLUG_DETECT3_CONTROL 0x7d24
# define DC_HOT_PLUG_DETECTx_EN (1 << 0)
#define DC_HOT_PLUG_DETECT1_INT_STATUS 0x7d04
#define DC_HOT_PLUG_DETECT2_INT_STATUS 0x7d14
#define DC_HOT_PLUG_DETECT3_INT_STATUS 0x7d28
# define DC_HOT_PLUG_DETECTx_INT_STATUS (1 << 0)
# define DC_HOT_PLUG_DETECTx_SENSE (1 << 1)
/* DCE 3.0 */
#define DC_HPD1_INT_STATUS 0x7d00
#define DC_HPD2_INT_STATUS 0x7d0c
#define DC_HPD3_INT_STATUS 0x7d18
#define DC_HPD4_INT_STATUS 0x7d24
/* DCE 3.2 */
#define DC_HPD5_INT_STATUS 0x7dc0
#define DC_HPD6_INT_STATUS 0x7df4
# define DC_HPDx_INT_STATUS (1 << 0)
# define DC_HPDx_SENSE (1 << 1)
# define DC_HPDx_RX_INT_STATUS (1 << 8)
#define DC_HOT_PLUG_DETECT1_INT_CONTROL 0x7d08
#define DC_HOT_PLUG_DETECT2_INT_CONTROL 0x7d18
#define DC_HOT_PLUG_DETECT3_INT_CONTROL 0x7d2c
# define DC_HOT_PLUG_DETECTx_INT_ACK (1 << 0)
# define DC_HOT_PLUG_DETECTx_INT_POLARITY (1 << 8)
# define DC_HOT_PLUG_DETECTx_INT_EN (1 << 16)
/* DCE 3.2 */
/* DCE 3.0 */
#define DC_HPD1_INT_CONTROL 0x7d04
#define DC_HPD2_INT_CONTROL 0x7d10
#define DC_HPD3_INT_CONTROL 0x7d1c
#define DC_HPD4_INT_CONTROL 0x7d28
/* DCE 3.2 */
#define DC_HPD5_INT_CONTROL 0x7dc4
#define DC_HPD6_INT_CONTROL 0x7df8
# define DC_HPDx_INT_ACK (1 << 0)
# define DC_HPDx_INT_POLARITY (1 << 8)
# define DC_HPDx_INT_EN (1 << 16)
# define DC_HPDx_RX_INT_ACK (1 << 20)
# define DC_HPDx_RX_INT_EN (1 << 24)
/* DCE 3.0 */
#define DC_HPD1_CONTROL 0x7d08
#define DC_HPD2_CONTROL 0x7d14
#define DC_HPD3_CONTROL 0x7d20
#define DC_HPD4_CONTROL 0x7d2c
/* DCE 3.2 */
#define DC_HPD5_CONTROL 0x7dc8
#define DC_HPD6_CONTROL 0x7dfc
# define DC_HPDx_CONNECTION_TIMER(x) ((x) << 0)
# define DC_HPDx_RX_INT_TIMER(x) ((x) << 16)
/* DCE 3.2 */
# define DC_HPDx_EN (1 << 28)
/*
* PM4
*/

View File

@ -339,6 +339,8 @@ struct radeon_irq {
bool sw_int;
/* FIXME: use a define max crtc rather than hardcode it */
bool crtc_vblank_int[2];
/* FIXME: use defines for max hpd/dacs */
bool hpd[6];
spinlock_t sw_lock;
int sw_refcount;
};
@ -647,6 +649,10 @@ struct radeon_asic {
int (*clear_surface_reg)(struct radeon_device *rdev, int reg);
void (*bandwidth_update)(struct radeon_device *rdev);
void (*hdp_flush)(struct radeon_device *rdev);
void (*hpd_init)(struct radeon_device *rdev);
void (*hpd_fini)(struct radeon_device *rdev);
bool (*hpd_sense)(struct radeon_device *rdev, enum radeon_hpd_id hpd);
void (*hpd_set_polarity)(struct radeon_device *rdev, enum radeon_hpd_id hpd);
};
/*
@ -803,6 +809,8 @@ struct radeon_device {
struct r600_blit r600_blit;
int msi_enabled; /* msi enabled */
struct r600_ih ih; /* r6/700 interrupt ring */
struct workqueue_struct *wq;
struct work_struct hotplug_work;
};
int radeon_device_init(struct radeon_device *rdev,
@ -986,6 +994,10 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v)
#define radeon_clear_surface_reg(rdev, r) ((rdev)->asic->clear_surface_reg((rdev), (r)))
#define radeon_bandwidth_update(rdev) (rdev)->asic->bandwidth_update((rdev))
#define radeon_hdp_flush(rdev) (rdev)->asic->hdp_flush((rdev))
#define radeon_hpd_init(rdev) (rdev)->asic->hpd_init((rdev))
#define radeon_hpd_fini(rdev) (rdev)->asic->hpd_fini((rdev))
#define radeon_hpd_sense(rdev, hpd) (rdev)->asic->hpd_sense((rdev), (hpd))
#define radeon_hpd_set_polarity(rdev, hpd) (rdev)->asic->hpd_set_polarity((rdev), (hpd))
/* Common functions */
extern int radeon_gart_table_vram_pin(struct radeon_device *rdev);

View File

@ -77,6 +77,11 @@ void r100_bandwidth_update(struct radeon_device *rdev);
void r100_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
int r100_ring_test(struct radeon_device *rdev);
void r100_hdp_flush(struct radeon_device *rdev);
void r100_hpd_init(struct radeon_device *rdev);
void r100_hpd_fini(struct radeon_device *rdev);
bool r100_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd);
void r100_hpd_set_polarity(struct radeon_device *rdev,
enum radeon_hpd_id hpd);
static struct radeon_asic r100_asic = {
.init = &r100_init,
@ -109,6 +114,10 @@ static struct radeon_asic r100_asic = {
.clear_surface_reg = r100_clear_surface_reg,
.bandwidth_update = &r100_bandwidth_update,
.hdp_flush = &r100_hdp_flush,
.hpd_init = &r100_hpd_init,
.hpd_fini = &r100_hpd_fini,
.hpd_sense = &r100_hpd_sense,
.hpd_set_polarity = &r100_hpd_set_polarity,
};
@ -165,6 +174,10 @@ static struct radeon_asic r300_asic = {
.clear_surface_reg = r100_clear_surface_reg,
.bandwidth_update = &r100_bandwidth_update,
.hdp_flush = &r100_hdp_flush,
.hpd_init = &r100_hpd_init,
.hpd_fini = &r100_hpd_fini,
.hpd_sense = &r100_hpd_sense,
.hpd_set_polarity = &r100_hpd_set_polarity,
};
/*
@ -205,6 +218,10 @@ static struct radeon_asic r420_asic = {
.clear_surface_reg = r100_clear_surface_reg,
.bandwidth_update = &r100_bandwidth_update,
.hdp_flush = &r100_hdp_flush,
.hpd_init = &r100_hpd_init,
.hpd_fini = &r100_hpd_fini,
.hpd_sense = &r100_hpd_sense,
.hpd_set_polarity = &r100_hpd_set_polarity,
};
@ -250,6 +267,10 @@ static struct radeon_asic rs400_asic = {
.clear_surface_reg = r100_clear_surface_reg,
.bandwidth_update = &r100_bandwidth_update,
.hdp_flush = &r100_hdp_flush,
.hpd_init = &r100_hpd_init,
.hpd_fini = &r100_hpd_fini,
.hpd_sense = &r100_hpd_sense,
.hpd_set_polarity = &r100_hpd_set_polarity,
};
@ -268,6 +289,12 @@ int rs600_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr);
uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg);
void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
void rs600_bandwidth_update(struct radeon_device *rdev);
void rs600_hpd_init(struct radeon_device *rdev);
void rs600_hpd_fini(struct radeon_device *rdev);
bool rs600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd);
void rs600_hpd_set_polarity(struct radeon_device *rdev,
enum radeon_hpd_id hpd);
static struct radeon_asic rs600_asic = {
.init = &rs600_init,
.fini = &rs600_fini,
@ -297,6 +324,10 @@ static struct radeon_asic rs600_asic = {
.set_clock_gating = &radeon_atom_set_clock_gating,
.bandwidth_update = &rs600_bandwidth_update,
.hdp_flush = &r100_hdp_flush,
.hpd_init = &rs600_hpd_init,
.hpd_fini = &rs600_hpd_fini,
.hpd_sense = &rs600_hpd_sense,
.hpd_set_polarity = &rs600_hpd_set_polarity,
};
@ -341,6 +372,10 @@ static struct radeon_asic rs690_asic = {
.clear_surface_reg = r100_clear_surface_reg,
.bandwidth_update = &rs690_bandwidth_update,
.hdp_flush = &r100_hdp_flush,
.hpd_init = &rs600_hpd_init,
.hpd_fini = &rs600_hpd_fini,
.hpd_sense = &rs600_hpd_sense,
.hpd_set_polarity = &rs600_hpd_set_polarity,
};
@ -389,6 +424,10 @@ static struct radeon_asic rv515_asic = {
.clear_surface_reg = r100_clear_surface_reg,
.bandwidth_update = &rv515_bandwidth_update,
.hdp_flush = &r100_hdp_flush,
.hpd_init = &rs600_hpd_init,
.hpd_fini = &rs600_hpd_fini,
.hpd_sense = &rs600_hpd_sense,
.hpd_set_polarity = &rs600_hpd_set_polarity,
};
@ -428,6 +467,10 @@ static struct radeon_asic r520_asic = {
.clear_surface_reg = r100_clear_surface_reg,
.bandwidth_update = &rv515_bandwidth_update,
.hdp_flush = &r100_hdp_flush,
.hpd_init = &rs600_hpd_init,
.hpd_fini = &rs600_hpd_fini,
.hpd_sense = &rs600_hpd_sense,
.hpd_set_polarity = &rs600_hpd_set_polarity,
};
/*
@ -465,6 +508,11 @@ int r600_copy_blit(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_pages, struct radeon_fence *fence);
void r600_hdp_flush(struct radeon_device *rdev);
void r600_hpd_init(struct radeon_device *rdev);
void r600_hpd_fini(struct radeon_device *rdev);
bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd);
void r600_hpd_set_polarity(struct radeon_device *rdev,
enum radeon_hpd_id hpd);
static struct radeon_asic r600_asic = {
.init = &r600_init,
@ -496,6 +544,10 @@ static struct radeon_asic r600_asic = {
.clear_surface_reg = r600_clear_surface_reg,
.bandwidth_update = &rv515_bandwidth_update,
.hdp_flush = &r600_hdp_flush,
.hpd_init = &r600_hpd_init,
.hpd_fini = &r600_hpd_fini,
.hpd_sense = &r600_hpd_sense,
.hpd_set_polarity = &r600_hpd_set_polarity,
};
/*
@ -537,6 +589,10 @@ static struct radeon_asic rv770_asic = {
.clear_surface_reg = r600_clear_surface_reg,
.bandwidth_update = &rv515_bandwidth_update,
.hdp_flush = &r600_hdp_flush,
.hpd_init = &r600_hpd_init,
.hpd_fini = &r600_hpd_fini,
.hpd_sense = &r600_hpd_sense,
.hpd_set_polarity = &r600_hpd_set_polarity,
};
#endif

View File

@ -47,7 +47,8 @@ radeon_add_atom_connector(struct drm_device *dev,
int connector_type,
struct radeon_i2c_bus_rec *i2c_bus,
bool linkb, uint32_t igp_lane_info,
uint16_t connector_object_id);
uint16_t connector_object_id,
struct radeon_hpd *hpd);
/* from radeon_legacy_encoder.c */
extern void
@ -60,12 +61,11 @@ union atom_supported_devices {
struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 info_2d1;
};
static inline struct radeon_i2c_bus_rec radeon_lookup_gpio(struct drm_device
*dev, uint8_t id)
static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_device *rdev,
uint8_t id)
{
struct radeon_device *rdev = dev->dev_private;
struct atom_context *ctx = rdev->mode_info.atom_context;
ATOM_GPIO_I2C_ASSIGMENT gpio;
ATOM_GPIO_I2C_ASSIGMENT *gpio;
struct radeon_i2c_bus_rec i2c;
int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);
struct _ATOM_GPIO_I2C_INFO *i2c_info;
@ -78,34 +78,116 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_gpio(struct drm_device
i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset);
gpio = i2c_info->asGPIO_Info[id];
gpio = &i2c_info->asGPIO_Info[id];
i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4;
i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4;
i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4;
i2c.en_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex) * 4;
i2c.y_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex) * 4;
i2c.y_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex) * 4;
i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex) * 4;
i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex) * 4;
i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift);
i2c.mask_data_mask = (1 << gpio->ucDataMaskShift);
i2c.en_clk_mask = (1 << gpio->ucClkEnShift);
i2c.en_data_mask = (1 << gpio->ucDataEnShift);
i2c.y_clk_mask = (1 << gpio->ucClkY_Shift);
i2c.y_data_mask = (1 << gpio->ucDataY_Shift);
i2c.a_clk_mask = (1 << gpio->ucClkA_Shift);
i2c.a_data_mask = (1 << gpio->ucDataA_Shift);
if (gpio->sucI2cId.sbfAccess.bfHW_Capable)
i2c.hw_capable = true;
else
i2c.hw_capable = false;
if (gpio->sucI2cId.ucAccess == 0xa0)
i2c.mm_i2c = true;
else
i2c.mm_i2c = false;
i2c.i2c_id = gpio->sucI2cId.ucAccess;
i2c.mask_clk_reg = le16_to_cpu(gpio.usClkMaskRegisterIndex) * 4;
i2c.mask_data_reg = le16_to_cpu(gpio.usDataMaskRegisterIndex) * 4;
i2c.en_clk_reg = le16_to_cpu(gpio.usClkEnRegisterIndex) * 4;
i2c.en_data_reg = le16_to_cpu(gpio.usDataEnRegisterIndex) * 4;
i2c.y_clk_reg = le16_to_cpu(gpio.usClkY_RegisterIndex) * 4;
i2c.y_data_reg = le16_to_cpu(gpio.usDataY_RegisterIndex) * 4;
i2c.a_clk_reg = le16_to_cpu(gpio.usClkA_RegisterIndex) * 4;
i2c.a_data_reg = le16_to_cpu(gpio.usDataA_RegisterIndex) * 4;
i2c.mask_clk_mask = (1 << gpio.ucClkMaskShift);
i2c.mask_data_mask = (1 << gpio.ucDataMaskShift);
i2c.en_clk_mask = (1 << gpio.ucClkEnShift);
i2c.en_data_mask = (1 << gpio.ucDataEnShift);
i2c.y_clk_mask = (1 << gpio.ucClkY_Shift);
i2c.y_data_mask = (1 << gpio.ucDataY_Shift);
i2c.a_clk_mask = (1 << gpio.ucClkA_Shift);
i2c.a_data_mask = (1 << gpio.ucDataA_Shift);
i2c.valid = true;
return i2c;
}
static inline struct radeon_gpio_rec radeon_lookup_gpio(struct radeon_device *rdev,
u8 id)
{
struct atom_context *ctx = rdev->mode_info.atom_context;
struct radeon_gpio_rec gpio;
int index = GetIndexIntoMasterTable(DATA, GPIO_Pin_LUT);
struct _ATOM_GPIO_PIN_LUT *gpio_info;
ATOM_GPIO_PIN_ASSIGNMENT *pin;
u16 data_offset, size;
int i, num_indices;
memset(&gpio, 0, sizeof(struct radeon_gpio_rec));
gpio.valid = false;
atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset);
gpio_info = (struct _ATOM_GPIO_PIN_LUT *)(ctx->bios + data_offset);
num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / sizeof(ATOM_GPIO_PIN_ASSIGNMENT);
for (i = 0; i < num_indices; i++) {
pin = &gpio_info->asGPIO_Pin[i];
if (id == pin->ucGPIO_ID) {
gpio.id = pin->ucGPIO_ID;
gpio.reg = pin->usGpioPin_AIndex * 4;
gpio.mask = (1 << pin->ucGpioPinBitShift);
gpio.valid = true;
break;
}
}
return gpio;
}
static struct radeon_hpd radeon_atom_get_hpd_info_from_gpio(struct radeon_device *rdev,
struct radeon_gpio_rec *gpio)
{
struct radeon_hpd hpd;
hpd.gpio = *gpio;
if (gpio->reg == AVIVO_DC_GPIO_HPD_A) {
switch(gpio->mask) {
case (1 << 0):
hpd.hpd = RADEON_HPD_1;
break;
case (1 << 8):
hpd.hpd = RADEON_HPD_2;
break;
case (1 << 16):
hpd.hpd = RADEON_HPD_3;
break;
case (1 << 24):
hpd.hpd = RADEON_HPD_4;
break;
case (1 << 26):
hpd.hpd = RADEON_HPD_5;
break;
case (1 << 28):
hpd.hpd = RADEON_HPD_6;
break;
default:
hpd.hpd = RADEON_HPD_NONE;
break;
}
} else
hpd.hpd = RADEON_HPD_NONE;
return hpd;
}
static bool radeon_atom_apply_quirks(struct drm_device *dev,
uint32_t supported_device,
int *connector_type,
struct radeon_i2c_bus_rec *i2c_bus,
uint16_t *line_mux)
uint16_t *line_mux,
struct radeon_hpd *hpd)
{
/* Asus M2A-VM HDMI board lists the DVI port as HDMI */
@ -266,16 +348,18 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
struct radeon_mode_info *mode_info = &rdev->mode_info;
struct atom_context *ctx = mode_info->atom_context;
int index = GetIndexIntoMasterTable(DATA, Object_Header);
uint16_t size, data_offset;
uint8_t frev, crev, line_mux = 0;
u16 size, data_offset;
u8 frev, crev;
ATOM_CONNECTOR_OBJECT_TABLE *con_obj;
ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj;
ATOM_OBJECT_HEADER *obj_header;
int i, j, path_size, device_support;
int connector_type;
uint16_t igp_lane_info, conn_id, connector_object_id;
u16 igp_lane_info, conn_id, connector_object_id;
bool linkb;
struct radeon_i2c_bus_rec ddc_bus;
struct radeon_gpio_rec gpio;
struct radeon_hpd hpd;
atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset);
@ -302,7 +386,6 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
path = (ATOM_DISPLAY_OBJECT_PATH *) addr;
path_size += le16_to_cpu(path->usSize);
linkb = false;
if (device_support & le16_to_cpu(path->usDeviceTag)) {
uint8_t con_obj_id, con_obj_num, con_obj_type;
@ -403,10 +486,9 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
}
}
/* look up gpio for ddc */
/* look up gpio for ddc, hpd */
if ((le16_to_cpu(path->usDeviceTag) &
(ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))
== 0) {
(ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) == 0) {
for (j = 0; j < con_obj->ucNumberOfObjects; j++) {
if (le16_to_cpu(path->usConnObjectId) ==
le16_to_cpu(con_obj->asObjects[j].
@ -420,21 +502,31 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
asObjects[j].
usRecordOffset));
ATOM_I2C_RECORD *i2c_record;
ATOM_HPD_INT_RECORD *hpd_record;
hpd.hpd = RADEON_HPD_NONE;
while (record->ucRecordType > 0
&& record->
ucRecordType <=
ATOM_MAX_OBJECT_RECORD_NUMBER) {
switch (record->
ucRecordType) {
switch (record->ucRecordType) {
case ATOM_I2C_RECORD_TYPE:
i2c_record =
(ATOM_I2C_RECORD
*) record;
line_mux =
i2c_record->
sucI2cId.
bfI2C_LineMux;
(ATOM_I2C_RECORD *)
record;
ddc_bus = radeon_lookup_i2c_gpio(rdev,
i2c_record->
sucI2cId.
bfI2C_LineMux);
break;
case ATOM_HPD_INT_RECORD_TYPE:
hpd_record =
(ATOM_HPD_INT_RECORD *)
record;
gpio = radeon_lookup_gpio(rdev,
hpd_record->ucHPDIntGPIOID);
hpd = radeon_atom_get_hpd_info_from_gpio(rdev, &gpio);
hpd.plugged_state = hpd_record->ucPlugged_PinState;
break;
}
record =
@ -447,24 +539,16 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
break;
}
}
} else
line_mux = 0;
if ((le16_to_cpu(path->usDeviceTag) ==
ATOM_DEVICE_TV1_SUPPORT)
|| (le16_to_cpu(path->usDeviceTag) ==
ATOM_DEVICE_TV2_SUPPORT)
|| (le16_to_cpu(path->usDeviceTag) ==
ATOM_DEVICE_CV_SUPPORT))
} else {
hpd.hpd = RADEON_HPD_NONE;
ddc_bus.valid = false;
else
ddc_bus = radeon_lookup_gpio(dev, line_mux);
}
conn_id = le16_to_cpu(path->usConnObjectId);
if (!radeon_atom_apply_quirks
(dev, le16_to_cpu(path->usDeviceTag), &connector_type,
&ddc_bus, &conn_id))
&ddc_bus, &conn_id, &hpd))
continue;
radeon_add_atom_connector(dev,
@ -473,7 +557,8 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
usDeviceTag),
connector_type, &ddc_bus,
linkb, igp_lane_info,
connector_object_id);
connector_object_id,
&hpd);
}
}
@ -528,6 +613,7 @@ struct bios_connector {
uint16_t devices;
int connector_type;
struct radeon_i2c_bus_rec ddc_bus;
struct radeon_hpd hpd;
};
bool radeon_get_atom_connector_info_from_supported_devices_table(struct
@ -543,7 +629,7 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
uint16_t device_support;
uint8_t dac;
union atom_supported_devices *supported_devices;
int i, j;
int i, j, max_device;
struct bios_connector bios_connectors[ATOM_MAX_SUPPORTED_DEVICE];
atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset);
@ -553,7 +639,12 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
device_support = le16_to_cpu(supported_devices->info.usDeviceSupport);
for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
if (frev > 1)
max_device = ATOM_MAX_SUPPORTED_DEVICE;
else
max_device = ATOM_MAX_SUPPORTED_DEVICE_INFO;
for (i = 0; i < max_device; i++) {
ATOM_CONNECTOR_INFO_I2C ci =
supported_devices->info.asConnInfo[i];
@ -608,8 +699,30 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
bios_connectors[i].line_mux = 52;
} else
bios_connectors[i].ddc_bus =
radeon_lookup_gpio(dev,
bios_connectors[i].line_mux);
radeon_lookup_i2c_gpio(rdev,
bios_connectors[i].line_mux);
if ((crev > 1) && (frev > 1)) {
u8 isb = supported_devices->info_2d1.asIntSrcInfo[i].ucIntSrcBitmap;
switch (isb) {
case 0x4:
bios_connectors[i].hpd.hpd = RADEON_HPD_1;
break;
case 0xa:
bios_connectors[i].hpd.hpd = RADEON_HPD_2;
break;
default:
bios_connectors[i].hpd.hpd = RADEON_HPD_NONE;
break;
}
} else {
if (i == ATOM_DEVICE_DFP1_INDEX)
bios_connectors[i].hpd.hpd = RADEON_HPD_1;
else if (i == ATOM_DEVICE_DFP2_INDEX)
bios_connectors[i].hpd.hpd = RADEON_HPD_2;
else
bios_connectors[i].hpd.hpd = RADEON_HPD_NONE;
}
/* Always set the connector type to VGA for CRT1/CRT2. if they are
* shared with a DVI port, we'll pick up the DVI connector when we
@ -621,7 +734,8 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
if (!radeon_atom_apply_quirks
(dev, (1 << i), &bios_connectors[i].connector_type,
&bios_connectors[i].ddc_bus, &bios_connectors[i].line_mux))
&bios_connectors[i].ddc_bus, &bios_connectors[i].line_mux,
&bios_connectors[i].hpd))
continue;
bios_connectors[i].valid = true;
@ -643,9 +757,9 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
}
/* combine shared connectors */
for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
for (i = 0; i < max_device; i++) {
if (bios_connectors[i].valid) {
for (j = 0; j < ATOM_MAX_SUPPORTED_DEVICE; j++) {
for (j = 0; j < max_device; j++) {
if (bios_connectors[j].valid && (i != j)) {
if (bios_connectors[i].line_mux ==
bios_connectors[j].line_mux) {
@ -669,6 +783,10 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
bios_connectors[i].
connector_type =
DRM_MODE_CONNECTOR_DVII;
if (bios_connectors[j].devices &
(ATOM_DEVICE_DFP_SUPPORT))
bios_connectors[i].hpd =
bios_connectors[j].hpd;
bios_connectors[j].
valid = false;
}
@ -679,7 +797,7 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
}
/* add the connectors */
for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
for (i = 0; i < max_device; i++) {
if (bios_connectors[i].valid) {
uint16_t connector_object_id =
atombios_get_connector_object_id(dev,
@ -692,7 +810,8 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
connector_type,
&bios_connectors[i].ddc_bus,
false, 0,
connector_object_id);
connector_object_id,
&bios_connectors[i].hpd);
}
}

View File

@ -50,7 +50,8 @@ radeon_add_legacy_connector(struct drm_device *dev,
uint32_t supported_device,
int connector_type,
struct radeon_i2c_bus_rec *i2c_bus,
uint16_t connector_object_id);
uint16_t connector_object_id,
struct radeon_hpd *hpd);
/* from radeon_legacy_encoder.c */
extern void
@ -442,29 +443,39 @@ static uint16_t combios_get_table_offset(struct drm_device *dev,
}
struct radeon_i2c_bus_rec combios_setup_i2c_bus(int ddc_line)
static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rdev,
int ddc_line)
{
struct radeon_i2c_bus_rec i2c;
i2c.mask_clk_mask = RADEON_GPIO_EN_1;
i2c.mask_data_mask = RADEON_GPIO_EN_0;
i2c.a_clk_mask = RADEON_GPIO_A_1;
i2c.a_data_mask = RADEON_GPIO_A_0;
i2c.en_clk_mask = RADEON_GPIO_EN_1;
i2c.en_data_mask = RADEON_GPIO_EN_0;
i2c.y_clk_mask = RADEON_GPIO_Y_1;
i2c.y_data_mask = RADEON_GPIO_Y_0;
if ((ddc_line == RADEON_LCD_GPIO_MASK) ||
(ddc_line == RADEON_MDGPIO_EN_REG)) {
i2c.mask_clk_reg = ddc_line;
i2c.mask_data_reg = ddc_line;
i2c.a_clk_reg = ddc_line;
i2c.a_data_reg = ddc_line;
i2c.en_clk_reg = ddc_line;
i2c.en_data_reg = ddc_line;
i2c.y_clk_reg = ddc_line + 4;
i2c.y_data_reg = ddc_line + 4;
if (ddc_line == RADEON_GPIOPAD_MASK) {
i2c.mask_clk_reg = RADEON_GPIOPAD_MASK;
i2c.mask_data_reg = RADEON_GPIOPAD_MASK;
i2c.a_clk_reg = RADEON_GPIOPAD_A;
i2c.a_data_reg = RADEON_GPIOPAD_A;
i2c.en_clk_reg = RADEON_GPIOPAD_EN;
i2c.en_data_reg = RADEON_GPIOPAD_EN;
i2c.y_clk_reg = RADEON_GPIOPAD_Y;
i2c.y_data_reg = RADEON_GPIOPAD_Y;
} else if (ddc_line == RADEON_MDGPIO_MASK) {
i2c.mask_clk_reg = RADEON_MDGPIO_MASK;
i2c.mask_data_reg = RADEON_MDGPIO_MASK;
i2c.a_clk_reg = RADEON_MDGPIO_A;
i2c.a_data_reg = RADEON_MDGPIO_A;
i2c.en_clk_reg = RADEON_MDGPIO_EN;
i2c.en_data_reg = RADEON_MDGPIO_EN;
i2c.y_clk_reg = RADEON_MDGPIO_Y;
i2c.y_data_reg = RADEON_MDGPIO_Y;
} else {
i2c.mask_clk_mask = RADEON_GPIO_EN_1;
i2c.mask_data_mask = RADEON_GPIO_EN_0;
i2c.a_clk_mask = RADEON_GPIO_A_1;
i2c.a_data_mask = RADEON_GPIO_A_0;
i2c.en_clk_mask = RADEON_GPIO_EN_1;
i2c.en_data_mask = RADEON_GPIO_EN_0;
i2c.y_clk_mask = RADEON_GPIO_Y_1;
i2c.y_data_mask = RADEON_GPIO_Y_0;
i2c.mask_clk_reg = ddc_line;
i2c.mask_data_reg = ddc_line;
i2c.a_clk_reg = ddc_line;
@ -475,6 +486,28 @@ struct radeon_i2c_bus_rec combios_setup_i2c_bus(int ddc_line)
i2c.y_data_reg = ddc_line;
}
if (rdev->family < CHIP_R200)
i2c.hw_capable = false;
else {
switch (ddc_line) {
case RADEON_GPIO_VGA_DDC:
case RADEON_GPIO_DVI_DDC:
i2c.hw_capable = true;
break;
case RADEON_GPIO_MONID:
/* hw i2c on RADEON_GPIO_MONID doesn't seem to work
* reliably on some pre-r4xx hardware; not sure why.
*/
i2c.hw_capable = false;
break;
default:
i2c.hw_capable = false;
break;
}
}
i2c.mm_i2c = false;
i2c.i2c_id = 0;
if (ddc_line)
i2c.valid = true;
else
@ -1077,7 +1110,7 @@ bool radeon_legacy_get_ext_tmds_info_from_table(struct radeon_encoder *encoder,
struct radeon_i2c_bus_rec i2c_bus;
/* default for macs */
i2c_bus = combios_setup_i2c_bus(RADEON_GPIO_MONID);
i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
/* XXX some macs have duallink chips */
@ -1153,23 +1186,23 @@ bool radeon_legacy_get_ext_tmds_info_from_combios(struct radeon_encoder *encoder
gpio = RBIOS8(offset + 4 + 3);
switch (gpio) {
case DDC_MONID:
i2c_bus = combios_setup_i2c_bus(RADEON_GPIO_MONID);
i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
break;
case DDC_DVI:
i2c_bus = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
break;
case DDC_VGA:
i2c_bus = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
break;
case DDC_CRT2:
/* R3xx+ chips don't have GPIO_CRT2_DDC gpio pad */
if (rdev->family >= CHIP_R300)
i2c_bus = combios_setup_i2c_bus(RADEON_GPIO_MONID);
i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
else
i2c_bus = combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC);
i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_CRT2_DDC);
tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
break;
case DDC_LCD: /* MM i2c */
@ -1194,6 +1227,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
{
struct radeon_device *rdev = dev->dev_private;
struct radeon_i2c_bus_rec ddc_i2c;
struct radeon_hpd hpd;
rdev->mode_info.connector_table = radeon_connector_table;
if (rdev->mode_info.connector_table == CT_NONE) {
@ -1254,7 +1288,8 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
/* these are the most common settings */
if (rdev->flags & RADEON_SINGLE_CRTC) {
/* VGA - primary dac */
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_CRT1_SUPPORT,
@ -1264,10 +1299,12 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
ATOM_DEVICE_CRT1_SUPPORT,
DRM_MODE_CONNECTOR_VGA,
&ddc_i2c,
CONNECTOR_OBJECT_ID_VGA);
CONNECTOR_OBJECT_ID_VGA,
&hpd);
} else if (rdev->flags & RADEON_IS_MOBILITY) {
/* LVDS */
ddc_i2c = combios_setup_i2c_bus(RADEON_LCD_GPIO_MASK);
ddc_i2c = combios_setup_i2c_bus(rdev, 0);
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_LCD1_SUPPORT,
@ -1277,10 +1314,12 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
ATOM_DEVICE_LCD1_SUPPORT,
DRM_MODE_CONNECTOR_LVDS,
&ddc_i2c,
CONNECTOR_OBJECT_ID_LVDS);
CONNECTOR_OBJECT_ID_LVDS,
&hpd);
/* VGA - primary dac */
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_CRT1_SUPPORT,
@ -1290,10 +1329,12 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
ATOM_DEVICE_CRT1_SUPPORT,
DRM_MODE_CONNECTOR_VGA,
&ddc_i2c,
CONNECTOR_OBJECT_ID_VGA);
CONNECTOR_OBJECT_ID_VGA,
&hpd);
} else {
/* DVI-I - tv dac, int tmds */
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
hpd.hpd = RADEON_HPD_1;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_DFP1_SUPPORT,
@ -1309,10 +1350,12 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
ATOM_DEVICE_CRT2_SUPPORT,
DRM_MODE_CONNECTOR_DVII,
&ddc_i2c,
CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I);
CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I,
&hpd);
/* VGA - primary dac */
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_CRT1_SUPPORT,
@ -1322,11 +1365,14 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
ATOM_DEVICE_CRT1_SUPPORT,
DRM_MODE_CONNECTOR_VGA,
&ddc_i2c,
CONNECTOR_OBJECT_ID_VGA);
CONNECTOR_OBJECT_ID_VGA,
&hpd);
}
if (rdev->family != CHIP_R100 && rdev->family != CHIP_R200) {
/* TV - tv dac */
ddc_i2c.valid = false;
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_TV1_SUPPORT,
@ -1336,14 +1382,16 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
ATOM_DEVICE_TV1_SUPPORT,
DRM_MODE_CONNECTOR_SVIDEO,
&ddc_i2c,
CONNECTOR_OBJECT_ID_SVIDEO);
CONNECTOR_OBJECT_ID_SVIDEO,
&hpd);
}
break;
case CT_IBOOK:
DRM_INFO("Connector Table: %d (ibook)\n",
rdev->mode_info.connector_table);
/* LVDS */
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_LCD1_SUPPORT,
@ -1351,9 +1399,11 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
ATOM_DEVICE_LCD1_SUPPORT);
radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_LCD1_SUPPORT,
DRM_MODE_CONNECTOR_LVDS, &ddc_i2c,
CONNECTOR_OBJECT_ID_LVDS);
CONNECTOR_OBJECT_ID_LVDS,
&hpd);
/* VGA - TV DAC */
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_CRT2_SUPPORT,
@ -1361,8 +1411,11 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
ATOM_DEVICE_CRT2_SUPPORT);
radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_CRT2_SUPPORT,
DRM_MODE_CONNECTOR_VGA, &ddc_i2c,
CONNECTOR_OBJECT_ID_VGA);
CONNECTOR_OBJECT_ID_VGA,
&hpd);
/* TV - TV DAC */
ddc_i2c.valid = false;
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_TV1_SUPPORT,
@ -1371,13 +1424,15 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT,
DRM_MODE_CONNECTOR_SVIDEO,
&ddc_i2c,
CONNECTOR_OBJECT_ID_SVIDEO);
CONNECTOR_OBJECT_ID_SVIDEO,
&hpd);
break;
case CT_POWERBOOK_EXTERNAL:
DRM_INFO("Connector Table: %d (powerbook external tmds)\n",
rdev->mode_info.connector_table);
/* LVDS */
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_LCD1_SUPPORT,
@ -1385,9 +1440,11 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
ATOM_DEVICE_LCD1_SUPPORT);
radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_LCD1_SUPPORT,
DRM_MODE_CONNECTOR_LVDS, &ddc_i2c,
CONNECTOR_OBJECT_ID_LVDS);
CONNECTOR_OBJECT_ID_LVDS,
&hpd);
/* DVI-I - primary dac, ext tmds */
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
hpd.hpd = RADEON_HPD_2; /* ??? */
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_DFP2_SUPPORT,
@ -1403,8 +1460,11 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
ATOM_DEVICE_DFP2_SUPPORT |
ATOM_DEVICE_CRT1_SUPPORT,
DRM_MODE_CONNECTOR_DVII, &ddc_i2c,
CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I);
CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I,
&hpd);
/* TV - TV DAC */
ddc_i2c.valid = false;
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_TV1_SUPPORT,
@ -1413,13 +1473,15 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT,
DRM_MODE_CONNECTOR_SVIDEO,
&ddc_i2c,
CONNECTOR_OBJECT_ID_SVIDEO);
CONNECTOR_OBJECT_ID_SVIDEO,
&hpd);
break;
case CT_POWERBOOK_INTERNAL:
DRM_INFO("Connector Table: %d (powerbook internal tmds)\n",
rdev->mode_info.connector_table);
/* LVDS */
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_LCD1_SUPPORT,
@ -1427,9 +1489,11 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
ATOM_DEVICE_LCD1_SUPPORT);
radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_LCD1_SUPPORT,
DRM_MODE_CONNECTOR_LVDS, &ddc_i2c,
CONNECTOR_OBJECT_ID_LVDS);
CONNECTOR_OBJECT_ID_LVDS,
&hpd);
/* DVI-I - primary dac, int tmds */
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
hpd.hpd = RADEON_HPD_1; /* ??? */
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_DFP1_SUPPORT,
@ -1444,8 +1508,11 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
ATOM_DEVICE_DFP1_SUPPORT |
ATOM_DEVICE_CRT1_SUPPORT,
DRM_MODE_CONNECTOR_DVII, &ddc_i2c,
CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I);
CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I,
&hpd);
/* TV - TV DAC */
ddc_i2c.valid = false;
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_TV1_SUPPORT,
@ -1454,13 +1521,15 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT,
DRM_MODE_CONNECTOR_SVIDEO,
&ddc_i2c,
CONNECTOR_OBJECT_ID_SVIDEO);
CONNECTOR_OBJECT_ID_SVIDEO,
&hpd);
break;
case CT_POWERBOOK_VGA:
DRM_INFO("Connector Table: %d (powerbook vga)\n",
rdev->mode_info.connector_table);
/* LVDS */
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_LCD1_SUPPORT,
@ -1468,9 +1537,11 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
ATOM_DEVICE_LCD1_SUPPORT);
radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_LCD1_SUPPORT,
DRM_MODE_CONNECTOR_LVDS, &ddc_i2c,
CONNECTOR_OBJECT_ID_LVDS);
CONNECTOR_OBJECT_ID_LVDS,
&hpd);
/* VGA - primary dac */
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_CRT1_SUPPORT,
@ -1478,8 +1549,11 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
ATOM_DEVICE_CRT1_SUPPORT);
radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_CRT1_SUPPORT,
DRM_MODE_CONNECTOR_VGA, &ddc_i2c,
CONNECTOR_OBJECT_ID_VGA);
CONNECTOR_OBJECT_ID_VGA,
&hpd);
/* TV - TV DAC */
ddc_i2c.valid = false;
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_TV1_SUPPORT,
@ -1488,13 +1562,15 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT,
DRM_MODE_CONNECTOR_SVIDEO,
&ddc_i2c,
CONNECTOR_OBJECT_ID_SVIDEO);
CONNECTOR_OBJECT_ID_SVIDEO,
&hpd);
break;
case CT_MINI_EXTERNAL:
DRM_INFO("Connector Table: %d (mini external tmds)\n",
rdev->mode_info.connector_table);
/* DVI-I - tv dac, ext tmds */
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC);
ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_CRT2_DDC);
hpd.hpd = RADEON_HPD_2; /* ??? */
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_DFP2_SUPPORT,
@ -1510,8 +1586,11 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
ATOM_DEVICE_DFP2_SUPPORT |
ATOM_DEVICE_CRT2_SUPPORT,
DRM_MODE_CONNECTOR_DVII, &ddc_i2c,
CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I);
CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I,
&hpd);
/* TV - TV DAC */
ddc_i2c.valid = false;
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_TV1_SUPPORT,
@ -1520,13 +1599,15 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_TV1_SUPPORT,
DRM_MODE_CONNECTOR_SVIDEO,
&ddc_i2c,
CONNECTOR_OBJECT_ID_SVIDEO);
CONNECTOR_OBJECT_ID_SVIDEO,
&hpd);
break;
case CT_MINI_INTERNAL:
DRM_INFO("Connector Table: %d (mini internal tmds)\n",
rdev->mode_info.connector_table);
/* DVI-I - tv dac, int tmds */
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC);
ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_CRT2_DDC);
hpd.hpd = RADEON_HPD_1; /* ??? */
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_DFP1_SUPPORT,
@ -1541,8 +1622,11 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
ATOM_DEVICE_DFP1_SUPPORT |
ATOM_DEVICE_CRT2_SUPPORT,
DRM_MODE_CONNECTOR_DVII, &ddc_i2c,
CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I);
CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I,
&hpd);
/* TV - TV DAC */
ddc_i2c.valid = false;
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_TV1_SUPPORT,
@ -1551,13 +1635,15 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_TV1_SUPPORT,
DRM_MODE_CONNECTOR_SVIDEO,
&ddc_i2c,
CONNECTOR_OBJECT_ID_SVIDEO);
CONNECTOR_OBJECT_ID_SVIDEO,
&hpd);
break;
case CT_IMAC_G5_ISIGHT:
DRM_INFO("Connector Table: %d (imac g5 isight)\n",
rdev->mode_info.connector_table);
/* DVI-D - int tmds */
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_MONID);
ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
hpd.hpd = RADEON_HPD_1; /* ??? */
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_DFP1_SUPPORT,
@ -1565,9 +1651,11 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
ATOM_DEVICE_DFP1_SUPPORT);
radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_DFP1_SUPPORT,
DRM_MODE_CONNECTOR_DVID, &ddc_i2c,
CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D);
CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D,
&hpd);
/* VGA - tv dac */
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_CRT2_SUPPORT,
@ -1575,8 +1663,11 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
ATOM_DEVICE_CRT2_SUPPORT);
radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_CRT2_SUPPORT,
DRM_MODE_CONNECTOR_VGA, &ddc_i2c,
CONNECTOR_OBJECT_ID_VGA);
CONNECTOR_OBJECT_ID_VGA,
&hpd);
/* TV - TV DAC */
ddc_i2c.valid = false;
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_TV1_SUPPORT,
@ -1585,13 +1676,15 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT,
DRM_MODE_CONNECTOR_SVIDEO,
&ddc_i2c,
CONNECTOR_OBJECT_ID_SVIDEO);
CONNECTOR_OBJECT_ID_SVIDEO,
&hpd);
break;
case CT_EMAC:
DRM_INFO("Connector Table: %d (emac)\n",
rdev->mode_info.connector_table);
/* VGA - primary dac */
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_CRT1_SUPPORT,
@ -1599,9 +1692,11 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
ATOM_DEVICE_CRT1_SUPPORT);
radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_CRT1_SUPPORT,
DRM_MODE_CONNECTOR_VGA, &ddc_i2c,
CONNECTOR_OBJECT_ID_VGA);
CONNECTOR_OBJECT_ID_VGA,
&hpd);
/* VGA - tv dac */
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC);
ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_CRT2_DDC);
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_CRT2_SUPPORT,
@ -1609,8 +1704,11 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
ATOM_DEVICE_CRT2_SUPPORT);
radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_CRT2_SUPPORT,
DRM_MODE_CONNECTOR_VGA, &ddc_i2c,
CONNECTOR_OBJECT_ID_VGA);
CONNECTOR_OBJECT_ID_VGA,
&hpd);
/* TV - TV DAC */
ddc_i2c.valid = false;
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
ATOM_DEVICE_TV1_SUPPORT,
@ -1619,7 +1717,8 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT,
DRM_MODE_CONNECTOR_SVIDEO,
&ddc_i2c,
CONNECTOR_OBJECT_ID_SVIDEO);
CONNECTOR_OBJECT_ID_SVIDEO,
&hpd);
break;
default:
DRM_INFO("Connector table: %d (invalid)\n",
@ -1636,7 +1735,8 @@ static bool radeon_apply_legacy_quirks(struct drm_device *dev,
int bios_index,
enum radeon_combios_connector
*legacy_connector,
struct radeon_i2c_bus_rec *ddc_i2c)
struct radeon_i2c_bus_rec *ddc_i2c,
struct radeon_hpd *hpd)
{
struct radeon_device *rdev = dev->dev_private;
@ -1644,11 +1744,11 @@ static bool radeon_apply_legacy_quirks(struct drm_device *dev,
if ((rdev->family == CHIP_RS400 ||
rdev->family == CHIP_RS480) &&
ddc_i2c->mask_clk_reg == RADEON_GPIO_CRT2_DDC)
*ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_MONID);
*ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
else if ((rdev->family == CHIP_RS400 ||
rdev->family == CHIP_RS480) &&
ddc_i2c->mask_clk_reg == RADEON_GPIO_MONID) {
ddc_i2c->valid = true;
*ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIOPAD_MASK);
ddc_i2c->mask_clk_mask = (0x20 << 8);
ddc_i2c->mask_data_mask = 0x80;
ddc_i2c->a_clk_mask = (0x20 << 8);
@ -1657,20 +1757,12 @@ static bool radeon_apply_legacy_quirks(struct drm_device *dev,
ddc_i2c->en_data_mask = 0x80;
ddc_i2c->y_clk_mask = (0x20 << 8);
ddc_i2c->y_data_mask = 0x80;
ddc_i2c->mask_clk_reg = RADEON_GPIOPAD_MASK;
ddc_i2c->mask_data_reg = RADEON_GPIOPAD_MASK;
ddc_i2c->a_clk_reg = RADEON_GPIOPAD_A;
ddc_i2c->a_data_reg = RADEON_GPIOPAD_A;
ddc_i2c->en_clk_reg = RADEON_GPIOPAD_EN;
ddc_i2c->en_data_reg = RADEON_GPIOPAD_EN;
ddc_i2c->y_clk_reg = RADEON_GPIOPAD_Y;
ddc_i2c->y_data_reg = RADEON_GPIOPAD_Y;
}
/* R3xx+ chips don't have GPIO_CRT2_DDC gpio pad */
if ((rdev->family >= CHIP_R300) &&
ddc_i2c->mask_clk_reg == RADEON_GPIO_CRT2_DDC)
*ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
*ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
/* Certain IBM chipset RN50s have a BIOS reporting two VGAs,
one with VGA DDC and one with CRT2 DDC. - kill the CRT2 DDC one */
@ -1768,6 +1860,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
enum radeon_combios_connector connector;
int i = 0;
struct radeon_i2c_bus_rec ddc_i2c;
struct radeon_hpd hpd;
if (rdev->bios == NULL)
return false;
@ -1788,26 +1881,40 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
switch (ddc_type) {
case DDC_MONID:
ddc_i2c =
combios_setup_i2c_bus(RADEON_GPIO_MONID);
combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
break;
case DDC_DVI:
ddc_i2c =
combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
break;
case DDC_VGA:
ddc_i2c =
combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
break;
case DDC_CRT2:
ddc_i2c =
combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC);
combios_setup_i2c_bus(rdev, RADEON_GPIO_CRT2_DDC);
break;
default:
break;
}
switch (connector) {
case CONNECTOR_PROPRIETARY_LEGACY:
case CONNECTOR_DVI_I_LEGACY:
case CONNECTOR_DVI_D_LEGACY:
if ((tmp >> 4) & 0x1)
hpd.hpd = RADEON_HPD_2;
else
hpd.hpd = RADEON_HPD_1;
break;
default:
hpd.hpd = RADEON_HPD_NONE;
break;
}
if (!radeon_apply_legacy_quirks(dev, i, &connector,
&ddc_i2c))
&ddc_i2c, &hpd))
continue;
switch (connector) {
@ -1824,7 +1931,8 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
legacy_connector_convert
[connector],
&ddc_i2c,
CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D);
CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D,
&hpd);
break;
case CONNECTOR_CRT_LEGACY:
if (tmp & 0x1) {
@ -1850,7 +1958,8 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
legacy_connector_convert
[connector],
&ddc_i2c,
CONNECTOR_OBJECT_ID_VGA);
CONNECTOR_OBJECT_ID_VGA,
&hpd);
break;
case CONNECTOR_DVI_I_LEGACY:
devices = 0;
@ -1896,7 +2005,8 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
legacy_connector_convert
[connector],
&ddc_i2c,
connector_object_id);
connector_object_id,
&hpd);
break;
case CONNECTOR_DVI_D_LEGACY:
if ((tmp >> 4) & 0x1) {
@ -1914,7 +2024,8 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
legacy_connector_convert
[connector],
&ddc_i2c,
connector_object_id);
connector_object_id,
&hpd);
break;
case CONNECTOR_CTV_LEGACY:
case CONNECTOR_STV_LEGACY:
@ -1929,7 +2040,8 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
legacy_connector_convert
[connector],
&ddc_i2c,
CONNECTOR_OBJECT_ID_SVIDEO);
CONNECTOR_OBJECT_ID_SVIDEO,
&hpd);
break;
default:
DRM_ERROR("Unknown connector type: %d\n",
@ -1955,14 +2067,16 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
0),
ATOM_DEVICE_DFP1_SUPPORT);
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_connector(dev,
0,
ATOM_DEVICE_CRT1_SUPPORT |
ATOM_DEVICE_DFP1_SUPPORT,
DRM_MODE_CONNECTOR_DVII,
&ddc_i2c,
CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I);
CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I,
&hpd);
} else {
uint16_t crt_info =
combios_get_table_offset(dev, COMBIOS_CRT_INFO_TABLE);
@ -1973,13 +2087,15 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
ATOM_DEVICE_CRT1_SUPPORT,
1),
ATOM_DEVICE_CRT1_SUPPORT);
ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_connector(dev,
0,
ATOM_DEVICE_CRT1_SUPPORT,
DRM_MODE_CONNECTOR_VGA,
&ddc_i2c,
CONNECTOR_OBJECT_ID_VGA);
CONNECTOR_OBJECT_ID_VGA,
&hpd);
} else {
DRM_DEBUG("No connector info found\n");
return false;
@ -2007,27 +2123,27 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
case DDC_MONID:
ddc_i2c =
combios_setup_i2c_bus
(RADEON_GPIO_MONID);
(rdev, RADEON_GPIO_MONID);
break;
case DDC_DVI:
ddc_i2c =
combios_setup_i2c_bus
(RADEON_GPIO_DVI_DDC);
(rdev, RADEON_GPIO_DVI_DDC);
break;
case DDC_VGA:
ddc_i2c =
combios_setup_i2c_bus
(RADEON_GPIO_VGA_DDC);
(rdev, RADEON_GPIO_VGA_DDC);
break;
case DDC_CRT2:
ddc_i2c =
combios_setup_i2c_bus
(RADEON_GPIO_CRT2_DDC);
(rdev, RADEON_GPIO_CRT2_DDC);
break;
case DDC_LCD:
ddc_i2c =
combios_setup_i2c_bus
(RADEON_LCD_GPIO_MASK);
(rdev, RADEON_GPIOPAD_MASK);
ddc_i2c.mask_clk_mask =
RBIOS32(lcd_ddc_info + 3);
ddc_i2c.mask_data_mask =
@ -2048,7 +2164,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
case DDC_GPIO:
ddc_i2c =
combios_setup_i2c_bus
(RADEON_MDGPIO_EN_REG);
(rdev, RADEON_MDGPIO_MASK);
ddc_i2c.mask_clk_mask =
RBIOS32(lcd_ddc_info + 3);
ddc_i2c.mask_data_mask =
@ -2074,12 +2190,14 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
} else
ddc_i2c.valid = false;
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_connector(dev,
5,
ATOM_DEVICE_LCD1_SUPPORT,
DRM_MODE_CONNECTOR_LVDS,
&ddc_i2c,
CONNECTOR_OBJECT_ID_LVDS);
CONNECTOR_OBJECT_ID_LVDS,
&hpd);
}
}
@ -2090,6 +2208,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
if (tv_info) {
if (RBIOS8(tv_info + 6) == 'T') {
if (radeon_apply_legacy_tv_quirks(dev)) {
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id
(dev,
@ -2100,7 +2219,8 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
ATOM_DEVICE_TV1_SUPPORT,
DRM_MODE_CONNECTOR_SVIDEO,
&ddc_i2c,
CONNECTOR_OBJECT_ID_SVIDEO);
CONNECTOR_OBJECT_ID_SVIDEO,
&hpd);
}
}
}

View File

@ -40,6 +40,26 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
struct drm_encoder *encoder,
bool connected);
void radeon_connector_hotplug(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
if (radeon_connector->hpd.hpd != RADEON_HPD_NONE)
radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
if (radeon_dp_getsinktype(radeon_connector) == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
if (radeon_dp_needs_link_train(radeon_connector)) {
if (connector->encoder)
dp_link_train(connector->encoder, connector);
}
}
}
}
static void radeon_property_change_mode(struct drm_encoder *encoder)
{
struct drm_crtc *crtc = encoder->crtc;
@ -896,6 +916,91 @@ struct drm_connector_funcs radeon_dvi_connector_funcs = {
.force = radeon_dvi_force,
};
static void radeon_dp_connector_destroy(struct drm_connector *connector)
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
if (radeon_connector->ddc_bus)
radeon_i2c_destroy(radeon_connector->ddc_bus);
if (radeon_connector->edid)
kfree(radeon_connector->edid);
if (radeon_dig_connector->dp_i2c_bus)
radeon_i2c_destroy(radeon_dig_connector->dp_i2c_bus);
kfree(radeon_connector->con_priv);
drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector);
kfree(connector);
}
static int radeon_dp_get_modes(struct drm_connector *connector)
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
int ret;
ret = radeon_ddc_get_modes(radeon_connector);
return ret;
}
static enum drm_connector_status radeon_dp_detect(struct drm_connector *connector)
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
enum drm_connector_status ret = connector_status_disconnected;
struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
u8 sink_type;
if (radeon_connector->edid) {
kfree(radeon_connector->edid);
radeon_connector->edid = NULL;
}
sink_type = radeon_dp_getsinktype(radeon_connector);
if (sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
if (radeon_dp_getdpcd(radeon_connector)) {
radeon_dig_connector->dp_sink_type = sink_type;
ret = connector_status_connected;
}
} else {
radeon_i2c_do_lock(radeon_connector->ddc_bus, 1);
if (radeon_ddc_probe(radeon_connector)) {
radeon_dig_connector->dp_sink_type = sink_type;
ret = connector_status_connected;
}
radeon_i2c_do_lock(radeon_connector->ddc_bus, 0);
}
return ret;
}
static int radeon_dp_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
/* XXX check mode bandwidth */
if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT)
return radeon_dp_mode_valid_helper(radeon_connector, mode);
else
return MODE_OK;
}
struct drm_connector_helper_funcs radeon_dp_connector_helper_funcs = {
.get_modes = radeon_dp_get_modes,
.mode_valid = radeon_dp_mode_valid,
.best_encoder = radeon_dvi_encoder,
};
struct drm_connector_funcs radeon_dp_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.detect = radeon_dp_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = radeon_connector_set_property,
.destroy = radeon_dp_connector_destroy,
.force = radeon_dvi_force,
};
void
radeon_add_atom_connector(struct drm_device *dev,
uint32_t connector_id,
@ -904,7 +1009,8 @@ radeon_add_atom_connector(struct drm_device *dev,
struct radeon_i2c_bus_rec *i2c_bus,
bool linkb,
uint32_t igp_lane_info,
uint16_t connector_object_id)
uint16_t connector_object_id,
struct radeon_hpd *hpd)
{
struct radeon_device *rdev = dev->dev_private;
struct drm_connector *connector;
@ -944,6 +1050,7 @@ radeon_add_atom_connector(struct drm_device *dev,
radeon_connector->devices = supported_device;
radeon_connector->shared_ddc = shared_ddc;
radeon_connector->connector_object_id = connector_object_id;
radeon_connector->hpd = *hpd;
switch (connector_type) {
case DRM_MODE_CONNECTOR_VGA:
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
@ -1030,10 +1137,12 @@ radeon_add_atom_connector(struct drm_device *dev,
radeon_dig_connector->linkb = linkb;
radeon_dig_connector->igp_lane_info = igp_lane_info;
radeon_connector->con_priv = radeon_dig_connector;
drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
ret = drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
ret = drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
if (ret)
goto failed;
/* add DP i2c bus */
radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch");
if (i2c_bus->valid) {
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DP");
if (!radeon_connector->ddc_bus)
@ -1099,7 +1208,8 @@ radeon_add_legacy_connector(struct drm_device *dev,
uint32_t supported_device,
int connector_type,
struct radeon_i2c_bus_rec *i2c_bus,
uint16_t connector_object_id)
uint16_t connector_object_id,
struct radeon_hpd *hpd)
{
struct radeon_device *rdev = dev->dev_private;
struct drm_connector *connector;
@ -1129,6 +1239,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
radeon_connector->connector_id = connector_id;
radeon_connector->devices = supported_device;
radeon_connector->connector_object_id = connector_object_id;
radeon_connector->hpd = *hpd;
switch (connector_type) {
case DRM_MODE_CONNECTOR_VGA:
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);

View File

@ -481,11 +481,13 @@ int radeon_atombios_init(struct radeon_device *rdev)
rdev->mode_info.atom_context = atom_parse(atom_card_info, rdev->bios);
radeon_atom_initialize_bios_scratch_regs(rdev->ddev);
atom_allocate_fb_scratch(rdev->mode_info.atom_context);
return 0;
}
void radeon_atombios_fini(struct radeon_device *rdev)
{
kfree(rdev->mode_info.atom_context->scratch);
kfree(rdev->mode_info.atom_context);
kfree(rdev->mode_info.atom_card_info);
}
@ -568,6 +570,11 @@ int radeon_device_init(struct radeon_device *rdev,
rwlock_init(&rdev->fence_drv.lock);
INIT_LIST_HEAD(&rdev->gem.objects);
/* setup workqueue */
rdev->wq = create_workqueue("radeon");
if (rdev->wq == NULL)
return -ENOMEM;
/* Set asic functions */
r = radeon_asic_init(rdev);
if (r) {
@ -641,6 +648,7 @@ void radeon_device_fini(struct radeon_device *rdev)
DRM_INFO("radeon: finishing device.\n");
rdev->shutdown = true;
radeon_fini(rdev);
destroy_workqueue(rdev->wq);
vga_client_register(rdev->pdev, NULL, NULL, NULL);
iounmap(rdev->rmmio);
rdev->rmmio = NULL;
@ -687,6 +695,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
radeon_save_bios_scratch_regs(rdev);
radeon_suspend(rdev);
radeon_hpd_fini(rdev);
/* evict remaining vram memory */
radeon_bo_evict_vram(rdev);
@ -721,6 +730,8 @@ int radeon_resume_kms(struct drm_device *dev)
fb_set_suspend(rdev->fbdev_info, 0);
release_console_sem();
/* reset hpd state */
radeon_hpd_init(rdev);
/* blat the mode back in */
drm_helper_resume_force_mode(dev);
return 0;

View File

@ -250,6 +250,16 @@ static const char *connector_names[13] = {
"HDMI-B",
};
static const char *hpd_names[7] = {
"NONE",
"HPD1",
"HPD2",
"HPD3",
"HPD4",
"HPD5",
"HPD6",
};
static void radeon_print_display_setup(struct drm_device *dev)
{
struct drm_connector *connector;
@ -264,6 +274,8 @@ static void radeon_print_display_setup(struct drm_device *dev)
radeon_connector = to_radeon_connector(connector);
DRM_INFO("Connector %d:\n", i);
DRM_INFO(" %s\n", connector_names[connector->connector_type]);
if (radeon_connector->hpd.hpd != RADEON_HPD_NONE)
DRM_INFO(" %s\n", hpd_names[radeon_connector->hpd.hpd]);
if (radeon_connector->ddc_bus)
DRM_INFO(" DDC: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
radeon_connector->ddc_bus->rec.mask_clk_reg,
@ -337,6 +349,11 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
{
int ret = 0;
if (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
if (dig->dp_i2c_bus)
radeon_connector->edid = drm_get_edid(&radeon_connector->base, &dig->dp_i2c_bus->adapter);
}
if (!radeon_connector->ddc_bus)
return -1;
if (!radeon_connector->edid) {
@ -724,6 +741,8 @@ int radeon_modeset_init(struct radeon_device *rdev)
if (!ret) {
return ret;
}
/* initialize hpd */
radeon_hpd_init(rdev);
drm_helper_initial_config(rdev->ddev);
return 0;
}
@ -731,6 +750,7 @@ int radeon_modeset_init(struct radeon_device *rdev)
void radeon_modeset_fini(struct radeon_device *rdev)
{
if (rdev->mode_info.mode_config_initialized) {
radeon_hpd_fini(rdev);
drm_mode_config_cleanup(rdev->ddev);
rdev->mode_info.mode_config_initialized = false;
}

View File

@ -250,6 +250,12 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder,
}
}
if (ASIC_IS_DCE3(rdev) &&
(radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT))) {
struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
radeon_dp_set_link_config(connector, mode);
}
return true;
}
@ -554,6 +560,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
{
struct drm_connector *connector;
struct radeon_connector *radeon_connector;
struct radeon_connector_atom_dig *radeon_dig_connector;
connector = radeon_get_connector_for_encoder(encoder);
if (!connector)
@ -583,10 +590,10 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
return ATOM_ENCODER_MODE_LVDS;
break;
case DRM_MODE_CONNECTOR_DisplayPort:
/*if (radeon_output->MonType == MT_DP)
return ATOM_ENCODER_MODE_DP;
else*/
if (drm_detect_hdmi_monitor(radeon_connector->edid))
radeon_dig_connector = radeon_connector->con_priv;
if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT)
return ATOM_ENCODER_MODE_DP;
else if (drm_detect_hdmi_monitor(radeon_connector->edid))
return ATOM_ENCODER_MODE_HDMI;
else
return ATOM_ENCODER_MODE_DVI;
@ -605,6 +612,30 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
}
}
/*
* 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)
{
@ -646,10 +677,17 @@ 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;
@ -684,19 +722,22 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
}
}
if (radeon_encoder->pixel_clock > 165000) {
args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA_B;
args.ucLaneNum = 8;
} else {
if (dig_connector->linkb)
args.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
else
args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
args.ucLaneNum = 4;
}
args.ucEncoderMode = atombios_get_encoder_mode(encoder);
if (args.ucEncoderMode == ATOM_ENCODER_MODE_DP) {
if (dig_connector->dp_clock == 270000)
args.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
args.ucLaneNum = dig_connector->dp_lane_count;
} else if (radeon_encoder->pixel_clock > 165000)
args.ucLaneNum = 8;
else
args.ucLaneNum = 4;
if (dig_connector->linkb)
args.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
else
args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
@ -706,8 +747,8 @@ union dig_transmitter_control {
DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2;
};
static void
atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action)
void
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;
@ -719,6 +760,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action)
struct drm_connector *connector;
struct radeon_connector *radeon_connector;
struct radeon_connector_atom_dig *dig_connector;
bool is_dp = false;
connector = radeon_get_connector_for_encoder(encoder);
if (!connector)
@ -736,6 +778,9 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action)
dig_connector = radeon_connector->con_priv;
if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP)
is_dp = true;
memset(&args, 0, sizeof(args));
if (ASIC_IS_DCE32(rdev))
@ -756,17 +801,23 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action)
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)
if (is_dp)
args.v1.usPixelClock =
cpu_to_le16(dig_connector->dp_clock / 10);
else if (radeon_encoder->pixel_clock > 165000)
args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10);
else
args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
}
if (ASIC_IS_DCE32(rdev)) {
if (radeon_encoder->pixel_clock > 165000)
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:
@ -783,7 +834,9 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action)
break;
}
if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
if (is_dp)
args.v2.acConfig.fCoherentMode = 1;
else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
if (dig->coherent_mode)
args.v2.acConfig.fCoherentMode = 1;
}
@ -792,17 +845,20 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action)
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)
@ -812,35 +868,25 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action)
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->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
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 (is_dp)
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
if (dig->coherent_mode)
args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
}
@ -950,12 +996,16 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
if (is_dig) {
switch (mode) {
case DRM_MODE_DPMS_ON:
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT);
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0);
{
struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
dp_link_train(encoder, connector);
}
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT);
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0);
break;
}
} else {
@ -1057,13 +1107,33 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
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:
@ -1136,11 +1206,14 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
if (radeon_encoder->enc_priv) {
struct radeon_encoder_atom_dig *dig;
if (radeon_encoder->active_device &
(ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) {
if (radeon_encoder->enc_priv) {
struct radeon_encoder_atom_dig *dig;
dig = radeon_encoder->enc_priv;
dig->dig_block = radeon_crtc->crtc_id;
dig = radeon_encoder->enc_priv;
dig->dig_block = radeon_crtc->crtc_id;
}
}
radeon_encoder->pixel_clock = adjusted_mode->clock;
@ -1166,14 +1239,14 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
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);

View File

@ -69,13 +69,15 @@ void radeon_i2c_do_lock(struct radeon_i2c_chan *i2c, int lock_state)
* holds the i2c port in a bad state - switch hw i2c away before
* doing DDC - do this for all r200s/r300s/r400s for safety sake
*/
if ((rdev->family >= CHIP_R200) && !ASIC_IS_AVIVO(rdev)) {
if (rec->a_clk_reg == RADEON_GPIO_MONID) {
WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST |
R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1)));
} else {
WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST |
R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3)));
if (rec->hw_capable) {
if ((rdev->family >= CHIP_R200) && !ASIC_IS_AVIVO(rdev)) {
if (rec->a_clk_reg == RADEON_GPIO_MONID) {
WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST |
R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1)));
} else {
WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST |
R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3)));
}
}
}
@ -86,6 +88,12 @@ void radeon_i2c_do_lock(struct radeon_i2c_chan *i2c, int lock_state)
temp = RREG32(rec->a_data_reg) & ~rec->a_data_mask;
WREG32(rec->a_data_reg, temp);
/* set the pins to input */
temp = RREG32(rec->en_clk_reg) & ~rec->en_clk_mask;
WREG32(rec->en_clk_reg, temp);
temp = RREG32(rec->en_data_reg) & ~rec->en_data_mask;
WREG32(rec->en_data_reg, temp);
/* mask the gpio pins for software use */
temp = RREG32(rec->mask_clk_reg);
@ -172,20 +180,19 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
return NULL;
i2c->adapter.owner = THIS_MODULE;
i2c->adapter.algo_data = &i2c->algo;
i2c->dev = dev;
i2c->algo.setsda = set_data;
i2c->algo.setscl = set_clock;
i2c->algo.getsda = get_data;
i2c->algo.getscl = get_clock;
i2c->algo.udelay = 20;
i2c_set_adapdata(&i2c->adapter, i2c);
i2c->adapter.algo_data = &i2c->algo.bit;
i2c->algo.bit.setsda = set_data;
i2c->algo.bit.setscl = set_clock;
i2c->algo.bit.getsda = get_data;
i2c->algo.bit.getscl = get_clock;
i2c->algo.bit.udelay = 20;
/* vesa says 2.2 ms is enough, 1 jiffy doesn't seem to always
* make this, 2 jiffies is a lot more reliable */
i2c->algo.timeout = 2;
i2c->algo.data = i2c;
i2c->algo.bit.timeout = 2;
i2c->algo.bit.data = i2c;
i2c->rec = *rec;
i2c_set_adapdata(&i2c->adapter, i2c);
ret = i2c_bit_add_bus(&i2c->adapter);
if (ret) {
DRM_INFO("Failed to register i2c %s\n", name);
@ -199,6 +206,38 @@ out_free:
}
struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev,
struct radeon_i2c_bus_rec *rec,
const char *name)
{
struct radeon_i2c_chan *i2c;
int ret;
i2c = kzalloc(sizeof(struct radeon_i2c_chan), GFP_KERNEL);
if (i2c == NULL)
return NULL;
i2c->rec = *rec;
i2c->adapter.owner = THIS_MODULE;
i2c->dev = dev;
i2c_set_adapdata(&i2c->adapter, i2c);
i2c->adapter.algo_data = &i2c->algo.dp;
i2c->algo.dp.aux_ch = radeon_dp_i2c_aux_ch;
i2c->algo.dp.address = 0;
ret = i2c_dp_aux_add_bus(&i2c->adapter);
if (ret) {
DRM_INFO("Failed to register i2c %s\n", name);
goto out_free;
}
return i2c;
out_free:
kfree(i2c);
return NULL;
}
void radeon_i2c_destroy(struct radeon_i2c_chan *i2c)
{
if (!i2c)

View File

@ -39,11 +39,32 @@ irqreturn_t radeon_driver_irq_handler_kms(DRM_IRQ_ARGS)
return radeon_irq_process(rdev);
}
/*
* Handle hotplug events outside the interrupt handler proper.
*/
static void radeon_hotplug_work_func(struct work_struct *work)
{
struct radeon_device *rdev = container_of(work, struct radeon_device,
hotplug_work);
struct drm_device *dev = rdev->ddev;
struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_connector *connector;
if (mode_config->num_connector) {
list_for_each_entry(connector, &mode_config->connector_list, head)
radeon_connector_hotplug(connector);
}
/* Just fire off a uevent and let userspace tell us what to do */
drm_sysfs_hotplug_event(dev);
}
void radeon_driver_irq_preinstall_kms(struct drm_device *dev)
{
struct radeon_device *rdev = dev->dev_private;
unsigned i;
INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
/* Disable *all* interrupts */
rdev->irq.sw_int = false;
for (i = 0; i < 2; i++) {

View File

@ -33,6 +33,7 @@
#include <drm_crtc.h>
#include <drm_mode.h>
#include <drm_edid.h>
#include <drm_dp_helper.h>
#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/i2c-algo-bit.h>
@ -105,6 +106,13 @@ enum radeon_tv_std {
*/
struct radeon_i2c_bus_rec {
bool valid;
/* id used by atom */
uint8_t i2c_id;
/* can be used with hw i2c engine */
bool hw_capable;
/* uses multi-media i2c engine */
bool mm_i2c;
/* regs and bits */
uint32_t mask_clk_reg;
uint32_t mask_data_reg;
uint32_t a_clk_reg;
@ -164,9 +172,12 @@ struct radeon_pll {
};
struct radeon_i2c_chan {
struct drm_device *dev;
struct i2c_adapter adapter;
struct i2c_algo_bit_data algo;
struct drm_device *dev;
union {
struct i2c_algo_dp_aux_data dp;
struct i2c_algo_bit_data bit;
} algo;
struct radeon_i2c_bus_rec rec;
};
@ -328,6 +339,35 @@ struct radeon_encoder {
struct radeon_connector_atom_dig {
uint32_t igp_lane_info;
bool linkb;
/* displayport */
struct radeon_i2c_chan *dp_i2c_bus;
u8 dpcd[8];
u8 dp_sink_type;
int dp_clock;
int dp_lane_count;
};
struct radeon_gpio_rec {
bool valid;
u8 id;
u32 reg;
u32 mask;
};
enum radeon_hpd_id {
RADEON_HPD_NONE = 0,
RADEON_HPD_1,
RADEON_HPD_2,
RADEON_HPD_3,
RADEON_HPD_4,
RADEON_HPD_5,
RADEON_HPD_6,
};
struct radeon_hpd {
enum radeon_hpd_id hpd;
u8 plugged_state;
struct radeon_gpio_rec gpio;
};
struct radeon_connector {
@ -344,6 +384,7 @@ struct radeon_connector {
void *con_priv;
bool dac_load_detect;
uint16_t connector_object_id;
struct radeon_hpd hpd;
};
struct radeon_framebuffer {
@ -351,6 +392,25 @@ struct radeon_framebuffer {
struct drm_gem_object *obj;
};
extern void radeon_connector_hotplug(struct drm_connector *connector);
extern bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector);
extern int radeon_dp_mode_valid_helper(struct radeon_connector *radeon_connector,
struct drm_display_mode *mode);
extern void radeon_dp_set_link_config(struct drm_connector *connector,
struct drm_display_mode *mode);
extern void dp_link_train(struct drm_encoder *encoder,
struct drm_connector *connector);
extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector);
extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
extern void atombios_dig_transmitter_setup(struct drm_encoder *encoder,
int action, uint8_t lane_num,
uint8_t lane_set);
extern int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
uint8_t write_byte, uint8_t *read_byte);
extern struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev,
struct radeon_i2c_bus_rec *rec,
const char *name);
extern struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
struct radeon_i2c_bus_rec *rec,
const char *name);

View File

@ -887,6 +887,7 @@
# define RADEON_FP_PANEL_FORMAT (1 << 3)
# define RADEON_FP_EN_TMDS (1 << 7)
# define RADEON_FP_DETECT_SENSE (1 << 8)
# define RADEON_FP_DETECT_INT_POL (1 << 9)
# define R200_FP_SOURCE_SEL_MASK (3 << 10)
# define R200_FP_SOURCE_SEL_CRTC1 (0 << 10)
# define R200_FP_SOURCE_SEL_CRTC2 (1 << 10)
@ -894,6 +895,7 @@
# define R200_FP_SOURCE_SEL_TRANS (3 << 10)
# define RADEON_FP_SEL_CRTC1 (0 << 13)
# define RADEON_FP_SEL_CRTC2 (1 << 13)
# define R300_HPD_SEL(x) ((x) << 13)
# define RADEON_FP_CRTC_DONT_SHADOW_HPAR (1 << 15)
# define RADEON_FP_CRTC_DONT_SHADOW_VPAR (1 << 16)
# define RADEON_FP_CRTC_DONT_SHADOW_HEND (1 << 17)
@ -909,6 +911,7 @@
# define RADEON_FP2_ON (1 << 2)
# define RADEON_FP2_PANEL_FORMAT (1 << 3)
# define RADEON_FP2_DETECT_SENSE (1 << 8)
# define RADEON_FP2_DETECT_INT_POL (1 << 9)
# define R200_FP2_SOURCE_SEL_MASK (3 << 10)
# define R200_FP2_SOURCE_SEL_CRTC1 (0 << 10)
# define R200_FP2_SOURCE_SEL_CRTC2 (1 << 10)
@ -988,14 +991,20 @@
#define RADEON_GEN_INT_CNTL 0x0040
# define RADEON_CRTC_VBLANK_MASK (1 << 0)
# define RADEON_FP_DETECT_MASK (1 << 4)
# define RADEON_CRTC2_VBLANK_MASK (1 << 9)
# define RADEON_FP2_DETECT_MASK (1 << 10)
# define RADEON_SW_INT_ENABLE (1 << 25)
#define RADEON_GEN_INT_STATUS 0x0044
# define AVIVO_DISPLAY_INT_STATUS (1 << 0)
# define RADEON_CRTC_VBLANK_STAT (1 << 0)
# define RADEON_CRTC_VBLANK_STAT_ACK (1 << 0)
# define RADEON_FP_DETECT_STAT (1 << 4)
# define RADEON_FP_DETECT_STAT_ACK (1 << 4)
# define RADEON_CRTC2_VBLANK_STAT (1 << 9)
# define RADEON_CRTC2_VBLANK_STAT_ACK (1 << 9)
# define RADEON_FP2_DETECT_STAT (1 << 10)
# define RADEON_FP2_DETECT_STAT_ACK (1 << 10)
# define RADEON_SW_INT_FIRE (1 << 26)
# define RADEON_SW_INT_TEST (1 << 25)
# define RADEON_SW_INT_TEST_ACK (1 << 25)
@ -1148,16 +1157,16 @@
# define RADEON_IO_MCLK_MAX_DYN_STOP_LAT (1 << 13)
# define RADEON_MC_MCLK_DYN_ENABLE (1 << 14)
# define RADEON_IO_MCLK_DYN_ENABLE (1 << 15)
#define RADEON_GPIOPAD_MASK 0x0198
#define RADEON_GPIOPAD_A 0x019c
#define RADEON_GPIOPAD_EN 0x01a0
#define RADEON_GPIOPAD_Y 0x01a4
#define RADEON_LCD_GPIO_MASK 0x01a0
#define RADEON_LCD_GPIO_Y_REG 0x01a4
#define RADEON_MDGPIO_A_REG 0x01ac
#define RADEON_MDGPIO_EN_REG 0x01b0
#define RADEON_MDGPIO_MASK 0x0198
#define RADEON_MDGPIO_Y_REG 0x01b4
#define RADEON_MDGPIO_MASK 0x01a8
#define RADEON_MDGPIO_A 0x01ac
#define RADEON_MDGPIO_EN 0x01b0
#define RADEON_MDGPIO_Y 0x01b4
#define RADEON_MEM_ADDR_CONFIG 0x0148
#define RADEON_MEM_BASE 0x0f10 /* PCI */
#define RADEON_MEM_CNTL 0x0140

View File

@ -60,6 +60,107 @@ int rs600_mc_init(struct radeon_device *rdev)
return r;
return 0;
}
/* hpd for digital panel detect/disconnect */
bool rs600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd)
{
u32 tmp;
bool connected = false;
switch (hpd) {
case RADEON_HPD_1:
tmp = RREG32(R_007D04_DC_HOT_PLUG_DETECT1_INT_STATUS);
if (G_007D04_DC_HOT_PLUG_DETECT1_SENSE(tmp))
connected = true;
break;
case RADEON_HPD_2:
tmp = RREG32(R_007D14_DC_HOT_PLUG_DETECT2_INT_STATUS);
if (G_007D14_DC_HOT_PLUG_DETECT2_SENSE(tmp))
connected = true;
break;
default:
break;
}
return connected;
}
void rs600_hpd_set_polarity(struct radeon_device *rdev,
enum radeon_hpd_id hpd)
{
u32 tmp;
bool connected = rs600_hpd_sense(rdev, hpd);
switch (hpd) {
case RADEON_HPD_1:
tmp = RREG32(R_007D08_DC_HOT_PLUG_DETECT1_INT_CONTROL);
if (connected)
tmp &= ~S_007D08_DC_HOT_PLUG_DETECT1_INT_POLARITY(1);
else
tmp |= S_007D08_DC_HOT_PLUG_DETECT1_INT_POLARITY(1);
WREG32(R_007D08_DC_HOT_PLUG_DETECT1_INT_CONTROL, tmp);
break;
case RADEON_HPD_2:
tmp = RREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL);
if (connected)
tmp &= ~S_007D18_DC_HOT_PLUG_DETECT2_INT_POLARITY(1);
else
tmp |= S_007D18_DC_HOT_PLUG_DETECT2_INT_POLARITY(1);
WREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL, tmp);
break;
default:
break;
}
}
void rs600_hpd_init(struct radeon_device *rdev)
{
struct drm_device *dev = rdev->ddev;
struct drm_connector *connector;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
switch (radeon_connector->hpd.hpd) {
case RADEON_HPD_1:
WREG32(R_007D00_DC_HOT_PLUG_DETECT1_CONTROL,
S_007D00_DC_HOT_PLUG_DETECT1_EN(1));
rdev->irq.hpd[0] = true;
break;
case RADEON_HPD_2:
WREG32(R_007D10_DC_HOT_PLUG_DETECT2_CONTROL,
S_007D10_DC_HOT_PLUG_DETECT2_EN(1));
rdev->irq.hpd[1] = true;
break;
default:
break;
}
}
rs600_irq_set(rdev);
}
void rs600_hpd_fini(struct radeon_device *rdev)
{
struct drm_device *dev = rdev->ddev;
struct drm_connector *connector;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
switch (radeon_connector->hpd.hpd) {
case RADEON_HPD_1:
WREG32(R_007D00_DC_HOT_PLUG_DETECT1_CONTROL,
S_007D00_DC_HOT_PLUG_DETECT1_EN(0));
rdev->irq.hpd[0] = false;
break;
case RADEON_HPD_2:
WREG32(R_007D10_DC_HOT_PLUG_DETECT2_CONTROL,
S_007D10_DC_HOT_PLUG_DETECT2_EN(0));
rdev->irq.hpd[1] = false;
break;
default:
break;
}
}
}
/*
* GART.
*/
@ -209,6 +310,10 @@ int rs600_irq_set(struct radeon_device *rdev)
{
uint32_t tmp = 0;
uint32_t mode_int = 0;
u32 hpd1 = RREG32(R_007D08_DC_HOT_PLUG_DETECT1_INT_CONTROL) &
~S_007D08_DC_HOT_PLUG_DETECT1_INT_EN(1);
u32 hpd2 = RREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL) &
~S_007D18_DC_HOT_PLUG_DETECT2_INT_EN(1);
if (rdev->irq.sw_int) {
tmp |= S_000040_SW_INT_EN(1);
@ -219,8 +324,16 @@ int rs600_irq_set(struct radeon_device *rdev)
if (rdev->irq.crtc_vblank_int[1]) {
mode_int |= S_006540_D2MODE_VBLANK_INT_MASK(1);
}
if (rdev->irq.hpd[0]) {
hpd1 |= S_007D08_DC_HOT_PLUG_DETECT1_INT_EN(1);
}
if (rdev->irq.hpd[1]) {
hpd2 |= S_007D18_DC_HOT_PLUG_DETECT2_INT_EN(1);
}
WREG32(R_000040_GEN_INT_CNTL, tmp);
WREG32(R_006540_DxMODE_INT_MASK, mode_int);
WREG32(R_007D08_DC_HOT_PLUG_DETECT1_INT_CONTROL, hpd1);
WREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL, hpd2);
return 0;
}
@ -228,6 +341,7 @@ static inline uint32_t rs600_irq_ack(struct radeon_device *rdev, u32 *r500_disp_
{
uint32_t irqs = RREG32(R_000044_GEN_INT_STATUS);
uint32_t irq_mask = ~C_000044_SW_INT;
u32 tmp;
if (G_000044_DISPLAY_INT_STAT(irqs)) {
*r500_disp_int = RREG32(R_007EDC_DISP_INTERRUPT_STATUS);
@ -239,6 +353,16 @@ static inline uint32_t rs600_irq_ack(struct radeon_device *rdev, u32 *r500_disp_
WREG32(R_006D34_D2MODE_VBLANK_STATUS,
S_006D34_D2MODE_VBLANK_ACK(1));
}
if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(*r500_disp_int)) {
tmp = RREG32(R_007D08_DC_HOT_PLUG_DETECT1_INT_CONTROL);
tmp |= S_007D08_DC_HOT_PLUG_DETECT1_INT_ACK(1);
WREG32(R_007D08_DC_HOT_PLUG_DETECT1_INT_CONTROL, tmp);
}
if (G_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(*r500_disp_int)) {
tmp = RREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL);
tmp |= S_007D18_DC_HOT_PLUG_DETECT2_INT_ACK(1);
WREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL, tmp);
}
} else {
*r500_disp_int = 0;
}
@ -264,6 +388,7 @@ int rs600_irq_process(struct radeon_device *rdev)
{
uint32_t status, msi_rearm;
uint32_t r500_disp_int;
bool queue_hotplug = false;
status = rs600_irq_ack(rdev, &r500_disp_int);
if (!status && !r500_disp_int) {
@ -278,8 +403,18 @@ int rs600_irq_process(struct radeon_device *rdev)
drm_handle_vblank(rdev->ddev, 0);
if (G_007EDC_LB_D2_VBLANK_INTERRUPT(r500_disp_int))
drm_handle_vblank(rdev->ddev, 1);
if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(r500_disp_int)) {
queue_hotplug = true;
DRM_DEBUG("HPD1\n");
}
if (G_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(r500_disp_int)) {
queue_hotplug = true;
DRM_DEBUG("HPD2\n");
}
status = rs600_irq_ack(rdev, &r500_disp_int);
}
if (queue_hotplug)
queue_work(rdev->wq, &rdev->hotplug_work);
if (rdev->msi_enabled) {
switch (rdev->family) {
case CHIP_RS600:

View File

@ -30,27 +30,12 @@
/* Registers */
#define R_000040_GEN_INT_CNTL 0x000040
#define S_000040_DISPLAY_INT_STATUS(x) (((x) & 0x1) << 0)
#define G_000040_DISPLAY_INT_STATUS(x) (((x) >> 0) & 0x1)
#define C_000040_DISPLAY_INT_STATUS 0xFFFFFFFE
#define S_000040_DMA_VIPH0_INT_EN(x) (((x) & 0x1) << 12)
#define G_000040_DMA_VIPH0_INT_EN(x) (((x) >> 12) & 0x1)
#define C_000040_DMA_VIPH0_INT_EN 0xFFFFEFFF
#define S_000040_CRTC2_VSYNC(x) (((x) & 0x1) << 6)
#define G_000040_CRTC2_VSYNC(x) (((x) >> 6) & 0x1)
#define C_000040_CRTC2_VSYNC 0xFFFFFFBF
#define S_000040_SNAPSHOT2(x) (((x) & 0x1) << 7)
#define G_000040_SNAPSHOT2(x) (((x) >> 7) & 0x1)
#define C_000040_SNAPSHOT2 0xFFFFFF7F
#define S_000040_CRTC2_VBLANK(x) (((x) & 0x1) << 9)
#define G_000040_CRTC2_VBLANK(x) (((x) >> 9) & 0x1)
#define C_000040_CRTC2_VBLANK 0xFFFFFDFF
#define S_000040_FP2_DETECT(x) (((x) & 0x1) << 10)
#define G_000040_FP2_DETECT(x) (((x) >> 10) & 0x1)
#define C_000040_FP2_DETECT 0xFFFFFBFF
#define S_000040_VSYNC_DIFF_OVER_LIMIT(x) (((x) & 0x1) << 11)
#define G_000040_VSYNC_DIFF_OVER_LIMIT(x) (((x) >> 11) & 0x1)
#define C_000040_VSYNC_DIFF_OVER_LIMIT 0xFFFFF7FF
#define S_000040_SCRATCH_INT_MASK(x) (((x) & 0x1) << 18)
#define G_000040_SCRATCH_INT_MASK(x) (((x) >> 18) & 0x1)
#define C_000040_SCRATCH_INT_MASK 0xFFFBFFFF
#define S_000040_GUI_IDLE_MASK(x) (((x) & 0x1) << 19)
#define G_000040_GUI_IDLE_MASK(x) (((x) >> 19) & 0x1)
#define C_000040_GUI_IDLE_MASK 0xFFF7FFFF
#define S_000040_DMA_VIPH1_INT_EN(x) (((x) & 0x1) << 13)
#define G_000040_DMA_VIPH1_INT_EN(x) (((x) >> 13) & 0x1)
#define C_000040_DMA_VIPH1_INT_EN 0xFFFFDFFF
@ -370,7 +355,90 @@
#define S_007EDC_LB_D2_VBLANK_INTERRUPT(x) (((x) & 0x1) << 5)
#define G_007EDC_LB_D2_VBLANK_INTERRUPT(x) (((x) >> 5) & 0x1)
#define C_007EDC_LB_D2_VBLANK_INTERRUPT 0xFFFFFFDF
#define S_007EDC_DACA_AUTODETECT_INTERRUPT(x) (((x) & 0x1) << 16)
#define G_007EDC_DACA_AUTODETECT_INTERRUPT(x) (((x) >> 16) & 0x1)
#define C_007EDC_DACA_AUTODETECT_INTERRUPT 0xFFFEFFFF
#define S_007EDC_DACB_AUTODETECT_INTERRUPT(x) (((x) & 0x1) << 17)
#define G_007EDC_DACB_AUTODETECT_INTERRUPT(x) (((x) >> 17) & 0x1)
#define C_007EDC_DACB_AUTODETECT_INTERRUPT 0xFFFDFFFF
#define S_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(x) (((x) & 0x1) << 18)
#define G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(x) (((x) >> 18) & 0x1)
#define C_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT 0xFFFBFFFF
#define S_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(x) (((x) & 0x1) << 19)
#define G_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(x) (((x) >> 19) & 0x1)
#define C_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT 0xFFF7FFFF
#define R_007828_DACA_AUTODETECT_CONTROL 0x007828
#define S_007828_DACA_AUTODETECT_MODE(x) (((x) & 0x3) << 0)
#define G_007828_DACA_AUTODETECT_MODE(x) (((x) >> 0) & 0x3)
#define C_007828_DACA_AUTODETECT_MODE 0xFFFFFFFC
#define S_007828_DACA_AUTODETECT_FRAME_TIME_COUNTER(x) (((x) & 0xff) << 8)
#define G_007828_DACA_AUTODETECT_FRAME_TIME_COUNTER(x) (((x) >> 8) & 0xff)
#define C_007828_DACA_AUTODETECT_FRAME_TIME_COUNTER 0xFFFF00FF
#define S_007828_DACA_AUTODETECT_CHECK_MASK(x) (((x) & 0x3) << 16)
#define G_007828_DACA_AUTODETECT_CHECK_MASK(x) (((x) >> 16) & 0x3)
#define C_007828_DACA_AUTODETECT_CHECK_MASK 0xFFFCFFFF
#define R_007838_DACA_AUTODETECT_INT_CONTROL 0x007838
#define S_007838_DACA_AUTODETECT_ACK(x) (((x) & 0x1) << 0)
#define C_007838_DACA_DACA_AUTODETECT_ACK 0xFFFFFFFE
#define S_007838_DACA_AUTODETECT_INT_ENABLE(x) (((x) & 0x1) << 16)
#define G_007838_DACA_AUTODETECT_INT_ENABLE(x) (((x) >> 16) & 0x1)
#define C_007838_DACA_AUTODETECT_INT_ENABLE 0xFFFCFFFF
#define R_007A28_DACB_AUTODETECT_CONTROL 0x007A28
#define S_007A28_DACB_AUTODETECT_MODE(x) (((x) & 0x3) << 0)
#define G_007A28_DACB_AUTODETECT_MODE(x) (((x) >> 0) & 0x3)
#define C_007A28_DACB_AUTODETECT_MODE 0xFFFFFFFC
#define S_007A28_DACB_AUTODETECT_FRAME_TIME_COUNTER(x) (((x) & 0xff) << 8)
#define G_007A28_DACB_AUTODETECT_FRAME_TIME_COUNTER(x) (((x) >> 8) & 0xff)
#define C_007A28_DACB_AUTODETECT_FRAME_TIME_COUNTER 0xFFFF00FF
#define S_007A28_DACB_AUTODETECT_CHECK_MASK(x) (((x) & 0x3) << 16)
#define G_007A28_DACB_AUTODETECT_CHECK_MASK(x) (((x) >> 16) & 0x3)
#define C_007A28_DACB_AUTODETECT_CHECK_MASK 0xFFFCFFFF
#define R_007A38_DACB_AUTODETECT_INT_CONTROL 0x007A38
#define S_007A38_DACB_AUTODETECT_ACK(x) (((x) & 0x1) << 0)
#define C_007A38_DACB_DACA_AUTODETECT_ACK 0xFFFFFFFE
#define S_007A38_DACB_AUTODETECT_INT_ENABLE(x) (((x) & 0x1) << 16)
#define G_007A38_DACB_AUTODETECT_INT_ENABLE(x) (((x) >> 16) & 0x1)
#define C_007A38_DACB_AUTODETECT_INT_ENABLE 0xFFFCFFFF
#define R_007D00_DC_HOT_PLUG_DETECT1_CONTROL 0x007D00
#define S_007D00_DC_HOT_PLUG_DETECT1_EN(x) (((x) & 0x1) << 0)
#define G_007D00_DC_HOT_PLUG_DETECT1_EN(x) (((x) >> 0) & 0x1)
#define C_007D00_DC_HOT_PLUG_DETECT1_EN 0xFFFFFFFE
#define R_007D04_DC_HOT_PLUG_DETECT1_INT_STATUS 0x007D04
#define S_007D04_DC_HOT_PLUG_DETECT1_INT_STATUS(x) (((x) & 0x1) << 0)
#define G_007D04_DC_HOT_PLUG_DETECT1_INT_STATUS(x) (((x) >> 0) & 0x1)
#define C_007D04_DC_HOT_PLUG_DETECT1_INT_STATUS 0xFFFFFFFE
#define S_007D04_DC_HOT_PLUG_DETECT1_SENSE(x) (((x) & 0x1) << 1)
#define G_007D04_DC_HOT_PLUG_DETECT1_SENSE(x) (((x) >> 1) & 0x1)
#define C_007D04_DC_HOT_PLUG_DETECT1_SENSE 0xFFFFFFFD
#define R_007D08_DC_HOT_PLUG_DETECT1_INT_CONTROL 0x007D08
#define S_007D08_DC_HOT_PLUG_DETECT1_INT_ACK(x) (((x) & 0x1) << 0)
#define C_007D08_DC_HOT_PLUG_DETECT1_INT_ACK 0xFFFFFFFE
#define S_007D08_DC_HOT_PLUG_DETECT1_INT_POLARITY(x) (((x) & 0x1) << 8)
#define G_007D08_DC_HOT_PLUG_DETECT1_INT_POLARITY(x) (((x) >> 8) & 0x1)
#define C_007D08_DC_HOT_PLUG_DETECT1_INT_POLARITY 0xFFFFFEFF
#define S_007D08_DC_HOT_PLUG_DETECT1_INT_EN(x) (((x) & 0x1) << 16)
#define G_007D08_DC_HOT_PLUG_DETECT1_INT_EN(x) (((x) >> 16) & 0x1)
#define C_007D08_DC_HOT_PLUG_DETECT1_INT_EN 0xFFFEFFFF
#define R_007D10_DC_HOT_PLUG_DETECT2_CONTROL 0x007D10
#define S_007D10_DC_HOT_PLUG_DETECT2_EN(x) (((x) & 0x1) << 0)
#define G_007D10_DC_HOT_PLUG_DETECT2_EN(x) (((x) >> 0) & 0x1)
#define C_007D10_DC_HOT_PLUG_DETECT2_EN 0xFFFFFFFE
#define R_007D14_DC_HOT_PLUG_DETECT2_INT_STATUS 0x007D14
#define S_007D14_DC_HOT_PLUG_DETECT2_INT_STATUS(x) (((x) & 0x1) << 0)
#define G_007D14_DC_HOT_PLUG_DETECT2_INT_STATUS(x) (((x) >> 0) & 0x1)
#define C_007D14_DC_HOT_PLUG_DETECT2_INT_STATUS 0xFFFFFFFE
#define S_007D14_DC_HOT_PLUG_DETECT2_SENSE(x) (((x) & 0x1) << 1)
#define G_007D14_DC_HOT_PLUG_DETECT2_SENSE(x) (((x) >> 1) & 0x1)
#define C_007D14_DC_HOT_PLUG_DETECT2_SENSE 0xFFFFFFFD
#define R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL 0x007D18
#define S_007D18_DC_HOT_PLUG_DETECT2_INT_ACK(x) (((x) & 0x1) << 0)
#define C_007D18_DC_HOT_PLUG_DETECT2_INT_ACK 0xFFFFFFFE
#define S_007D18_DC_HOT_PLUG_DETECT2_INT_POLARITY(x) (((x) & 0x1) << 8)
#define G_007D18_DC_HOT_PLUG_DETECT2_INT_POLARITY(x) (((x) >> 8) & 0x1)
#define C_007D18_DC_HOT_PLUG_DETECT2_INT_POLARITY 0xFFFFFEFF
#define S_007D18_DC_HOT_PLUG_DETECT2_INT_EN(x) (((x) & 0x1) << 16)
#define G_007D18_DC_HOT_PLUG_DETECT2_INT_EN(x) (((x) >> 16) & 0x1)
#define C_007D18_DC_HOT_PLUG_DETECT2_INT_EN 0xFFFEFFFF
/* MC registers */
#define R_000000_MC_STATUS 0x000000

View File

@ -43,16 +43,41 @@
#define AUX_I2C_REPLY_MASK (0x3 << 6)
/* AUX CH addresses */
#define DP_LINK_BW_SET 0x100
/* DPCD */
#define DP_DPCD_REV 0x000
#define DP_MAX_LINK_RATE 0x001
#define DP_MAX_LANE_COUNT 0x002
# define DP_MAX_LANE_COUNT_MASK 0x1f
# define DP_ENHANCED_FRAME_CAP (1 << 7)
#define DP_MAX_DOWNSPREAD 0x003
# define DP_NO_AUX_HANDSHAKE_LINK_TRAINING (1 << 6)
#define DP_NORP 0x004
#define DP_DOWNSTREAMPORT_PRESENT 0x005
# define DP_DWN_STRM_PORT_PRESENT (1 << 0)
# define DP_DWN_STRM_PORT_TYPE_MASK 0x06
/* 00b = DisplayPort */
/* 01b = Analog */
/* 10b = TMDS or HDMI */
/* 11b = Other */
# define DP_FORMAT_CONVERSION (1 << 3)
#define DP_MAIN_LINK_CHANNEL_CODING 0x006
/* link configuration */
#define DP_LINK_BW_SET 0x100
# define DP_LINK_BW_1_62 0x06
# define DP_LINK_BW_2_7 0x0a
#define DP_LANE_COUNT_SET 0x101
#define DP_LANE_COUNT_SET 0x101
# define DP_LANE_COUNT_MASK 0x0f
# define DP_LANE_COUNT_ENHANCED_FRAME_EN (1 << 7)
#define DP_TRAINING_PATTERN_SET 0x102
#define DP_TRAINING_PATTERN_SET 0x102
# define DP_TRAINING_PATTERN_DISABLE 0
# define DP_TRAINING_PATTERN_1 1
# define DP_TRAINING_PATTERN_2 2
@ -102,11 +127,14 @@
#define DP_LANE0_1_STATUS 0x202
#define DP_LANE2_3_STATUS 0x203
# define DP_LANE_CR_DONE (1 << 0)
# define DP_LANE_CHANNEL_EQ_DONE (1 << 1)
# define DP_LANE_SYMBOL_LOCKED (1 << 2)
#define DP_CHANNEL_EQ_BITS (DP_LANE_CR_DONE | \
DP_LANE_CHANNEL_EQ_DONE | \
DP_LANE_SYMBOL_LOCKED)
#define DP_LANE_ALIGN_STATUS_UPDATED 0x204
#define DP_INTERLANE_ALIGN_DONE (1 << 0)
@ -120,15 +148,18 @@
#define DP_ADJUST_REQUEST_LANE0_1 0x206
#define DP_ADJUST_REQUEST_LANE2_3 0x207
# define DP_ADJUST_VOLTAGE_SWING_LANE0_MASK 0x03
# define DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT 0
# define DP_ADJUST_PRE_EMPHASIS_LANE0_MASK 0x0c
# define DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT 2
# define DP_ADJUST_VOLTAGE_SWING_LANE1_MASK 0x30
# define DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT 4
# define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK 0xc0
# define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT 6
#define DP_ADJUST_VOLTAGE_SWING_LANE0_MASK 0x03
#define DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT 0
#define DP_ADJUST_PRE_EMPHASIS_LANE0_MASK 0x0c
#define DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT 2
#define DP_ADJUST_VOLTAGE_SWING_LANE1_MASK 0x30
#define DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT 4
#define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK 0xc0
#define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT 6
#define DP_SET_POWER 0x600
# define DP_SET_POWER_D0 0x1
# define DP_SET_POWER_D3 0x2
#define MODE_I2C_START 1
#define MODE_I2C_WRITE 2