31,18 → 31,8 |
#include "radeon.h" |
#include "atom.h" |
|
#define DISABLE_DP 0 |
|
|
extern void |
radeon_combios_connected_scratch_regs(struct drm_connector *connector, |
struct drm_encoder *encoder, |
bool connected); |
extern void |
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; |
58,6 → 48,7 |
radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); |
|
/* if the connector is already off, don't turn it back on */ |
/* FIXME: This access isn't protected by any locks. */ |
if (connector->dpms != DRM_MODE_DPMS_ON) |
return; |
|
99,7 → 90,7 |
|
if (crtc && crtc->enabled) { |
drm_crtc_helper_set_mode(crtc, &crtc->mode, |
crtc->x, crtc->y, crtc->fb); |
crtc->x, crtc->y, crtc->primary->fb); |
} |
} |
|
110,12 → 101,13 |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
struct radeon_connector_atom_dig *dig_connector; |
int bpc = 8; |
int mode_clock, max_tmds_clock; |
|
switch (connector->connector_type) { |
case DRM_MODE_CONNECTOR_DVII: |
case DRM_MODE_CONNECTOR_HDMIB: |
if (radeon_connector->use_digital) { |
if (drm_detect_hdmi_monitor(radeon_connector->edid)) { |
if (drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { |
if (connector->display_info.bpc) |
bpc = connector->display_info.bpc; |
} |
123,7 → 115,7 |
break; |
case DRM_MODE_CONNECTOR_DVID: |
case DRM_MODE_CONNECTOR_HDMIA: |
if (drm_detect_hdmi_monitor(radeon_connector->edid)) { |
if (drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { |
if (connector->display_info.bpc) |
bpc = connector->display_info.bpc; |
} |
132,7 → 124,7 |
dig_connector = radeon_connector->con_priv; |
if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || |
(dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) || |
drm_detect_hdmi_monitor(radeon_connector->edid)) { |
drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { |
if (connector->display_info.bpc) |
bpc = connector->display_info.bpc; |
} |
155,6 → 147,73 |
} |
break; |
} |
|
if (drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { |
/* hdmi deep color only implemented on DCE4+ */ |
if ((bpc > 8) && !ASIC_IS_DCE4(rdev)) { |
DRM_DEBUG("%s: HDMI deep color %d bpc unsupported. Using 8 bpc.\n", |
connector->name, bpc); |
bpc = 8; |
} |
|
/* |
* Pre DCE-8 hw can't handle > 12 bpc, and more than 12 bpc doesn't make |
* much sense without support for > 12 bpc framebuffers. RGB 4:4:4 at |
* 12 bpc is always supported on hdmi deep color sinks, as this is |
* required by the HDMI-1.3 spec. Clamp to a safe 12 bpc maximum. |
*/ |
if (bpc > 12) { |
DRM_DEBUG("%s: HDMI deep color %d bpc unsupported. Using 12 bpc.\n", |
connector->name, bpc); |
bpc = 12; |
} |
|
/* Any defined maximum tmds clock limit we must not exceed? */ |
if (connector->max_tmds_clock > 0) { |
/* mode_clock is clock in kHz for mode to be modeset on this connector */ |
mode_clock = radeon_connector->pixelclock_for_modeset; |
|
/* Maximum allowable input clock in kHz */ |
max_tmds_clock = connector->max_tmds_clock * 1000; |
|
DRM_DEBUG("%s: hdmi mode dotclock %d kHz, max tmds input clock %d kHz.\n", |
connector->name, mode_clock, max_tmds_clock); |
|
/* Check if bpc is within clock limit. Try to degrade gracefully otherwise */ |
if ((bpc == 12) && (mode_clock * 3/2 > max_tmds_clock)) { |
if ((connector->display_info.edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) && |
(mode_clock * 5/4 <= max_tmds_clock)) |
bpc = 10; |
else |
bpc = 8; |
|
DRM_DEBUG("%s: HDMI deep color 12 bpc exceeds max tmds clock. Using %d bpc.\n", |
connector->name, bpc); |
} |
|
if ((bpc == 10) && (mode_clock * 5/4 > max_tmds_clock)) { |
bpc = 8; |
DRM_DEBUG("%s: HDMI deep color 10 bpc exceeds max tmds clock. Using %d bpc.\n", |
connector->name, bpc); |
} |
} |
else if (bpc > 8) { |
/* max_tmds_clock missing, but hdmi spec mandates it for deep color. */ |
DRM_DEBUG("%s: Required max tmds clock for HDMI deep color missing. Using 8 bpc.\n", |
connector->name); |
bpc = 8; |
} |
} |
|
if ((radeon_deep_color == 0) && (bpc > 8)) { |
DRM_DEBUG("%s: Deep color disabled. Set radeon module param deep_color=1 to enable.\n", |
connector->name); |
bpc = 8; |
} |
|
DRM_DEBUG("%s: Display bpc=%d, returned bpc=%d\n", |
connector->name, connector->display_info.bpc, bpc); |
|
return bpc; |
} |
|
166,7 → 225,6 |
struct drm_encoder *best_encoder = NULL; |
struct drm_encoder *encoder = NULL; |
struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; |
struct drm_mode_object *obj; |
bool connected; |
int i; |
|
176,14 → 234,11 |
if (connector->encoder_ids[i] == 0) |
break; |
|
obj = drm_mode_object_find(connector->dev, |
connector->encoder_ids[i], |
DRM_MODE_OBJECT_ENCODER); |
if (!obj) |
encoder = drm_encoder_find(connector->dev, |
connector->encoder_ids[i]); |
if (!encoder) |
continue; |
|
encoder = obj_to_encoder(obj); |
|
if ((encoder == best_encoder) && (status == connector_status_connected)) |
connected = true; |
else |
199,7 → 254,6 |
|
static struct drm_encoder *radeon_find_encoder(struct drm_connector *connector, int encoder_type) |
{ |
struct drm_mode_object *obj; |
struct drm_encoder *encoder; |
int i; |
|
207,11 → 261,10 |
if (connector->encoder_ids[i] == 0) |
break; |
|
obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER); |
if (!obj) |
encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]); |
if (!encoder) |
continue; |
|
encoder = obj_to_encoder(obj); |
if (encoder->encoder_type == encoder_type) |
return encoder; |
} |
218,22 → 271,123 |
return NULL; |
} |
|
struct edid *radeon_connector_edid(struct drm_connector *connector) |
{ |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
struct drm_property_blob *edid_blob = connector->edid_blob_ptr; |
|
if (radeon_connector->edid) { |
return radeon_connector->edid; |
} else if (edid_blob) { |
struct edid *edid = kmemdup(edid_blob->data, edid_blob->length, GFP_KERNEL); |
if (edid) |
radeon_connector->edid = edid; |
} |
return radeon_connector->edid; |
} |
|
static void radeon_connector_get_edid(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->edid) |
return; |
|
/* on hw with routers, select right port */ |
if (radeon_connector->router.ddc_valid) |
radeon_router_select_ddc_port(radeon_connector); |
|
if ((radeon_connector_encoder_get_dp_bridge_encoder_id(connector) != |
ENCODER_OBJECT_ID_NONE) && |
radeon_connector->ddc_bus->has_aux) { |
radeon_connector->edid = drm_get_edid(connector, |
&radeon_connector->ddc_bus->aux.ddc); |
} else if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) || |
(connector->connector_type == DRM_MODE_CONNECTOR_eDP)) { |
struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; |
|
if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT || |
dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && |
radeon_connector->ddc_bus->has_aux) |
radeon_connector->edid = drm_get_edid(&radeon_connector->base, |
&radeon_connector->ddc_bus->aux.ddc); |
else if (radeon_connector->ddc_bus) |
radeon_connector->edid = drm_get_edid(&radeon_connector->base, |
&radeon_connector->ddc_bus->adapter); |
} else if (radeon_connector->ddc_bus) { |
radeon_connector->edid = drm_get_edid(&radeon_connector->base, |
&radeon_connector->ddc_bus->adapter); |
} |
|
if (!radeon_connector->edid) { |
if (rdev->is_atom_bios) { |
/* some laptops provide a hardcoded edid in rom for LCDs */ |
if (((connector->connector_type == DRM_MODE_CONNECTOR_LVDS) || |
(connector->connector_type == DRM_MODE_CONNECTOR_eDP))) |
radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev); |
} else { |
/* some servers provide a hardcoded edid in rom for KVMs */ |
radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev); |
} |
} |
} |
|
static void radeon_connector_free_edid(struct drm_connector *connector) |
{ |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
|
if (radeon_connector->edid) { |
kfree(radeon_connector->edid); |
radeon_connector->edid = NULL; |
} |
} |
|
static int radeon_ddc_get_modes(struct drm_connector *connector) |
{ |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
int ret; |
|
if (radeon_connector->edid) { |
drm_mode_connector_update_edid_property(connector, radeon_connector->edid); |
ret = drm_add_edid_modes(connector, radeon_connector->edid); |
drm_edid_to_eld(connector, radeon_connector->edid); |
return ret; |
} |
drm_mode_connector_update_edid_property(connector, NULL); |
return 0; |
} |
|
static struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector) |
{ |
int enc_id = connector->encoder_ids[0]; |
struct drm_mode_object *obj; |
struct drm_encoder *encoder; |
|
/* pick the encoder ids */ |
if (enc_id) { |
obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER); |
if (!obj) |
if (enc_id) |
return drm_encoder_find(connector->dev, enc_id); |
return NULL; |
encoder = obj_to_encoder(obj); |
return encoder; |
} |
return NULL; |
|
static void radeon_get_native_mode(struct drm_connector *connector) |
{ |
struct drm_encoder *encoder = radeon_best_single_encoder(connector); |
struct radeon_encoder *radeon_encoder; |
|
if (encoder == NULL) |
return; |
|
radeon_encoder = to_radeon_encoder(encoder); |
|
if (!list_empty(&connector->probed_modes)) { |
struct drm_display_mode *preferred_mode = |
list_first_entry(&connector->probed_modes, |
struct drm_display_mode, head); |
|
radeon_encoder->native_mode = *preferred_mode; |
} else { |
radeon_encoder->native_mode.clock = 0; |
} |
} |
|
/* |
* radeon_connector_analog_encoder_conflict_solve |
270,13 → 424,17 |
continue; |
|
if (priority == true) { |
DRM_DEBUG_KMS("1: conflicting encoders switching off %s\n", drm_get_connector_name(conflict)); |
DRM_DEBUG_KMS("in favor of %s\n", drm_get_connector_name(connector)); |
DRM_DEBUG_KMS("1: conflicting encoders switching off %s\n", |
conflict->name); |
DRM_DEBUG_KMS("in favor of %s\n", |
connector->name); |
conflict->status = connector_status_disconnected; |
radeon_connector_update_scratch_regs(conflict, connector_status_disconnected); |
} else { |
DRM_DEBUG_KMS("2: conflicting encoders switching off %s\n", drm_get_connector_name(connector)); |
DRM_DEBUG_KMS("in favor of %s\n", drm_get_connector_name(conflict)); |
DRM_DEBUG_KMS("2: conflicting encoders switching off %s\n", |
connector->name); |
DRM_DEBUG_KMS("in favor of %s\n", |
conflict->name); |
current_status = connector_status_disconnected; |
} |
break; |
399,6 → 557,36 |
} |
} |
|
if (property == rdev->mode_info.audio_property) { |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
/* need to find digital encoder on connector */ |
encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS); |
if (!encoder) |
return 0; |
|
radeon_encoder = to_radeon_encoder(encoder); |
|
if (radeon_connector->audio != val) { |
radeon_connector->audio = val; |
radeon_property_change_mode(&radeon_encoder->base); |
} |
} |
|
if (property == rdev->mode_info.dither_property) { |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
/* need to find digital encoder on connector */ |
encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS); |
if (!encoder) |
return 0; |
|
radeon_encoder = to_radeon_encoder(encoder); |
|
if (radeon_connector->dither != val) { |
radeon_connector->dither = val; |
radeon_property_change_mode(&radeon_encoder->base); |
} |
} |
|
if (property == rdev->mode_info.underscan_property) { |
/* need to find digital encoder on connector */ |
encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS); |
501,9 → 689,38 |
radeon_property_change_mode(&radeon_encoder->base); |
} |
|
if (property == dev->mode_config.scaling_mode_property) { |
enum radeon_rmx_type rmx_type; |
|
if (connector->encoder) |
radeon_encoder = to_radeon_encoder(connector->encoder); |
else { |
struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; |
radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector)); |
} |
|
switch (val) { |
default: |
case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break; |
case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break; |
case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break; |
case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break; |
} |
if (radeon_encoder->rmx_type == rmx_type) |
return 0; |
|
if ((rmx_type != DRM_MODE_SCALE_NONE) && |
(radeon_encoder->native_mode.clock == 0)) |
return 0; |
|
radeon_encoder->rmx_type = rmx_type; |
|
radeon_property_change_mode(&radeon_encoder->base); |
} |
|
return 0; |
} |
|
static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder, |
struct drm_connector *connector) |
{ |
541,13 → 758,12 |
|
static int radeon_lvds_get_modes(struct drm_connector *connector) |
{ |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
struct drm_encoder *encoder; |
int ret = 0; |
struct drm_display_mode *mode; |
|
if (radeon_connector->ddc_bus) { |
ret = radeon_ddc_get_modes(radeon_connector); |
radeon_connector_get_edid(connector); |
ret = radeon_ddc_get_modes(connector); |
if (ret > 0) { |
encoder = radeon_best_single_encoder(connector); |
if (encoder) { |
557,7 → 773,6 |
} |
return ret; |
} |
} |
|
encoder = radeon_best_single_encoder(connector); |
if (!encoder) |
626,16 → 841,9 |
} |
|
/* check for edid as well */ |
radeon_connector_get_edid(connector); |
if (radeon_connector->edid) |
ret = connector_status_connected; |
else { |
if (radeon_connector->ddc_bus) { |
radeon_connector->edid = drm_get_edid(&radeon_connector->base, |
&radeon_connector->ddc_bus->adapter); |
if (radeon_connector->edid) |
ret = connector_status_connected; |
} |
} |
/* check acpi lid status ??? */ |
|
radeon_connector_update_scratch_regs(connector, ret); |
646,10 → 854,9 |
{ |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
|
if (radeon_connector->edid) |
kfree(radeon_connector->edid); |
radeon_connector_free_edid(connector); |
kfree(radeon_connector->con_priv); |
// drm_sysfs_connector_remove(connector); |
drm_connector_unregister(connector); |
drm_connector_cleanup(connector); |
kfree(connector); |
} |
706,11 → 913,13 |
|
static int radeon_vga_get_modes(struct drm_connector *connector) |
{ |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
int ret; |
|
ret = radeon_ddc_get_modes(radeon_connector); |
radeon_connector_get_edid(connector); |
ret = radeon_ddc_get_modes(connector); |
|
radeon_get_native_mode(connector); |
|
return ret; |
} |
|
747,29 → 956,27 |
dret = radeon_ddc_probe(radeon_connector, false); |
if (dret) { |
radeon_connector->detected_by_load = false; |
if (radeon_connector->edid) { |
kfree(radeon_connector->edid); |
radeon_connector->edid = NULL; |
} |
radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); |
radeon_connector_free_edid(connector); |
radeon_connector_get_edid(connector); |
|
if (!radeon_connector->edid) { |
DRM_ERROR("%s: probed a monitor but no|invalid EDID\n", |
drm_get_connector_name(connector)); |
connector->name); |
ret = connector_status_connected; |
} else { |
radeon_connector->use_digital = !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL); |
radeon_connector->use_digital = |
!!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL); |
|
/* some oems have boards with separate digital and analog connectors |
* with a shared ddc line (often vga + hdmi) |
*/ |
if (radeon_connector->use_digital && radeon_connector->shared_ddc) { |
kfree(radeon_connector->edid); |
radeon_connector->edid = NULL; |
radeon_connector_free_edid(connector); |
ret = connector_status_disconnected; |
} else |
} else { |
ret = connector_status_connected; |
} |
} |
} else { |
|
/* if we aren't forcing don't do destructive polling */ |
778,9 → 985,8 |
* detected a monitor via load. |
*/ |
if (radeon_connector->detected_by_load) |
return connector->status; |
else |
return ret; |
ret = connector->status; |
goto out; |
} |
|
if (radeon_connector->dac_load_detect && encoder) { |
805,6 → 1011,8 |
} |
|
radeon_connector_update_scratch_regs(connector, ret); |
|
out: |
return ret; |
} |
|
861,6 → 1069,7 |
struct drm_encoder_helper_funcs *encoder_funcs; |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
enum drm_connector_status ret = connector_status_disconnected; |
int r; |
|
if (!radeon_connector->dac_load_detect) |
return ret; |
892,15 → 1101,6 |
.set_property = radeon_connector_set_property, |
}; |
|
static int radeon_dvi_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 bool radeon_check_hpd_status_unchanged(struct drm_connector *connector) |
{ |
struct drm_device *dev = connector->dev; |
941,32 → 1141,33 |
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; |
int i, r; |
enum drm_connector_status ret = connector_status_disconnected; |
bool dret = false, broken_edid = false; |
|
if (!force && radeon_check_hpd_status_unchanged(connector)) |
return connector->status; |
|
if (!force && radeon_check_hpd_status_unchanged(connector)) { |
ret = connector->status; |
goto exit; |
} |
|
if (radeon_connector->ddc_bus) |
dret = radeon_ddc_probe(radeon_connector, false); |
if (dret) { |
radeon_connector->detected_by_load = false; |
if (radeon_connector->edid) { |
kfree(radeon_connector->edid); |
radeon_connector->edid = NULL; |
} |
radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); |
radeon_connector_free_edid(connector); |
radeon_connector_get_edid(connector); |
|
if (!radeon_connector->edid) { |
DRM_ERROR("%s: probed a monitor but no|invalid EDID\n", |
drm_get_connector_name(connector)); |
connector->name); |
/* rs690 seems to have a problem with connectors not existing and always |
* return a block of 0's. If we see this just stop polling on this output */ |
if ((rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) && radeon_connector->base.null_edid_counter) { |
if ((rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) && |
radeon_connector->base.null_edid_counter) { |
ret = connector_status_disconnected; |
DRM_ERROR("%s: detected RS690 floating bus bug, stopping ddc detect\n", drm_get_connector_name(connector)); |
DRM_ERROR("%s: detected RS690 floating bus bug, stopping ddc detect\n", |
connector->name); |
radeon_connector->ddc_bus = NULL; |
} else { |
ret = connector_status_connected; |
973,18 → 1174,18 |
broken_edid = true; /* defer use_digital to later */ |
} |
} else { |
radeon_connector->use_digital = !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL); |
radeon_connector->use_digital = |
!!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL); |
|
/* some oems have boards with separate digital and analog connectors |
* with a shared ddc line (often vga + hdmi) |
*/ |
if ((!radeon_connector->use_digital) && radeon_connector->shared_ddc) { |
kfree(radeon_connector->edid); |
radeon_connector->edid = NULL; |
radeon_connector_free_edid(connector); |
ret = connector_status_disconnected; |
} else |
} else { |
ret = connector_status_connected; |
|
} |
/* This gets complicated. We have boards with VGA + HDMI with a |
* shared DDC line and we have boards with DVI-D + HDMI with a shared |
* DDC line. The latter is more complex because with DVI<->HDMI adapters |
1004,8 → 1205,7 |
if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) { |
/* hpd is our only option in this case */ |
if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) { |
kfree(radeon_connector->edid); |
radeon_connector->edid = NULL; |
radeon_connector_free_edid(connector); |
ret = connector_status_disconnected; |
} |
} |
1039,14 → 1239,11 |
if (connector->encoder_ids[i] == 0) |
break; |
|
obj = drm_mode_object_find(connector->dev, |
connector->encoder_ids[i], |
DRM_MODE_OBJECT_ENCODER); |
if (!obj) |
encoder = drm_encoder_find(connector->dev, |
connector->encoder_ids[i]); |
if (!encoder) |
continue; |
|
encoder = obj_to_encoder(obj); |
|
if (encoder->encoder_type != DRM_MODE_ENCODER_DAC && |
encoder->encoder_type != DRM_MODE_ENCODER_TVDAC) |
continue; |
1098,6 → 1295,8 |
|
/* updated in get modes as well since we need to know if it's analog or digital */ |
radeon_connector_update_scratch_regs(connector, ret); |
|
exit: |
return ret; |
} |
|
1106,7 → 1305,6 |
{ |
int enc_id = connector->encoder_ids[0]; |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
struct drm_mode_object *obj; |
struct drm_encoder *encoder; |
int i; |
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { |
1113,12 → 1311,10 |
if (connector->encoder_ids[i] == 0) |
break; |
|
obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER); |
if (!obj) |
encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]); |
if (!encoder) |
continue; |
|
encoder = obj_to_encoder(obj); |
|
if (radeon_connector->use_digital == true) { |
if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS) |
return encoder; |
1133,15 → 1329,10 |
|
/* then check use digitial */ |
/* pick the first one */ |
if (enc_id) { |
obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER); |
if (!obj) |
if (enc_id) |
return drm_encoder_find(connector->dev, enc_id); |
return NULL; |
encoder = obj_to_encoder(obj); |
return encoder; |
} |
return NULL; |
} |
|
static void radeon_dvi_force(struct drm_connector *connector) |
{ |
1172,18 → 1363,16 |
(radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D) || |
(radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_B)) |
return MODE_OK; |
else if (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_A) { |
if (ASIC_IS_DCE6(rdev)) { |
else if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { |
/* HDMI 1.3+ supports max clock of 340 Mhz */ |
if (mode->clock > 340000) |
return MODE_CLOCK_HIGH; |
else |
return MODE_OK; |
} else |
} else { |
return MODE_CLOCK_HIGH; |
} else |
return MODE_CLOCK_HIGH; |
} |
} |
|
/* check against the max pixel clock */ |
if ((mode->clock / 10) > rdev->clock.max_pixel_clock) |
1193,7 → 1382,7 |
} |
|
static const struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = { |
.get_modes = radeon_dvi_get_modes, |
.get_modes = radeon_vga_get_modes, |
.mode_valid = radeon_dvi_mode_valid, |
.best_encoder = radeon_dvi_encoder, |
}; |
1207,21 → 1396,6 |
.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->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); |
1237,7 → 1411,8 |
if (!radeon_dig_connector->edp_on) |
atombios_set_edp_panel_power(connector, |
ATOM_TRANSMITTER_ACTION_POWER_ON); |
ret = radeon_ddc_get_modes(radeon_connector); |
radeon_connector_get_edid(connector); |
ret = radeon_ddc_get_modes(connector); |
if (!radeon_dig_connector->edp_on) |
atombios_set_edp_panel_power(connector, |
ATOM_TRANSMITTER_ACTION_POWER_OFF); |
1248,7 → 1423,8 |
if (encoder) |
radeon_atom_ext_encoder_setup_ddc(encoder); |
} |
ret = radeon_ddc_get_modes(radeon_connector); |
radeon_connector_get_edid(connector); |
ret = radeon_ddc_get_modes(connector); |
} |
|
if (ret > 0) { |
1281,7 → 1457,10 |
if (encoder) |
radeon_atom_ext_encoder_setup_ddc(encoder); |
} |
ret = radeon_ddc_get_modes(radeon_connector); |
radeon_connector_get_edid(connector); |
ret = radeon_ddc_get_modes(connector); |
|
radeon_get_native_mode(connector); |
} |
|
return ret; |
1289,7 → 1468,6 |
|
u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector) |
{ |
struct drm_mode_object *obj; |
struct drm_encoder *encoder; |
struct radeon_encoder *radeon_encoder; |
int i; |
1298,11 → 1476,10 |
if (connector->encoder_ids[i] == 0) |
break; |
|
obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER); |
if (!obj) |
encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]); |
if (!encoder) |
continue; |
|
encoder = obj_to_encoder(obj); |
radeon_encoder = to_radeon_encoder(encoder); |
|
switch (radeon_encoder->encoder_id) { |
1317,9 → 1494,8 |
return ENCODER_OBJECT_ID_NONE; |
} |
|
bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector) |
static bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector) |
{ |
struct drm_mode_object *obj; |
struct drm_encoder *encoder; |
struct radeon_encoder *radeon_encoder; |
int i; |
1329,11 → 1505,10 |
if (connector->encoder_ids[i] == 0) |
break; |
|
obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER); |
if (!obj) |
encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]); |
if (!encoder) |
continue; |
|
encoder = obj_to_encoder(obj); |
radeon_encoder = to_radeon_encoder(encoder); |
if (radeon_encoder->caps & ATOM_ENCODER_CAP_RECORD_HBR2) |
found = true; |
1348,7 → 1523,7 |
struct radeon_device *rdev = dev->dev_private; |
|
if (ASIC_IS_DCE5(rdev) && |
(rdev->clock.dp_extclk >= 53900) && |
(rdev->clock.default_dispclk >= 53900) && |
radeon_connector_encoder_is_hbr2(connector)) { |
return true; |
} |
1365,21 → 1540,16 |
enum drm_connector_status ret = connector_status_disconnected; |
struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; |
struct drm_encoder *encoder = radeon_best_single_encoder(connector); |
int r; |
|
|
#if DISABLE_DP |
connector->status = connector_status_disconnected; |
return connector->status; |
#endif |
if (!force && radeon_check_hpd_status_unchanged(connector)) { |
ret = connector->status; |
goto out; |
} |
|
if (!force && radeon_check_hpd_status_unchanged(connector)) |
return connector->status; |
radeon_connector_free_edid(connector); |
|
if (radeon_connector->edid) { |
kfree(radeon_connector->edid); |
radeon_connector->edid = NULL; |
} |
|
if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) || |
(connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) { |
if (encoder) { |
1429,7 → 1599,7 |
if (radeon_dp_getdpcd(radeon_connector)) |
ret = connector_status_connected; |
} else { |
/* try non-aux ddc (DP to DVI/HMDI/etc. adapter) */ |
/* try non-aux ddc (DP to DVI/HDMI/etc. adapter) */ |
if (radeon_ddc_probe(radeon_connector, false)) |
ret = connector_status_connected; |
} |
1437,6 → 1607,7 |
} |
|
radeon_connector_update_scratch_regs(connector, ret); |
out: |
return ret; |
} |
|
1443,6 → 1614,8 |
static int radeon_dp_mode_valid(struct drm_connector *connector, |
struct drm_display_mode *mode) |
{ |
struct drm_device *dev = connector->dev; |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; |
|
1473,16 → 1646,25 |
return MODE_PANEL; |
} |
} |
return MODE_OK; |
} else { |
if ((radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || |
(radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) |
(radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) { |
return radeon_dp_mode_valid_helper(connector, mode); |
else |
return MODE_OK; |
} else { |
if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { |
/* HDMI 1.3+ supports max clock of 340 Mhz */ |
if (mode->clock > 340000) |
return MODE_CLOCK_HIGH; |
} else { |
if (mode->clock > 165000) |
return MODE_CLOCK_HIGH; |
} |
} |
} |
|
return MODE_OK; |
} |
|
static const struct drm_connector_helper_funcs radeon_dp_connector_helper_funcs = { |
.get_modes = radeon_dp_get_modes, |
.mode_valid = radeon_dp_mode_valid, |
1494,10 → 1676,28 |
.detect = radeon_dp_detect, |
.fill_modes = drm_helper_probe_single_connector_modes, |
.set_property = radeon_connector_set_property, |
.destroy = radeon_dp_connector_destroy, |
.destroy = radeon_connector_destroy, |
.force = radeon_dvi_force, |
}; |
|
static const struct drm_connector_funcs radeon_edp_connector_funcs = { |
.dpms = drm_helper_connector_dpms, |
.detect = radeon_dp_detect, |
.fill_modes = drm_helper_probe_single_connector_modes, |
.set_property = radeon_lvds_set_property, |
.destroy = radeon_connector_destroy, |
.force = radeon_dvi_force, |
}; |
|
static const struct drm_connector_funcs radeon_lvds_bridge_connector_funcs = { |
.dpms = drm_helper_connector_dpms, |
.detect = radeon_dp_detect, |
.fill_modes = drm_helper_probe_single_connector_modes, |
.set_property = radeon_lvds_set_property, |
.destroy = radeon_connector_destroy, |
.force = radeon_dvi_force, |
}; |
|
void |
radeon_add_atom_connector(struct drm_device *dev, |
uint32_t connector_id, |
1518,6 → 1718,7 |
uint32_t subpixel_order = SubPixelNone; |
bool shared_ddc = false; |
bool is_dp_bridge = false; |
bool has_aux = false; |
|
if (connector_type == DRM_MODE_CONNECTOR_Unknown) |
return; |
1589,18 → 1790,11 |
goto failed; |
radeon_dig_connector->igp_lane_info = igp_lane_info; |
radeon_connector->con_priv = radeon_dig_connector; |
drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type); |
drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs); |
if (i2c_bus->valid) { |
/* add DP i2c bus */ |
if (connector_type == DRM_MODE_CONNECTOR_eDP) |
radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch"); |
radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); |
if (radeon_connector->ddc_bus) |
has_aux = true; |
else |
radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch"); |
if (!radeon_dig_connector->dp_i2c_bus) |
DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); |
radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); |
if (!radeon_connector->ddc_bus) |
DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); |
} |
switch (connector_type) { |
1607,6 → 1801,10 |
case DRM_MODE_CONNECTOR_VGA: |
case DRM_MODE_CONNECTOR_DVIA: |
default: |
drm_connector_init(dev, &radeon_connector->base, |
&radeon_dp_connector_funcs, connector_type); |
drm_connector_helper_add(&radeon_connector->base, |
&radeon_dp_connector_helper_funcs); |
connector->interlace_allowed = true; |
connector->doublescan_allowed = true; |
radeon_connector->dac_load_detect = true; |
1613,6 → 1811,9 |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.load_detect_property, |
1); |
drm_object_attach_property(&radeon_connector->base.base, |
dev->mode_config.scaling_mode_property, |
DRM_MODE_SCALE_NONE); |
break; |
case DRM_MODE_CONNECTOR_DVII: |
case DRM_MODE_CONNECTOR_DVID: |
1619,6 → 1820,10 |
case DRM_MODE_CONNECTOR_HDMIA: |
case DRM_MODE_CONNECTOR_HDMIB: |
case DRM_MODE_CONNECTOR_DisplayPort: |
drm_connector_init(dev, &radeon_connector->base, |
&radeon_dp_connector_funcs, connector_type); |
drm_connector_helper_add(&radeon_connector->base, |
&radeon_dp_connector_helper_funcs); |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.underscan_property, |
UNDERSCAN_OFF); |
1628,6 → 1833,20 |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.underscan_vborder_property, |
0); |
|
drm_object_attach_property(&radeon_connector->base.base, |
dev->mode_config.scaling_mode_property, |
DRM_MODE_SCALE_NONE); |
|
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.dither_property, |
RADEON_FMT_DITHER_DISABLE); |
|
if (radeon_audio != 0) |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.audio_property, |
RADEON_AUDIO_AUTO); |
|
subpixel_order = SubPixelHorizontalRGB; |
connector->interlace_allowed = true; |
if (connector_type == DRM_MODE_CONNECTOR_HDMIB) |
1643,6 → 1862,10 |
break; |
case DRM_MODE_CONNECTOR_LVDS: |
case DRM_MODE_CONNECTOR_eDP: |
drm_connector_init(dev, &radeon_connector->base, |
&radeon_lvds_bridge_connector_funcs, connector_type); |
drm_connector_helper_add(&radeon_connector->base, |
&radeon_dp_connector_helper_funcs); |
drm_object_attach_property(&radeon_connector->base.base, |
dev->mode_config.scaling_mode_property, |
DRM_MODE_SCALE_FULLSCREEN); |
1665,6 → 1888,10 |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.load_detect_property, |
1); |
if (ASIC_IS_AVIVO(rdev)) |
drm_object_attach_property(&radeon_connector->base.base, |
dev->mode_config.scaling_mode_property, |
DRM_MODE_SCALE_NONE); |
/* no HPD on analog connectors */ |
radeon_connector->hpd.hpd = RADEON_HPD_NONE; |
connector->polled = DRM_CONNECTOR_POLL_CONNECT; |
1683,6 → 1910,10 |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.load_detect_property, |
1); |
if (ASIC_IS_AVIVO(rdev)) |
drm_object_attach_property(&radeon_connector->base.base, |
dev->mode_config.scaling_mode_property, |
DRM_MODE_SCALE_NONE); |
/* no HPD on analog connectors */ |
radeon_connector->hpd.hpd = RADEON_HPD_NONE; |
connector->interlace_allowed = true; |
1716,7 → 1947,18 |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.underscan_vborder_property, |
0); |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.dither_property, |
RADEON_FMT_DITHER_DISABLE); |
drm_object_attach_property(&radeon_connector->base.base, |
dev->mode_config.scaling_mode_property, |
DRM_MODE_SCALE_NONE); |
} |
if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) { |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.audio_property, |
RADEON_AUDIO_AUTO); |
} |
if (connector_type == DRM_MODE_CONNECTOR_DVII) { |
radeon_connector->dac_load_detect = true; |
drm_object_attach_property(&radeon_connector->base.base, |
1756,7 → 1998,18 |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.underscan_vborder_property, |
0); |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.dither_property, |
RADEON_FMT_DITHER_DISABLE); |
drm_object_attach_property(&radeon_connector->base.base, |
dev->mode_config.scaling_mode_property, |
DRM_MODE_SCALE_NONE); |
} |
if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) { |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.audio_property, |
RADEON_AUDIO_AUTO); |
} |
subpixel_order = SubPixelHorizontalRGB; |
connector->interlace_allowed = true; |
if (connector_type == DRM_MODE_CONNECTOR_HDMIB) |
1773,12 → 2026,10 |
drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type); |
drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs); |
if (i2c_bus->valid) { |
/* add DP i2c bus */ |
radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch"); |
if (!radeon_dig_connector->dp_i2c_bus) |
DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); |
radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); |
if (!radeon_connector->ddc_bus) |
if (radeon_connector->ddc_bus) |
has_aux = true; |
else |
DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); |
} |
subpixel_order = SubPixelHorizontalRGB; |
1795,7 → 2046,18 |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.underscan_vborder_property, |
0); |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.dither_property, |
RADEON_FMT_DITHER_DISABLE); |
drm_object_attach_property(&radeon_connector->base.base, |
dev->mode_config.scaling_mode_property, |
DRM_MODE_SCALE_NONE); |
} |
if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) { |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.audio_property, |
RADEON_AUDIO_AUTO); |
} |
connector->interlace_allowed = true; |
/* in theory with a DP to VGA converter... */ |
connector->doublescan_allowed = false; |
1806,15 → 2068,13 |
goto failed; |
radeon_dig_connector->igp_lane_info = igp_lane_info; |
radeon_connector->con_priv = radeon_dig_connector; |
drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type); |
drm_connector_init(dev, &radeon_connector->base, &radeon_edp_connector_funcs, connector_type); |
drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs); |
if (i2c_bus->valid) { |
/* add DP i2c bus */ |
radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch"); |
if (!radeon_dig_connector->dp_i2c_bus) |
DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); |
radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); |
if (!radeon_connector->ddc_bus) |
if (radeon_connector->ddc_bus) |
has_aux = true; |
else |
DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); |
} |
drm_object_attach_property(&radeon_connector->base.base, |
1871,7 → 2131,11 |
connector->polled = DRM_CONNECTOR_POLL_HPD; |
|
connector->display_info.subpixel_order = subpixel_order; |
drm_sysfs_connector_add(connector); |
drm_connector_register(connector); |
|
if (has_aux) |
radeon_dp_aux_init(radeon_connector); |
|
return; |
|
failed: |
2028,5 → 2292,5 |
} else |
connector->polled = DRM_CONNECTOR_POLL_HPD; |
connector->display_info.subpixel_order = subpixel_order; |
drm_sysfs_connector_add(connector); |
drm_connector_register(connector); |
} |