From d904ef9b00a4473af16766e99f17bdbb5f0fde65 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 17 Nov 2009 06:29:46 +1000 Subject: drm/radeon/kms: add support to atom parser for FB read/write FB read/write really doesn't need to access the actual VRAM, we can just use a scratch area. This is required for using atom displayport calls later. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atom.c | 8 ++++---- drivers/gpu/drm/radeon/atom.h | 2 ++ drivers/gpu/drm/radeon/radeon_device.c | 2 ++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index d67c42555ab..85abc0850e7 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -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)++; diff --git a/drivers/gpu/drm/radeon/atom.h b/drivers/gpu/drm/radeon/atom.h index e6eb38f2bca..6671848e5ea 100644 --- a/drivers/gpu/drm/radeon/atom.h +++ b/drivers/gpu/drm/radeon/atom.h @@ -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" diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index a014ba4cc97..60ee6a8b4f7 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -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); } -- cgit v1.2.3 From 746c1aa4d100f7441423050f34be79f401fbf7d4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 8 Dec 2009 07:07:28 +1000 Subject: drm/radeon/kms: initial radeon displayport porting This is enough to retrieve EDID and DPCP. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/Makefile | 2 +- drivers/gpu/drm/radeon/atombios_dp.c | 275 +++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_atombios.c | 17 +- drivers/gpu/drm/radeon/radeon_connectors.c | 57 +++++- drivers/gpu/drm/radeon/radeon_display.c | 7 + drivers/gpu/drm/radeon/radeon_encoders.c | 93 ++++++++++ drivers/gpu/drm/radeon/radeon_i2c.c | 50 ++++-- drivers/gpu/drm/radeon/radeon_mode.h | 21 ++- include/drm/drm_dp_helper.h | 2 + 9 files changed, 500 insertions(+), 24 deletions(-) create mode 100644 drivers/gpu/drm/radeon/atombios_dp.c diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index b5713eedd6e..feb52eee431 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -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 diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c new file mode 100644 index 00000000000..a4bc8011338 --- /dev/null +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -0,0 +1,275 @@ +/* + * 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" + +#define DP_LINK_STATUS_SIZE 6 + +bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes, + int num_bytes, u8 *read_byte, + 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->i2c_id; + args.ucDelay = delay; + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + + if (args.ucReplyStatus) { + DRM_ERROR("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->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; +} + +int 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; +} + +int radeon_dp_getsinktype(struct radeon_connector *radeon_connector) +{ + struct radeon_connector_atom_dig *radeon_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, + radeon_dig_connector->uc_i2c_id, 0); +} + +union dig_transmitter_control { + DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1; + DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2; +}; + +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 *radeon_dig_connector = radeon_connector->con_priv; + struct drm_device *dev = radeon_connector->base.dev; + struct radeon_device *rdev = dev->dev_private; + 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(radeon_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 *radeon_dig_connector = radeon_connector->con_priv; + struct drm_device *dev = radeon_connector->base.dev; + struct radeon_device *rdev = dev->dev_private; + 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(radeon_dig_connector->dp_i2c_bus, msg, msg_len, read_p, expected_bytes, delay); + return ret; +} + +void radeon_dp_getdpcp(struct radeon_connector *radeon_connector) +{ + struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; + u8 msg[25]; + int ret; + + ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCP_REV, 0, 8, msg); + if (ret) { + memcpy(radeon_dig_connector->dpcp, msg, 8); + { + int i; + printk("DPCP: "); + for (i = 0; i < 8; i++) + printk("%02x ", msg[i]); + printk("\n"); + } + } + radeon_dig_connector->dpcp[0] = 0; + return; +} + +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_INFO("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; +} + +static void dp_set_power(struct radeon_connector *radeon_connector, u8 power_state) +{ + struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; + if (radeon_dig_connector->dpcp[0] >= 0x11) { + radeon_dp_aux_native_write(radeon_connector, 0x600, 1, + &power_state); + } +} + +static void dp_update_dpvs_emph(struct radeon_connector *radeon_connector, + u8 train_set[4]) +{ + struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; + +// radeon_dp_digtransmitter_setup_vsemph(); + radeon_dp_aux_native_write(radeon_connector, DP_TRAINING_LANE0_SET, + 0/* lc */, 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); +} + +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; +} diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 5e414102c87..de05ac97647 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -47,7 +47,7 @@ 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, uint8_t uc_i2c_id); /* from radeon_legacy_encoder.c */ extern void @@ -60,8 +60,8 @@ 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_gpio(struct drm_device *dev, + uint8_t id) { struct radeon_device *rdev = dev->dev_private; struct atom_context *ctx = rdev->mode_info.atom_context; @@ -276,7 +276,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) uint16_t igp_lane_info, conn_id, connector_object_id; bool linkb; struct radeon_i2c_bus_rec ddc_bus; - + ATOM_I2C_ID_CONFIG_ACCESS i2c_id; atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); if (data_offset == 0) @@ -302,7 +302,7 @@ 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; - + i2c_id.ucAccess = 0; if (device_support & le16_to_cpu(path->usDeviceTag)) { uint8_t con_obj_id, con_obj_num, con_obj_type; @@ -420,7 +420,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) asObjects[j]. usRecordOffset)); ATOM_I2C_RECORD *i2c_record; - + while (record->ucRecordType > 0 && record-> ucRecordType <= @@ -431,6 +431,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) i2c_record = (ATOM_I2C_RECORD *) record; + i2c_id.sbfAccess = i2c_record->sucI2cId; line_mux = i2c_record-> sucI2cId. @@ -473,7 +474,7 @@ 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, i2c_id.ucAccess); } } @@ -692,7 +693,7 @@ 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, 0); } } diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 7ab3c501b4d..733427555ee 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -896,6 +896,54 @@ struct drm_connector_funcs radeon_dvi_connector_funcs = { .force = radeon_dvi_force, }; +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); + struct drm_encoder *encoder = NULL; + struct drm_encoder_helper_funcs *encoder_funcs; + struct drm_mode_object *obj; + int i; + enum drm_connector_status ret = connector_status_disconnected; + int sink_type; + bool dret; + + 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) { + radeon_dp_getdpcp(radeon_connector); + ret = connector_status_connected; + } + return ret; +} + +struct drm_connector_helper_funcs radeon_dp_connector_helper_funcs = { + .get_modes = radeon_dp_get_modes, + .mode_valid = radeon_dvi_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_connector_destroy, + .force = radeon_dvi_force, +}; + void radeon_add_atom_connector(struct drm_device *dev, uint32_t connector_id, @@ -904,7 +952,7 @@ 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, uint8_t uc_i2c_id) { struct radeon_device *rdev = dev->dev_private; struct drm_connector *connector; @@ -1030,10 +1078,13 @@ 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->uc_i2c_id = uc_i2c_id; + radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, "DP-auxch", true, uc_i2c_id); if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DP"); if (!radeon_connector->ddc_bus) diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 62b02372cb0..a1c2804b694 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -337,6 +337,13 @@ 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); + DRM_INFO("got edid %p from DP\n", radeon_connector->edid); + } + } if (!radeon_connector->ddc_bus) return -1; if (!radeon_connector->edid) { diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 291f6dd3683..37f5ea1af96 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -850,6 +850,99 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action) } +static void +atombios_dig_transmitter_setup_vsemph(struct drm_encoder *encoder, u8 lane_num, + u8 lane_set) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + union dig_transmitter_control args; + int index = 0, num = 0; + uint8_t frev, crev; + struct radeon_encoder_atom_dig *dig; + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + struct radeon_connector_atom_dig *dig_connector; + + connector = radeon_get_connector_for_encoder(encoder); + if (!connector) + return; + + radeon_connector = to_radeon_connector(connector); + + if (!radeon_encoder->enc_priv) + return; + + dig = radeon_encoder->enc_priv; + + if (!radeon_connector->con_priv) + return; + + dig_connector = radeon_connector->con_priv; + + memset(&args, 0, sizeof(args)); + + if (ASIC_IS_DCE32(rdev)) + index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); + else { + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + index = GetIndexIntoMasterTable(COMMAND, DIG1TransmitterControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + index = GetIndexIntoMasterTable(COMMAND, DIG2TransmitterControl); + break; + } + } + + atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev); + + args.v1.ucAction = ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH; + args.v1.asMode.ucLaneSel = lane_num; + args.v1.asMode.ucLaneSet = lane_set; + + if (ASIC_IS_DCE32(rdev)) { + args.v2.acConfig.fDPConnector = 1; + + if (dig->dig_block) + args.v2.acConfig.ucEncoderSel = 1; + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + args.v2.acConfig.ucTransmitterSel = 0; + num = 0; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + args.v2.acConfig.ucTransmitterSel = 1; + num = 1; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + args.v2.acConfig.ucTransmitterSel = 2; + num = 2; + break; + } + } else { + args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL; + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; + if (dig_connector->linkb) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3; + else + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3; + } + } + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + + if (ASIC_IS_DCE32(rdev)) + DRM_INFO("Output UNIPHY%d transmitter VSEMPH setup success\n", num); + else + DRM_INFO("Output DIG%d transmitter VSEMPH setup success\n", num); +} + static void atombios_yuv_setup(struct drm_encoder *encoder, bool enable) { diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index 6c645fb4dad..f200312dd5d 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -172,20 +172,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 +198,37 @@ out_free: } +struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, + const char *name, bool dp, u8 i2c_id) +{ + struct radeon_i2c_chan *i2c; + int ret; + + i2c = kzalloc(sizeof(struct radeon_i2c_chan), GFP_KERNEL); + if (i2c == NULL) + return NULL; + + i2c->i2c_id = i2c_id; + 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) diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 135693d5437..ce1cdc748f1 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -164,10 +165,14 @@ 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; + uint8_t i2c_id; }; /* mostly for macs, but really any system without connector tables */ @@ -328,6 +333,9 @@ struct radeon_encoder { struct radeon_connector_atom_dig { uint32_t igp_lane_info; bool linkb; + uint16_t uc_i2c_id; + struct radeon_i2c_chan *dp_i2c_bus; + u8 dpcp[8]; }; struct radeon_connector { @@ -344,6 +352,8 @@ struct radeon_connector { void *con_priv; bool dac_load_detect; uint16_t connector_object_id; + /* need to keep this for display port */ +// }; struct radeon_framebuffer { @@ -351,6 +361,13 @@ struct radeon_framebuffer { struct drm_gem_object *obj; }; +extern int radeon_dp_getsinktype(struct radeon_connector *radeon_connector); +extern void radeon_dp_getdpcp(struct radeon_connector *connector); +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, + const char *name, bool dp, u8 i2c_id); extern struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, struct radeon_i2c_bus_rec *rec, const char *name); diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index e49879ce95f..376155f8f81 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -43,6 +43,8 @@ #define AUX_I2C_REPLY_MASK (0x3 << 6) /* AUX CH addresses */ +#define DP_DPCP_REV 0x0 + #define DP_LINK_BW_SET 0x100 # define DP_LINK_BW_1_62 0x06 # define DP_LINK_BW_2_7 0x0a -- cgit v1.2.3 From 1a66c95a64c9ae0bc8382254f544b24b23f498ec Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 20 Nov 2009 19:40:13 -0500 Subject: drm/radeon/kms: DP fixes and cleanup from the ddx - dpcp -> dpcd - fix up dig encoder routing - aux transaction table takes delay in 10 usec units Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_dp.c | 24 ++-- drivers/gpu/drm/radeon/radeon_connectors.c | 2 +- drivers/gpu/drm/radeon/radeon_encoders.c | 221 ++++++++++++----------------- drivers/gpu/drm/radeon/radeon_mode.h | 4 +- include/drm/drm_dp_helper.h | 4 +- 5 files changed, 105 insertions(+), 150 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index a4bc8011338..d1c144be973 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -34,7 +34,7 @@ #define DP_LINK_STATUS_SIZE 6 bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes, - int num_bytes, u8 *read_byte, + int num_bytes, u8 *read_byte, u8 read_buf_len, u8 delay) { struct drm_device *dev = chan->dev; @@ -42,9 +42,9 @@ bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes, 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); @@ -53,7 +53,7 @@ bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes, args.lpDataOut = 16; args.ucDataOutLen = 0; args.ucChannelID = chan->i2c_id; - args.ucDelay = delay; + args.ucDelay = delay / 10; atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); @@ -158,24 +158,24 @@ bool radeon_dp_aux_native_read(struct radeon_connector *radeon_connector, uint16 return ret; } -void radeon_dp_getdpcp(struct radeon_connector *radeon_connector) +void radeon_dp_getdpcd(struct radeon_connector *radeon_connector) { struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; u8 msg[25]; int ret; - ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCP_REV, 0, 8, msg); + ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCD_REV, 0, 8, msg); if (ret) { - memcpy(radeon_dig_connector->dpcp, msg, 8); - { + memcpy(radeon_dig_connector->dpcd, msg, 8); + { int i; - printk("DPCP: "); + printk("DPCD: "); for (i = 0; i < 8; i++) printk("%02x ", msg[i]); printk("\n"); } } - radeon_dig_connector->dpcp[0] = 0; + radeon_dig_connector->dpcd[0] = 0; return; } @@ -199,8 +199,8 @@ static bool atom_dp_get_link_status(struct radeon_connector *radeon_connector, static void dp_set_power(struct radeon_connector *radeon_connector, u8 power_state) { struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; - if (radeon_dig_connector->dpcp[0] >= 0x11) { - radeon_dp_aux_native_write(radeon_connector, 0x600, 1, + if (radeon_dig_connector->dpcd[0] >= 0x11) { + radeon_dp_aux_native_write(radeon_connector, DP_SET_POWER, 1, &power_state); } } diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 733427555ee..4d457bc9014 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -923,7 +923,7 @@ static enum drm_connector_status radeon_dp_detect(struct drm_connector *connecto sink_type = radeon_dp_getsinktype(radeon_connector); if (sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { - radeon_dp_getdpcp(radeon_connector); + radeon_dp_getdpcd(radeon_connector); ret = connector_status_connected; } return ret; diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 37f5ea1af96..b4e7abadbfb 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -605,6 +605,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 +670,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,16 +715,15 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) } } - if (radeon_encoder->pixel_clock > 165000) { - args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA_B; + if (radeon_encoder->pixel_clock > 165000) args.ucLaneNum = 8; - } else { - if (dig_connector->linkb) - args.ucConfig |= ATOM_ENCODER_CONFIG_LINKB; - else - args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; + else args.ucLaneNum = 4; - } + + if (dig_connector->linkb) + args.ucConfig |= ATOM_ENCODER_CONFIG_LINKB; + else + args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; args.ucEncoderMode = atombios_get_encoder_mode(encoder); @@ -707,7 +737,7 @@ union dig_transmitter_control { }; static void -atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action) +atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; @@ -756,6 +786,9 @@ 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) args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); @@ -767,6 +800,8 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action) 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: @@ -792,17 +827,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,34 +850,22 @@ 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->pixel_clock > 165000) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK; + + if (dig_connector->linkb) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB; + else + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA; + if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { if (dig->coherent_mode) args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; @@ -850,99 +876,6 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action) } -static void -atombios_dig_transmitter_setup_vsemph(struct drm_encoder *encoder, u8 lane_num, - u8 lane_set) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - union dig_transmitter_control args; - int index = 0, num = 0; - uint8_t frev, crev; - struct radeon_encoder_atom_dig *dig; - struct drm_connector *connector; - struct radeon_connector *radeon_connector; - struct radeon_connector_atom_dig *dig_connector; - - connector = radeon_get_connector_for_encoder(encoder); - if (!connector) - return; - - radeon_connector = to_radeon_connector(connector); - - if (!radeon_encoder->enc_priv) - return; - - dig = radeon_encoder->enc_priv; - - if (!radeon_connector->con_priv) - return; - - dig_connector = radeon_connector->con_priv; - - memset(&args, 0, sizeof(args)); - - if (ASIC_IS_DCE32(rdev)) - index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); - else { - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - index = GetIndexIntoMasterTable(COMMAND, DIG1TransmitterControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - index = GetIndexIntoMasterTable(COMMAND, DIG2TransmitterControl); - break; - } - } - - atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev); - - args.v1.ucAction = ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH; - args.v1.asMode.ucLaneSel = lane_num; - args.v1.asMode.ucLaneSet = lane_set; - - if (ASIC_IS_DCE32(rdev)) { - args.v2.acConfig.fDPConnector = 1; - - if (dig->dig_block) - args.v2.acConfig.ucEncoderSel = 1; - - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - args.v2.acConfig.ucTransmitterSel = 0; - num = 0; - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - args.v2.acConfig.ucTransmitterSel = 1; - num = 1; - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - args.v2.acConfig.ucTransmitterSel = 2; - num = 2; - break; - } - } else { - args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL; - - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; - if (dig_connector->linkb) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3; - else - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3; - } - } - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - - if (ASIC_IS_DCE32(rdev)) - DRM_INFO("Output UNIPHY%d transmitter VSEMPH setup success\n", num); - else - DRM_INFO("Output DIG%d transmitter VSEMPH setup success\n", num); -} - static void atombios_yuv_setup(struct drm_encoder *encoder, bool enable) { @@ -1150,13 +1083,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: @@ -1259,14 +1212,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); diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index ce1cdc748f1..166f75395f5 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -335,7 +335,7 @@ struct radeon_connector_atom_dig { bool linkb; uint16_t uc_i2c_id; struct radeon_i2c_chan *dp_i2c_bus; - u8 dpcp[8]; + u8 dpcd[8]; }; struct radeon_connector { @@ -362,7 +362,7 @@ struct radeon_framebuffer { }; extern int radeon_dp_getsinktype(struct radeon_connector *radeon_connector); -extern void radeon_dp_getdpcp(struct radeon_connector *connector); +extern void radeon_dp_getdpcd(struct radeon_connector *connector); extern int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, uint8_t write_byte, uint8_t *read_byte); diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 376155f8f81..f09b0b2a99b 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -43,7 +43,7 @@ #define AUX_I2C_REPLY_MASK (0x3 << 6) /* AUX CH addresses */ -#define DP_DPCP_REV 0x0 +#define DP_DPCD_REV 0x0 #define DP_LINK_BW_SET 0x100 # define DP_LINK_BW_1_62 0x06 @@ -132,6 +132,8 @@ #define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK 0xc0 #define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT 6 +#define DP_SET_POWER 0x600 + #define MODE_I2C_START 1 #define MODE_I2C_WRITE 2 #define MODE_I2C_READ 4 -- cgit v1.2.3 From 6a93cb250a60af1bb7b4070949f8546a2fdc52ef Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 23 Nov 2009 17:39:28 -0500 Subject: drm/radeon/kms: i2c reorg - keep the atom i2c id in the i2c rec - fix gpio regs for GPIO and MDGPIO on pre-avivo chips - track whether the i2c line is hw capable - track whether the i2c line uses the multimedia i2c block Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_dp.c | 6 +- drivers/gpu/drm/radeon/radeon_atombios.c | 62 ++++++----- drivers/gpu/drm/radeon/radeon_combios.c | 158 +++++++++++++++++------------ drivers/gpu/drm/radeon/radeon_connectors.c | 5 +- drivers/gpu/drm/radeon/radeon_i2c.c | 27 +++-- drivers/gpu/drm/radeon/radeon_mode.h | 16 +-- drivers/gpu/drm/radeon/radeon_reg.h | 12 +-- 7 files changed, 166 insertions(+), 120 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index d1c144be973..fc5a2df4544 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -52,7 +52,7 @@ bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes, args.lpAuxRequest = 0; args.lpDataOut = 16; args.ucDataOutLen = 0; - args.ucChannelID = chan->i2c_id; + args.ucChannelID = chan->rec.i2c_id; args.ucDelay = delay / 10; atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); @@ -60,7 +60,7 @@ bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes, if (args.ucReplyStatus) { DRM_ERROR("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->i2c_id, args.ucReplyStatus); + chan->rec.i2c_id, args.ucReplyStatus); return false; } @@ -102,7 +102,7 @@ int radeon_dp_getsinktype(struct radeon_connector *radeon_connector) struct radeon_device *rdev = dev->dev_private; return radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_GET_SINK_TYPE, 0, - radeon_dig_connector->uc_i2c_id, 0); + radeon_dig_connector->dp_i2c_bus->rec.i2c_id, 0); } union dig_transmitter_control { diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index de05ac97647..87bf6b9d10a 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -47,7 +47,7 @@ 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, uint8_t uc_i2c_id); + uint16_t connector_object_id); /* from radeon_legacy_encoder.c */ extern void @@ -65,7 +65,7 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_gpio(struct drm_device *de { 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,24 +78,37 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_gpio(struct drm_device *de i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset); - 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); + 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.valid = true; return i2c; @@ -276,7 +289,6 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) uint16_t igp_lane_info, conn_id, connector_object_id; bool linkb; struct radeon_i2c_bus_rec ddc_bus; - ATOM_I2C_ID_CONFIG_ACCESS i2c_id; atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); if (data_offset == 0) @@ -302,7 +314,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; - i2c_id.ucAccess = 0; if (device_support & le16_to_cpu(path->usDeviceTag)) { uint8_t con_obj_id, con_obj_num, con_obj_type; @@ -420,7 +431,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) asObjects[j]. usRecordOffset)); ATOM_I2C_RECORD *i2c_record; - + while (record->ucRecordType > 0 && record-> ucRecordType <= @@ -431,7 +442,6 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) i2c_record = (ATOM_I2C_RECORD *) record; - i2c_id.sbfAccess = i2c_record->sucI2cId; line_mux = i2c_record-> sucI2cId. @@ -474,7 +484,7 @@ 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, i2c_id.ucAccess); + connector_object_id); } } @@ -693,7 +703,7 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct connector_type, &bios_connectors[i].ddc_bus, false, 0, - connector_object_id, 0); + connector_object_id); } } diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 14d3555e4af..b6761cde1ec 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -442,29 +442,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 +485,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 +1109,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 +1185,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 */ @@ -1254,7 +1286,7 @@ 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); radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_CRT1_SUPPORT, @@ -1267,7 +1299,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) CONNECTOR_OBJECT_ID_VGA); } 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); radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_LCD1_SUPPORT, @@ -1280,7 +1312,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) CONNECTOR_OBJECT_ID_LVDS); /* VGA - primary dac */ - ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); + ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC); radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_CRT1_SUPPORT, @@ -1293,7 +1325,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) CONNECTOR_OBJECT_ID_VGA); } 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); radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_DFP1_SUPPORT, @@ -1312,7 +1344,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I); /* VGA - primary dac */ - ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); + ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC); radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_CRT1_SUPPORT, @@ -1343,7 +1375,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) 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); radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_LCD1_SUPPORT, @@ -1353,7 +1385,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) DRM_MODE_CONNECTOR_LVDS, &ddc_i2c, CONNECTOR_OBJECT_ID_LVDS); /* VGA - TV DAC */ - ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); + ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC); radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_CRT2_SUPPORT, @@ -1377,7 +1409,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) 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); radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_LCD1_SUPPORT, @@ -1387,7 +1419,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) DRM_MODE_CONNECTOR_LVDS, &ddc_i2c, CONNECTOR_OBJECT_ID_LVDS); /* 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); radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_DFP2_SUPPORT, @@ -1419,7 +1451,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) 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); radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_LCD1_SUPPORT, @@ -1429,7 +1461,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) DRM_MODE_CONNECTOR_LVDS, &ddc_i2c, CONNECTOR_OBJECT_ID_LVDS); /* 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); radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_DFP1_SUPPORT, @@ -1460,7 +1492,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) 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); radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_LCD1_SUPPORT, @@ -1470,7 +1502,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) DRM_MODE_CONNECTOR_LVDS, &ddc_i2c, CONNECTOR_OBJECT_ID_LVDS); /* VGA - primary dac */ - ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); + ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC); radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_CRT1_SUPPORT, @@ -1494,7 +1526,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) 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); radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_DFP2_SUPPORT, @@ -1526,7 +1558,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) 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); radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_DFP1_SUPPORT, @@ -1557,7 +1589,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) 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); radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_DFP1_SUPPORT, @@ -1567,7 +1599,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) DRM_MODE_CONNECTOR_DVID, &ddc_i2c, CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D); /* VGA - tv dac */ - ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); + ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC); radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_CRT2_SUPPORT, @@ -1591,7 +1623,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) 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); radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_CRT1_SUPPORT, @@ -1601,7 +1633,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) DRM_MODE_CONNECTOR_VGA, &ddc_i2c, CONNECTOR_OBJECT_ID_VGA); /* VGA - tv dac */ - ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC); + ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_CRT2_DDC); radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_CRT2_SUPPORT, @@ -1644,11 +1676,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 +1689,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 */ @@ -1788,19 +1812,19 @@ 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; @@ -1955,7 +1979,7 @@ 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); radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_CRT1_SUPPORT | @@ -1973,7 +1997,7 @@ 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); radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_CRT1_SUPPORT, @@ -2007,27 +2031,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 +2072,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 = diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 4d457bc9014..98634ce5ba1 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -952,7 +952,7 @@ 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, uint8_t uc_i2c_id) + uint16_t connector_object_id) { struct radeon_device *rdev = dev->dev_private; struct drm_connector *connector; @@ -1083,8 +1083,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (ret) goto failed; /* add DP i2c bus */ - radeon_dig_connector->uc_i2c_id = uc_i2c_id; - radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, "DP-auxch", true, uc_i2c_id); + 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) diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index f200312dd5d..da3da1e89d0 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -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); @@ -199,7 +207,8 @@ out_free: } struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, - const char *name, bool dp, u8 i2c_id) + struct radeon_i2c_bus_rec *rec, + const char *name) { struct radeon_i2c_chan *i2c; int ret; @@ -208,7 +217,7 @@ struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, if (i2c == NULL) return NULL; - i2c->i2c_id = i2c_id; + i2c->rec = *rec; i2c->adapter.owner = THIS_MODULE; i2c->dev = dev; i2c_set_adapdata(&i2c->adapter, i2c); diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 166f75395f5..1964afb94db 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -106,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; @@ -172,7 +179,6 @@ struct radeon_i2c_chan { struct i2c_algo_bit_data bit; } algo; struct radeon_i2c_bus_rec rec; - uint8_t i2c_id; }; /* mostly for macs, but really any system without connector tables */ @@ -333,7 +339,6 @@ struct radeon_encoder { struct radeon_connector_atom_dig { uint32_t igp_lane_info; bool linkb; - uint16_t uc_i2c_id; struct radeon_i2c_chan *dp_i2c_bus; u8 dpcd[8]; }; @@ -352,8 +357,6 @@ struct radeon_connector { void *con_priv; bool dac_load_detect; uint16_t connector_object_id; - /* need to keep this for display port */ -// }; struct radeon_framebuffer { @@ -362,12 +365,13 @@ struct radeon_framebuffer { }; extern int radeon_dp_getsinktype(struct radeon_connector *radeon_connector); -extern void radeon_dp_getdpcd(struct radeon_connector *connector); +extern void radeon_dp_getdpcd(struct radeon_connector *radeon_connector); 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, - const char *name, bool dp, u8 i2c_id); + 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); diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index c4c41c8d908..b8116401ffa 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -1148,16 +1148,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 -- cgit v1.2.3 From 4143e919ea999c9356ae4f71b5a3a80e075290d5 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 23 Nov 2009 18:02:35 -0500 Subject: drm/radeon/kms: store sink type in atom dig connector This will be used laster when the encoder and transmitters are set up. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_dp.c | 6 +++--- drivers/gpu/drm/radeon/radeon_connectors.c | 17 +++++++++++------ drivers/gpu/drm/radeon/radeon_mode.h | 4 +++- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index fc5a2df4544..e761fefaacb 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -78,8 +78,8 @@ bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes, return true; } -int radeon_dp_encoder_service(struct radeon_device *rdev, int action, int dp_clock, - uint8_t ucconfig, uint8_t lane_num) +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); @@ -95,7 +95,7 @@ int radeon_dp_encoder_service(struct radeon_device *rdev, int action, int dp_clo return args.ucStatus; } -int radeon_dp_getsinktype(struct radeon_connector *radeon_connector) +u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector) { struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; struct drm_device *dev = radeon_connector->base.dev; diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 98634ce5ba1..b51e38386cc 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -908,13 +908,9 @@ static int radeon_dp_get_modes(struct drm_connector *connector) static enum drm_connector_status radeon_dp_detect(struct drm_connector *connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct drm_encoder *encoder = NULL; - struct drm_encoder_helper_funcs *encoder_funcs; - struct drm_mode_object *obj; - int i; enum drm_connector_status ret = connector_status_disconnected; - int sink_type; - bool dret; + struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; + u8 sink_type; if (radeon_connector->edid) { kfree(radeon_connector->edid); @@ -924,8 +920,17 @@ static enum drm_connector_status radeon_dp_detect(struct drm_connector *connecto sink_type = radeon_dp_getsinktype(radeon_connector); if (sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { 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; } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 1964afb94db..338d0af1851 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -339,8 +339,10 @@ 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; }; struct radeon_connector { @@ -364,7 +366,7 @@ struct radeon_framebuffer { struct drm_gem_object *obj; }; -extern int radeon_dp_getsinktype(struct radeon_connector *radeon_connector); +extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector); extern void radeon_dp_getdpcd(struct radeon_connector *radeon_connector); extern int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, uint8_t write_byte, uint8_t *read_byte); -- cgit v1.2.3 From f92a8b6758bdc0f277c4f42aa7d736a205ac9ded Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 23 Nov 2009 18:40:40 -0500 Subject: drm/radeon/kms: handle dp sinks in atom encoder/transmitter tables Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_dp.c | 69 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_encoders.c | 41 +++++++++++++------ drivers/gpu/drm/radeon/radeon_mode.h | 2 + 3 files changed, 100 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index e761fefaacb..76eb5c8a701 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -33,6 +33,75 @@ #define DP_LINK_STATUS_SIZE 6 +/* move these to drm_dp_helper.c/h */ + +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); + +int dp_lanes_for_mode_clock(int max_link_bw, int mode_clock) +{ + int i; + + switch (max_link_bw) { + case DP_LINK_BW_1_62: + default: + for (i = 0; i < num_dp_clocks; i++) { + if (i % 2) + continue; + 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++) { + if (dp_clocks[i] > mode_clock) { + if (i < 2) + return 1; + else if (i < 4) + return 2; + else + return 4; + } + } + break; + } + + return 0; +} + +int dp_link_clock_for_mode_clock(int max_link_bw, int mode_clock) +{ + int i; + + switch (max_link_bw) { + case DP_LINK_BW_1_62: + default: + return 162000; + break; + case DP_LINK_BW_2_7: + for (i = 0; i < num_dp_clocks; i++) { + if (dp_clocks[i] > mode_clock) + return (i % 2) ? 270000 : 162000; + } + } + + return 0; +} + 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) diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index b4e7abadbfb..8f3d67b6032 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -554,6 +554,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 +584,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; @@ -715,7 +716,15 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) } } - if (radeon_encoder->pixel_clock > 165000) + args.ucEncoderMode = atombios_get_encoder_mode(encoder); + + if (args.ucEncoderMode == ATOM_ENCODER_MODE_DP) { + if (dp_link_clock_for_mode_clock(dig_connector->dpcd[1], + radeon_encoder->pixel_clock) == 270000) + args.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; + args.ucLaneNum = dp_lanes_for_mode_clock(dig_connector->dpcd[1], + radeon_encoder->pixel_clock); + } else if (radeon_encoder->pixel_clock > 165000) args.ucLaneNum = 8; else args.ucLaneNum = 4; @@ -725,8 +734,6 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) else args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; - args.ucEncoderMode = atombios_get_encoder_mode(encoder); - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } @@ -749,6 +756,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t 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) @@ -766,6 +774,9 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t 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)) @@ -790,14 +801,16 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t 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(dp_link_clock_for_mode_clock(dig_connector->dpcd[1], + radeon_encoder->pixel_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) @@ -818,7 +831,9 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t 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; } @@ -866,7 +881,9 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t else args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA; - if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { + 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; } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 338d0af1851..b516401c151 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -366,6 +366,8 @@ struct radeon_framebuffer { struct drm_gem_object *obj; }; +extern int dp_lanes_for_mode_clock(int max_link_bw, int mode_clock); +extern int dp_link_clock_for_mode_clock(int max_link_bw, int mode_clock); extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector); extern void radeon_dp_getdpcd(struct radeon_connector *radeon_connector); extern int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, -- cgit v1.2.3 From 5801ead6bd6bddf5505d6eab55f84d8ee8106cd8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 24 Nov 2009 13:32:59 -0500 Subject: drm/radeon/kms: add support for DP modesetting Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atom.c | 25 ++ drivers/gpu/drm/radeon/atombios_dp.c | 541 ++++++++++++++++++++++++++--- drivers/gpu/drm/radeon/radeon_connectors.c | 16 +- drivers/gpu/drm/radeon/radeon_encoders.c | 30 +- drivers/gpu/drm/radeon/radeon_mode.h | 13 +- include/drm/drm_dp_helper.h | 57 ++- 6 files changed, 600 insertions(+), 82 deletions(-) diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index 85abc0850e7..6578d19dff9 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -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; +} diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 76eb5c8a701..ebaf3f8cd60 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -31,9 +31,20 @@ #include "atom-bits.h" #include "drm_dp_helper.h" -#define DP_LINK_STATUS_SIZE 6 - /* 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 char *link_train_names[] = { + "pattern 1", "pattern 2", "idle", "off" +}; static const int dp_clocks[] = { 54000, // 1 lane, 1.62 Ghz @@ -46,9 +57,18 @@ static const int dp_clocks[] = { static const int num_dp_clocks = sizeof(dp_clocks) / sizeof(int); -int dp_lanes_for_mode_clock(int max_link_bw, int mode_clock) +/* 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: @@ -56,6 +76,19 @@ int dp_lanes_for_mode_clock(int max_link_bw, int mode_clock) 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; @@ -68,6 +101,19 @@ int dp_lanes_for_mode_clock(int max_link_bw, int mode_clock) 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; @@ -83,17 +129,56 @@ int dp_lanes_for_mode_clock(int max_link_bw, int mode_clock) return 0; } -int dp_link_clock_for_mode_clock(int max_link_bw, int mode_clock) +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: - return 162000; + 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; } @@ -102,6 +187,145 @@ int dp_link_clock_for_mode_clock(int max_link_bw, int mode_clock) 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_INFO("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_INFO("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) @@ -147,44 +371,10 @@ bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes, return true; } -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 *radeon_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, - radeon_dig_connector->dp_i2c_bus->rec.i2c_id, 0); -} - -union dig_transmitter_control { - DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1; - DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2; -}; - 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 *radeon_dig_connector = radeon_connector->con_priv; - struct drm_device *dev = radeon_connector->base.dev; - struct radeon_device *rdev = dev->dev_private; + struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; u8 msg[20]; u8 msg_len, dp_msg_len; bool ret; @@ -201,7 +391,7 @@ bool radeon_dp_aux_native_write(struct radeon_connector *radeon_connector, uint1 memcpy(&msg[4], send, send_bytes); msg_len = 4 + send_bytes; - ret = radeon_process_aux_ch(radeon_dig_connector->dp_i2c_bus, msg, msg_len, NULL, 0, 0); + ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus, msg, msg_len, NULL, 0, 0); return ret; } @@ -209,9 +399,7 @@ bool radeon_dp_aux_native_read(struct radeon_connector *radeon_connector, uint16 uint8_t delay, uint8_t expected_bytes, uint8_t *read_p) { - struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; - struct drm_device *dev = radeon_connector->base.dev; - struct radeon_device *rdev = dev->dev_private; + struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; u8 msg[20]; u8 msg_len, dp_msg_len; bool ret = false; @@ -223,19 +411,47 @@ bool radeon_dp_aux_native_read(struct radeon_connector *radeon_connector, uint16 msg[3] = (dp_msg_len) << 4; msg[3] |= expected_bytes - 1; - ret = radeon_process_aux_ch(radeon_dig_connector->dp_i2c_bus, msg, msg_len, read_p, expected_bytes, delay); + 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); +} + void radeon_dp_getdpcd(struct radeon_connector *radeon_connector) { - struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; + 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(radeon_dig_connector->dpcd, msg, 8); + memcpy(dig_connector->dpcd, msg, 8); { int i; printk("DPCD: "); @@ -244,10 +460,38 @@ void radeon_dp_getdpcd(struct radeon_connector *radeon_connector) printk("\n"); } } - radeon_dig_connector->dpcd[0] = 0; + dig_connector->dpcd[0] = 0; return; } +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]) { @@ -267,21 +511,41 @@ static bool atom_dp_get_link_status(struct radeon_connector *radeon_connector, static void dp_set_power(struct radeon_connector *radeon_connector, u8 power_state) { - struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; - if (radeon_dig_connector->dpcd[0] >= 0x11) { + 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 *radeon_dig_connector = radeon_connector->con_priv; + 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_digtransmitter_setup_vsemph(); radeon_dp_aux_native_write(radeon_connector, DP_TRAINING_LANE0_SET, - 0/* lc */, train_set); + dig_connector->dp_lane_count, train_set); } static void dp_set_training(struct radeon_connector *radeon_connector, @@ -291,6 +555,176 @@ static void dp_set_training(struct radeon_connector *radeon_connector, 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); + dp_update_dpvs_emph(radeon_connector, encoder, train_set); + udelay(400); + /* set training pattern 1 on the sink */ + dp_set_training(radeon_connector, DP_TRAINING_PATTERN_1); + + /* 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_INFO("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_INFO("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) { @@ -342,3 +776,4 @@ int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, } return -EREMOTEIO; } + diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index b51e38386cc..3837cc94261 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -934,9 +934,23 @@ static enum drm_connector_status radeon_dp_detect(struct drm_connector *connecto 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_dvi_mode_valid, + .mode_valid = radeon_dp_mode_valid, .best_encoder = radeon_dvi_encoder, }; diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 8f3d67b6032..397c86f761c 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -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; } @@ -719,11 +725,9 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) args.ucEncoderMode = atombios_get_encoder_mode(encoder); if (args.ucEncoderMode == ATOM_ENCODER_MODE_DP) { - if (dp_link_clock_for_mode_clock(dig_connector->dpcd[1], - radeon_encoder->pixel_clock) == 270000) + if (dig_connector->dp_clock == 270000) args.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; - args.ucLaneNum = dp_lanes_for_mode_clock(dig_connector->dpcd[1], - radeon_encoder->pixel_clock); + args.ucLaneNum = dig_connector->dp_lane_count; } else if (radeon_encoder->pixel_clock > 165000) args.ucLaneNum = 8; else @@ -743,7 +747,7 @@ union dig_transmitter_control { DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2; }; -static void +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; @@ -803,8 +807,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t } else { if (is_dp) args.v1.usPixelClock = - cpu_to_le16(dp_link_clock_for_mode_clock(dig_connector->dpcd[1], - radeon_encoder->pixel_clock) / 10); + 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 @@ -1198,12 +1201,16 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); - 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; @@ -1237,6 +1244,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, 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); + dp_link_train(encoder, connector); break; case ENCODER_OBJECT_ID_INTERNAL_DDI: atombios_ddia_setup(encoder, ATOM_ENABLE); diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index b516401c151..7d03e397149 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -343,6 +343,8 @@ struct radeon_connector_atom_dig { struct radeon_i2c_chan *dp_i2c_bus; u8 dpcd[8]; u8 dp_sink_type; + int dp_clock; + int dp_lane_count; }; struct radeon_connector { @@ -366,10 +368,17 @@ struct radeon_framebuffer { struct drm_gem_object *obj; }; -extern int dp_lanes_for_mode_clock(int max_link_bw, int mode_clock); -extern int dp_link_clock_for_mode_clock(int max_link_bw, int mode_clock); +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 void 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); diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index f09b0b2a99b..a49e791db0b 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -43,18 +43,41 @@ #define AUX_I2C_REPLY_MASK (0x3 << 6) /* AUX CH addresses */ -#define DP_DPCD_REV 0x0 +/* DPCD */ +#define DP_DPCD_REV 0x000 -#define DP_LINK_BW_SET 0x100 +#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 @@ -104,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) @@ -122,17 +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 -- cgit v1.2.3 From ffd09c648a76a1cf96872c033e98d4730f9b10a4 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 24 Nov 2009 16:13:23 -0500 Subject: drm/radeon/kms: free aux channel i2c adapter on destroy Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_connectors.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 3837cc94261..9c57633a4f4 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -896,6 +896,23 @@ 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); @@ -959,7 +976,7 @@ struct drm_connector_funcs radeon_dp_connector_funcs = { .detect = radeon_dp_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = radeon_connector_set_property, - .destroy = radeon_connector_destroy, + .destroy = radeon_dp_connector_destroy, .force = radeon_dvi_force, }; -- cgit v1.2.3 From 54d9cb47dd6a754e434e5adeccb3a1e2835594fd Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 26 Nov 2009 08:49:17 +1000 Subject: drm/radeon/kms/dp: fix return in dpcd retrival. Not returning here caused us to get a display port version of 0 for everything this caused power up to not get sent which ends up in a black screen. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_dp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index ebaf3f8cd60..65c82395c8e 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -459,6 +459,7 @@ void radeon_dp_getdpcd(struct radeon_connector *radeon_connector) printk("%02x ", msg[i]); printk("\n"); } + return; } dig_connector->dpcd[0] = 0; return; -- cgit v1.2.3 From 5fbfce7fc906c4a9e3d5e0872e5d6affaca54761 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 26 Nov 2009 08:55:18 +1000 Subject: drm/radeon/kms: make displayport work by reorganising vsemph setup. This fix reorganises the initial DP link training slightly, and actually makes DP work under kms here. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_dp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 65c82395c8e..28741d40bf6 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -627,11 +627,12 @@ void dp_link_train(struct drm_encoder *encoder, /* set initial vs/emph */ memset(train_set, 0, 4); - dp_update_dpvs_emph(radeon_connector, encoder, train_set); 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; -- cgit v1.2.3 From 58682f107ad5178e47a45af3af1851442d05d7fc Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 26 Nov 2009 08:56:35 +1000 Subject: drm/radeon/kms: do dp link training at dpms on time not mode set. This moves the radeon DP link training call to happen when we dpms on the encoder not when we set the mode. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 397c86f761c..b4f23ec9320 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -996,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 { @@ -1201,7 +1205,6 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); - struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); if (radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) { @@ -1244,7 +1247,6 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, 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); - dp_link_train(encoder, connector); break; case ENCODER_OBJECT_ID_INTERNAL_DDI: atombios_ddia_setup(encoder, ATOM_ENABLE); -- cgit v1.2.3 From e8696330e2a95e1b5872550dcf3ed04aecaf96b3 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 26 Nov 2009 08:57:23 +1000 Subject: drm/radeon/kms: drop unused array to fix warning. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_dp.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 28741d40bf6..e1cbd5049f8 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -42,9 +42,6 @@ static char *voltage_names[] = { static char *pre_emph_names[] = { "0dB", "3.5dB", "6dB", "9.5dB" }; -static char *link_train_names[] = { - "pattern 1", "pattern 2", "idle", "off" -}; static const int dp_clocks[] = { 54000, // 1 lane, 1.62 Ghz -- cgit v1.2.3 From 9fa05c98d69eb77c82e59b5e434ca63bba230ba0 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 27 Nov 2009 13:01:46 -0500 Subject: drm/radeon/kms: fix DP detect only return connected if there is actually a monitor connected. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_dp.c | 6 +++--- drivers/gpu/drm/radeon/radeon_connectors.c | 7 ++++--- drivers/gpu/drm/radeon/radeon_display.c | 6 ++---- drivers/gpu/drm/radeon/radeon_mode.h | 2 +- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index e1cbd5049f8..75977a46ba1 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -440,7 +440,7 @@ u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector) dig_connector->dp_i2c_bus->rec.i2c_id, 0); } -void radeon_dp_getdpcd(struct radeon_connector *radeon_connector) +bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector) { struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; u8 msg[25]; @@ -456,10 +456,10 @@ void radeon_dp_getdpcd(struct radeon_connector *radeon_connector) printk("%02x ", msg[i]); printk("\n"); } - return; + return true; } dig_connector->dpcd[0] = 0; - return; + return false; } void radeon_dp_set_link_config(struct drm_connector *connector, diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 9c57633a4f4..56384721360 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -936,9 +936,10 @@ static enum drm_connector_status radeon_dp_detect(struct drm_connector *connecto sink_type = radeon_dp_getsinktype(radeon_connector); if (sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { - radeon_dp_getdpcd(radeon_connector); - radeon_dig_connector->dp_sink_type = sink_type; - ret = connector_status_connected; + 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)) { diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index a1c2804b694..62c929e5b08 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -339,10 +339,8 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) 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); - DRM_INFO("got edid %p from DP\n", radeon_connector->edid); - } + 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; diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 7d03e397149..a2633628dbb 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -375,7 +375,7 @@ extern void radeon_dp_set_link_config(struct drm_connector *connector, extern void dp_link_train(struct drm_encoder *encoder, struct drm_connector *connector); extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector); -extern void radeon_dp_getdpcd(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); -- cgit v1.2.3 From 53c1e09fea4cf3fc0ec1f735a5fcab78c43cb55d Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 27 Nov 2009 13:14:37 -0500 Subject: drm/radeon/kms: clean up DP debugging Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_dp.c | 56 ++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 75977a46ba1..784ba80afcb 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -44,12 +44,12 @@ static char *pre_emph_names[] = { }; 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 + 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); @@ -296,10 +296,10 @@ static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE], u8 this_v = dp_get_adjust_request_voltage(link_status, lane); u8 this_p = dp_get_adjust_request_pre_emphasis(link_status, lane); - DRM_INFO("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]); + 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; @@ -313,9 +313,9 @@ static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE], if (p >= dp_pre_emphasis_max(v)) p = dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; - DRM_INFO("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]); + 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; @@ -348,7 +348,7 @@ bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes, atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); if (args.ucReplyStatus) { - DRM_ERROR("failed to get auxch %02x%02x %02x %02x 0x%02x %02x\n", + 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; @@ -451,10 +451,10 @@ bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector) memcpy(dig_connector->dpcd, msg, 8); { int i; - printk("DPCD: "); + DRM_DEBUG("DPCD: "); for (i = 0; i < 8; i++) - printk("%02x ", msg[i]); - printk("\n"); + DRM_DEBUG("%02x ", msg[i]); + DRM_DEBUG("\n"); } return true; } @@ -501,9 +501,9 @@ static bool atom_dp_get_link_status(struct radeon_connector *radeon_connector, return false; } - DRM_INFO("link status %02x %02x %02x %02x %02x %02x\n", - link_status[0], link_status[1], link_status[2], - link_status[3], link_status[4], link_status[5]); + DRM_DEBUG("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; } @@ -671,10 +671,10 @@ void dp_link_train(struct drm_encoder *encoder, if (!clock_recovery) DRM_ERROR("clock recovery failed\n"); else - DRM_INFO("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); + 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 */ @@ -712,10 +712,10 @@ void dp_link_train(struct drm_encoder *encoder, if (!channel_eq) DRM_ERROR("channel eq failed\n"); else - DRM_INFO("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); + 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); -- cgit v1.2.3 From eed45b30cd1423f8dc10b4312700773cac13c1c8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 4 Dec 2009 14:45:27 -0500 Subject: drm/radeon/kms: get HPD info for connectors This populates the connectors with HPD (Hot Plug Detect) information. This will be used in subsequent patches for automatic digital monitor connect/disconnect handling. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios.h | 2 +- drivers/gpu/drm/radeon/r500_reg.h | 2 + drivers/gpu/drm/radeon/radeon_atombios.c | 190 ++++++++++++++++++++++------- drivers/gpu/drm/radeon/radeon_combios.c | 176 ++++++++++++++++++++------ drivers/gpu/drm/radeon/radeon_connectors.c | 8 +- drivers/gpu/drm/radeon/radeon_display.c | 12 ++ drivers/gpu/drm/radeon/radeon_mode.h | 24 ++++ 7 files changed, 330 insertions(+), 84 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h index c11ddddfb3b..e83927644de 100644 --- a/drivers/gpu/drm/radeon/atombios.h +++ b/drivers/gpu/drm/radeon/atombios.h @@ -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 { diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h index 7baa7395556..74ad89bdf2b 100644 --- a/drivers/gpu/drm/radeon/r500_reg.h +++ b/drivers/gpu/drm/radeon/r500_reg.h @@ -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 diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 87bf6b9d10a..d7b0feb7d47 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -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,10 +61,9 @@ 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; struct radeon_i2c_bus_rec i2c; @@ -114,11 +114,80 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_gpio(struct drm_device *de 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 */ @@ -279,16 +348,19 @@ 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); if (data_offset == 0) @@ -414,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]. @@ -431,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 = @@ -458,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, @@ -484,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); } } @@ -539,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 @@ -554,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); @@ -564,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]; @@ -619,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 @@ -632,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; @@ -654,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) { @@ -680,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; } @@ -690,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, @@ -703,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); } } diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index b6761cde1ec..c5021a3445d 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -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 @@ -1226,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) { @@ -1287,6 +1289,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) if (rdev->flags & RADEON_SINGLE_CRTC) { /* VGA - primary dac */ 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, @@ -1296,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(rdev, 0); + hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_LCD1_SUPPORT, @@ -1309,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(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,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(rdev, RADEON_GPIO_DVI_DDC); + hpd.hpd = RADEON_HPD_1; radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_DFP1_SUPPORT, @@ -1341,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(rdev, RADEON_GPIO_VGA_DDC); + hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_CRT1_SUPPORT, @@ -1354,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, @@ -1368,7 +1382,8 @@ 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: @@ -1376,6 +1391,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) rdev->mode_info.connector_table); /* LVDS */ 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, @@ -1383,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(rdev, RADEON_GPIO_VGA_DDC); + hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_CRT2_SUPPORT, @@ -1393,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, @@ -1403,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(rdev, RADEON_GPIO_DVI_DDC); + hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_LCD1_SUPPORT, @@ -1417,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(rdev, RADEON_GPIO_VGA_DDC); + hpd.hpd = RADEON_HPD_2; /* ??? */ radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_DFP2_SUPPORT, @@ -1435,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, @@ -1445,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(rdev, RADEON_GPIO_DVI_DDC); + hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_LCD1_SUPPORT, @@ -1459,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(rdev, RADEON_GPIO_VGA_DDC); + hpd.hpd = RADEON_HPD_1; /* ??? */ radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_DFP1_SUPPORT, @@ -1476,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, @@ -1486,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(rdev, RADEON_GPIO_DVI_DDC); + hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_LCD1_SUPPORT, @@ -1500,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(rdev, RADEON_GPIO_VGA_DDC); + hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_CRT1_SUPPORT, @@ -1510,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, @@ -1520,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(rdev, RADEON_GPIO_CRT2_DDC); + hpd.hpd = RADEON_HPD_2; /* ??? */ radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_DFP2_SUPPORT, @@ -1542,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, @@ -1552,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(rdev, RADEON_GPIO_CRT2_DDC); + hpd.hpd = RADEON_HPD_1; /* ??? */ radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_DFP1_SUPPORT, @@ -1573,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, @@ -1583,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(rdev, RADEON_GPIO_MONID); + hpd.hpd = RADEON_HPD_1; /* ??? */ radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_DFP1_SUPPORT, @@ -1597,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(rdev, RADEON_GPIO_DVI_DDC); + hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_CRT2_SUPPORT, @@ -1607,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, @@ -1617,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(rdev, RADEON_GPIO_VGA_DDC); + hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_CRT1_SUPPORT, @@ -1631,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(rdev, RADEON_GPIO_CRT2_DDC); + hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, ATOM_DEVICE_CRT2_SUPPORT, @@ -1641,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, @@ -1651,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", @@ -1668,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; @@ -1792,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; @@ -1830,8 +1899,22 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) 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) { @@ -1848,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) { @@ -1874,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; @@ -1920,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) { @@ -1938,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: @@ -1953,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", @@ -1980,13 +2068,15 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) ATOM_DEVICE_DFP1_SUPPORT); 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); @@ -1998,12 +2088,14 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) 1), ATOM_DEVICE_CRT1_SUPPORT); 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; @@ -2098,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); } } @@ -2114,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, @@ -2124,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); } } } diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 56384721360..7328d1528a8 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -989,7 +989,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; @@ -1029,6 +1030,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); @@ -1186,7 +1188,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; @@ -1216,6 +1219,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); diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 62c929e5b08..d4f4fb1c54c 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -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, diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index a2633628dbb..61b90343f79 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -347,6 +347,29 @@ struct radeon_connector_atom_dig { 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 { struct drm_connector base; uint32_t connector_id; @@ -361,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 { -- cgit v1.2.3 From b500f68045058454549f5f8553110ef086d8d06b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 3 Dec 2009 13:08:53 -0500 Subject: drm/radeon/kms: add regs and irq tracking bits for hpd Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600d.h | 54 ++++++++++++++++- drivers/gpu/drm/radeon/radeon.h | 2 + drivers/gpu/drm/radeon/radeon_reg.h | 9 +++ drivers/gpu/drm/radeon/rs600d.h | 112 +++++++++++++++++++++++++++++------- 4 files changed, 154 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 61ccde5637d..05894edadab 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -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 */ diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index f3deb4982b2..eafe5fad38b 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -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; }; diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index b8116401ffa..6d0a009dd4a 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -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) diff --git a/drivers/gpu/drm/radeon/rs600d.h b/drivers/gpu/drm/radeon/rs600d.h index 81308924859..c1c8f5885cb 100644 --- a/drivers/gpu/drm/radeon/rs600d.h +++ b/drivers/gpu/drm/radeon/rs600d.h @@ -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 -- cgit v1.2.3 From 05a05c506f52041daa511f4899b63d21c9457474 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 4 Dec 2009 14:53:41 -0500 Subject: drm/radeon/kms: add hpd support for r1xx-r4xx asics This just adds the functionality, it's not hooked up yet. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 106 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 109096802e6..2b534c528aa 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -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); @@ -213,6 +309,12 @@ 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) { + DRM_INFO("HPD1\n"); + } + if (status & RADEON_FP2_DETECT_STAT) { + DRM_INFO("HPD2\n"); + } status = r100_irq_ack(rdev); } if (rdev->msi_enabled) { -- cgit v1.2.3 From dcfdd4083509f9c46b1e92c58c062d50da50580e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 4 Dec 2009 15:04:19 -0500 Subject: drm/radeon/kms: add hpd support for r5xx/rs600/rs690/rs740 asics This just adds the functionality, it's not hooked up yet. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/rs600.c | 130 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 84b26376027..6364ba1d415 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -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; } @@ -278,6 +402,12 @@ 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)) { + DRM_INFO("HPD1\n"); + } + if (G_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(r500_disp_int)) { + DRM_INFO("HPD2\n"); + } status = rs600_irq_ack(rdev, &r500_disp_int); } if (rdev->msi_enabled) { -- cgit v1.2.3 From e0df1ac5c2cf346f4cc335025734978a4d747aa0 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 4 Dec 2009 15:12:21 -0500 Subject: drm/radeon/kms: add hpd support for r6xx/r7xx/rs780/rs880 asics This just adds the functionality, it's not hooked up yet. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 508 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 485 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 94e7fd2f59e..f6068960208 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -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 (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) + 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,7 +2672,7 @@ 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; DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr); @@ -2267,11 +2690,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 +2740,49 @@ 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; + DRM_INFO("IH: HPD1\n"); + } + break; + case 1: + if (disp_int & DC_HPD2_INTERRUPT) { + disp_int &= ~DC_HPD2_INTERRUPT; + DRM_INFO("IH: HPD2\n"); + } + break; + case 4: + if (disp_int_cont & DC_HPD3_INTERRUPT) { + disp_int_cont &= ~DC_HPD3_INTERRUPT; + DRM_INFO("IH: HPD3\n"); + } + break; + case 5: + if (disp_int_cont & DC_HPD4_INTERRUPT) { + disp_int_cont &= ~DC_HPD4_INTERRUPT; + DRM_INFO("IH: HPD4\n"); + } + break; + case 10: + if (disp_int_cont2 & DC_HPD5_INTERRUPT) { + disp_int_cont &= ~DC_HPD5_INTERRUPT; + DRM_INFO("IH: HPD5\n"); + } + break; + case 12: + if (disp_int_cont2 & DC_HPD6_INTERRUPT) { + disp_int_cont &= ~DC_HPD6_INTERRUPT; + DRM_INFO("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 */ -- cgit v1.2.3 From 429770b3e39999c4d025fbcb9959502adc3989d8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 4 Dec 2009 15:26:55 -0500 Subject: drm/radeon/kms: add asic callbacks for hpd Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 2 +- drivers/gpu/drm/radeon/radeon.h | 8 ++++++ drivers/gpu/drm/radeon/radeon_asic.h | 56 ++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index f6068960208..c11715fb29c 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -131,7 +131,7 @@ 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) + enum radeon_hpd_id hpd) { u32 tmp; bool connected = r600_hpd_sense(rdev, hpd); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index eafe5fad38b..29c6e0af375 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -649,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); }; /* @@ -988,6 +992,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); diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 755f50555c3..636116bedcb 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -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 -- cgit v1.2.3 From d4877cf2293f5463f531769fd12300cb3417c778 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 4 Dec 2009 16:56:37 -0500 Subject: drm/radeon/kms: enable hpd support This enabled interrupt driven hpd support for all radeon chips. Assuming the hpd pin is wired up correctly, the driver will generate uevents on digital monitor connect and disconnect and retrain DP monitors automatically. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_dp.c | 12 ++++++++++++ drivers/gpu/drm/radeon/r100.c | 9 +++++++-- drivers/gpu/drm/radeon/r600.c | 21 +++++++++++++++------ drivers/gpu/drm/radeon/radeon.h | 2 ++ drivers/gpu/drm/radeon/radeon_connectors.c | 20 ++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_device.c | 9 +++++++++ drivers/gpu/drm/radeon/radeon_display.c | 3 +++ drivers/gpu/drm/radeon/radeon_irq_kms.c | 21 +++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_mode.h | 2 ++ drivers/gpu/drm/radeon/rs600.c | 9 +++++++-- 10 files changed, 98 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 784ba80afcb..0d63c4436e7 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -507,6 +507,18 @@ static bool atom_dp_get_link_status(struct radeon_connector *radeon_connector, 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; diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 2b534c528aa..b7baf16c11d 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -289,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) { @@ -310,13 +311,17 @@ int r100_irq_process(struct radeon_device *rdev) drm_handle_vblank(rdev->ddev, 1); } if (status & RADEON_FP_DETECT_STAT) { - DRM_INFO("HPD1\n"); + queue_hotplug = true; + DRM_DEBUG("HPD1\n"); } if (status & RADEON_FP2_DETECT_STAT) { - DRM_INFO("HPD2\n"); + 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: diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index c11715fb29c..250ec3fe1a1 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2674,6 +2674,7 @@ int r600_irq_process(struct radeon_device *rdev) u32 last_entry = rdev->ih.ring_size - 16; 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); @@ -2745,37 +2746,43 @@ restart_ih: case 0: if (disp_int & DC_HPD1_INTERRUPT) { disp_int &= ~DC_HPD1_INTERRUPT; - DRM_INFO("IH: HPD1\n"); + queue_hotplug = true; + DRM_DEBUG("IH: HPD1\n"); } break; case 1: if (disp_int & DC_HPD2_INTERRUPT) { disp_int &= ~DC_HPD2_INTERRUPT; - DRM_INFO("IH: HPD2\n"); + queue_hotplug = true; + DRM_DEBUG("IH: HPD2\n"); } break; case 4: if (disp_int_cont & DC_HPD3_INTERRUPT) { disp_int_cont &= ~DC_HPD3_INTERRUPT; - DRM_INFO("IH: HPD3\n"); + queue_hotplug = true; + DRM_DEBUG("IH: HPD3\n"); } break; case 5: if (disp_int_cont & DC_HPD4_INTERRUPT) { disp_int_cont &= ~DC_HPD4_INTERRUPT; - DRM_INFO("IH: HPD4\n"); + queue_hotplug = true; + DRM_DEBUG("IH: HPD4\n"); } break; case 10: if (disp_int_cont2 & DC_HPD5_INTERRUPT) { disp_int_cont &= ~DC_HPD5_INTERRUPT; - DRM_INFO("IH: HPD5\n"); + queue_hotplug = true; + DRM_DEBUG("IH: HPD5\n"); } break; case 12: if (disp_int_cont2 & DC_HPD6_INTERRUPT) { disp_int_cont &= ~DC_HPD6_INTERRUPT; - DRM_INFO("IH: HPD6\n"); + queue_hotplug = true; + DRM_DEBUG("IH: HPD6\n"); } break; default: @@ -2807,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); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 29c6e0af375..a15cf9ceb9a 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -809,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, diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 7328d1528a8..cfa2ebb259f 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -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; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 60ee6a8b4f7..7e55647f118 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -570,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) { @@ -643,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; @@ -689,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); @@ -723,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; diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index d4f4fb1c54c..c115f2e442e 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -741,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; } @@ -748,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; } diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 26789970c5c..9223296fe37 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -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++) { diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 61b90343f79..15ec7ca18a9 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -392,6 +392,8 @@ 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, diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 6364ba1d415..fd5ab01f6ad 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -388,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) { @@ -403,13 +404,17 @@ int rs600_irq_process(struct radeon_device *rdev) 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)) { - DRM_INFO("HPD1\n"); + queue_hotplug = true; + DRM_DEBUG("HPD1\n"); } if (G_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(r500_disp_int)) { - DRM_INFO("HPD2\n"); + 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: -- cgit v1.2.3