27,12 → 27,24 |
#include <drm/drm_edid.h> |
#include <drm/drm_crtc_helper.h> |
#include <drm/drm_fb_helper.h> |
#include <drm/drm_dp_mst_helper.h> |
#include <drm/radeon_drm.h> |
#include "radeon.h" |
#include "radeon_audio.h" |
#include "atom.h" |
|
#include <linux/pm_runtime.h> |
|
static int radeon_dp_handle_hpd(struct drm_connector *connector) |
{ |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
int ret; |
|
ret = radeon_dp_mst_check_status(radeon_connector); |
if (ret == -EINVAL) |
return 1; |
return 0; |
} |
void radeon_connector_hotplug(struct drm_connector *connector) |
{ |
struct drm_device *dev = connector->dev; |
39,6 → 51,17 |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
|
if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { |
struct radeon_connector_atom_dig *dig_connector = |
radeon_connector->con_priv; |
|
if (radeon_connector->is_mst_connector) |
return; |
if (dig_connector->is_mst) { |
radeon_dp_handle_hpd(connector); |
return; |
} |
} |
/* bail if the connector does not have hpd pin, e.g., |
* VGA, TV, etc. |
*/ |
72,6 → 95,11 |
if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) { |
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); |
} else if (radeon_dp_needs_link_train(radeon_connector)) { |
/* Don't try to start link training before we |
* have the dpcd */ |
if (!radeon_dp_getdpcd(radeon_connector)) |
return; |
|
/* set it to OFF so that drm_helper_connector_dpms() |
* won't return immediately since the current state |
* is ON at this point. |
134,7 → 162,7 |
if (connector->display_info.bpc) |
bpc = connector->display_info.bpc; |
else if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) { |
struct drm_connector_helper_funcs *connector_funcs = |
const struct drm_connector_helper_funcs *connector_funcs = |
connector->helper_private; |
struct drm_encoder *encoder = connector_funcs->best_encoder(connector); |
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
224,7 → 252,7 |
struct radeon_device *rdev = dev->dev_private; |
struct drm_encoder *best_encoder = NULL; |
struct drm_encoder *encoder = NULL; |
struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; |
const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; |
bool connected; |
int i; |
|
701,7 → 729,7 |
if (connector->encoder) |
radeon_encoder = to_radeon_encoder(connector->encoder); |
else { |
struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; |
const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; |
radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector)); |
} |
|
724,9 → 752,33 |
radeon_property_change_mode(&radeon_encoder->base); |
} |
|
if (property == rdev->mode_info.output_csc_property) { |
if (connector->encoder) |
radeon_encoder = to_radeon_encoder(connector->encoder); |
else { |
const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; |
radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector)); |
} |
|
if (radeon_encoder->output_csc == val) |
return 0; |
|
radeon_encoder->output_csc = val; |
|
if (connector->encoder->crtc) { |
struct drm_crtc *crtc = connector->encoder->crtc; |
const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
|
radeon_crtc->output_csc = radeon_encoder->output_csc; |
|
(*crtc_funcs->load_lut)(crtc); |
} |
} |
|
return 0; |
} |
|
static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder, |
struct drm_connector *connector) |
{ |
845,7 → 897,11 |
/* check if panel is valid */ |
if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240) |
ret = connector_status_connected; |
|
/* don't fetch the edid from the vbios if ddc fails and runpm is |
* enabled so we report disconnected. |
*/ |
if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0)) |
ret = connector_status_disconnected; |
} |
|
/* check for edid as well */ |
884,7 → 940,7 |
if (connector->encoder) |
radeon_encoder = to_radeon_encoder(connector->encoder); |
else { |
struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; |
const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; |
radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector)); |
} |
|
952,7 → 1008,7 |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
struct drm_encoder *encoder; |
struct drm_encoder_helper_funcs *encoder_funcs; |
const struct drm_encoder_helper_funcs *encoder_funcs; |
bool dret = false; |
enum drm_connector_status ret = connector_status_disconnected; |
|
1074,7 → 1130,7 |
radeon_tv_detect(struct drm_connector *connector, bool force) |
{ |
struct drm_encoder *encoder; |
struct drm_encoder_helper_funcs *encoder_funcs; |
const 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; |
1148,7 → 1204,7 |
struct radeon_device *rdev = dev->dev_private; |
struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
struct drm_encoder *encoder = NULL; |
struct drm_encoder_helper_funcs *encoder_funcs; |
const struct drm_encoder_helper_funcs *encoder_funcs; |
int i, r; |
enum drm_connector_status ret = connector_status_disconnected; |
bool dret = false, broken_edid = false; |
1159,8 → 1215,9 |
goto exit; |
} |
|
if (radeon_connector->ddc_bus) |
if (radeon_connector->ddc_bus) { |
dret = radeon_ddc_probe(radeon_connector, false); |
} |
if (dret) { |
radeon_connector->detected_by_load = false; |
radeon_connector_free_edid(connector); |
1304,6 → 1361,17 |
/* updated in get modes as well since we need to know if it's analog or digital */ |
radeon_connector_update_scratch_regs(connector, ret); |
|
if ((radeon_audio != 0) && radeon_connector->use_digital) { |
const struct drm_connector_helper_funcs *connector_funcs = |
connector->helper_private; |
|
encoder = connector_funcs->best_encoder(connector); |
if (encoder && (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)) { |
radeon_connector_get_edid(connector); |
radeon_audio_detect(connector, encoder, ret); |
} |
} |
|
exit: |
return ret; |
} |
1550,6 → 1618,8 |
struct drm_encoder *encoder = radeon_best_single_encoder(connector); |
int r; |
|
if (radeon_dig_connector->is_mst) |
return connector_status_disconnected; |
|
if (!force && radeon_check_hpd_status_unchanged(connector)) { |
ret = connector->status; |
1567,6 → 1637,11 |
/* check if panel is valid */ |
if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240) |
ret = connector_status_connected; |
/* don't fetch the edid from the vbios if ddc fails and runpm is |
* enabled so we report disconnected. |
*/ |
if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0)) |
ret = connector_status_disconnected; |
} |
/* eDP is always DP */ |
radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT; |
1592,7 → 1667,7 |
if (radeon_ddc_probe(radeon_connector, true)) /* try DDC */ |
ret = connector_status_connected; |
else if (radeon_connector->dac_load_detect) { /* try load detection */ |
struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; |
const struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; |
ret = encoder_funcs->detect(encoder, connector); |
} |
} |
1600,12 → 1675,21 |
radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector); |
if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) { |
ret = connector_status_connected; |
if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) |
if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { |
radeon_dp_getdpcd(radeon_connector); |
r = radeon_dp_mst_probe(radeon_connector); |
if (r == 1) |
ret = connector_status_disconnected; |
} |
} else { |
if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { |
if (radeon_dp_getdpcd(radeon_connector)) |
if (radeon_dp_getdpcd(radeon_connector)) { |
r = radeon_dp_mst_probe(radeon_connector); |
if (r == 1) |
ret = connector_status_disconnected; |
else |
ret = connector_status_connected; |
} |
} else { |
/* try non-aux ddc (DP to DVI/HDMI/etc. adapter) */ |
if (radeon_ddc_probe(radeon_connector, false)) |
1615,6 → 1699,12 |
} |
|
radeon_connector_update_scratch_regs(connector, ret); |
|
if ((radeon_audio != 0) && encoder) { |
radeon_connector_get_edid(connector); |
radeon_audio_detect(connector, encoder, ret); |
} |
|
out: |
return ret; |
} |
1822,6 → 1912,10 |
drm_object_attach_property(&radeon_connector->base.base, |
dev->mode_config.scaling_mode_property, |
DRM_MODE_SCALE_NONE); |
if (ASIC_IS_DCE5(rdev)) |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.output_csc_property, |
RADEON_OUTPUT_CSC_BYPASS); |
break; |
case DRM_MODE_CONNECTOR_DVII: |
case DRM_MODE_CONNECTOR_DVID: |
1854,6 → 1948,10 |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.audio_property, |
RADEON_AUDIO_AUTO); |
if (ASIC_IS_DCE5(rdev)) |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.output_csc_property, |
RADEON_OUTPUT_CSC_BYPASS); |
|
subpixel_order = SubPixelHorizontalRGB; |
connector->interlace_allowed = true; |
1900,6 → 1998,10 |
drm_object_attach_property(&radeon_connector->base.base, |
dev->mode_config.scaling_mode_property, |
DRM_MODE_SCALE_NONE); |
if (ASIC_IS_DCE5(rdev)) |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.output_csc_property, |
RADEON_OUTPUT_CSC_BYPASS); |
/* no HPD on analog connectors */ |
radeon_connector->hpd.hpd = RADEON_HPD_NONE; |
connector->polled = DRM_CONNECTOR_POLL_CONNECT; |
1922,6 → 2024,10 |
drm_object_attach_property(&radeon_connector->base.base, |
dev->mode_config.scaling_mode_property, |
DRM_MODE_SCALE_NONE); |
if (ASIC_IS_DCE5(rdev)) |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.output_csc_property, |
RADEON_OUTPUT_CSC_BYPASS); |
/* no HPD on analog connectors */ |
radeon_connector->hpd.hpd = RADEON_HPD_NONE; |
connector->interlace_allowed = true; |
1973,6 → 2079,10 |
rdev->mode_info.load_detect_property, |
1); |
} |
if (ASIC_IS_DCE5(rdev)) |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.output_csc_property, |
RADEON_OUTPUT_CSC_BYPASS); |
connector->interlace_allowed = true; |
if (connector_type == DRM_MODE_CONNECTOR_DVII) |
connector->doublescan_allowed = true; |
2018,6 → 2128,10 |
rdev->mode_info.audio_property, |
RADEON_AUDIO_AUTO); |
} |
if (ASIC_IS_DCE5(rdev)) |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.output_csc_property, |
RADEON_OUTPUT_CSC_BYPASS); |
subpixel_order = SubPixelHorizontalRGB; |
connector->interlace_allowed = true; |
if (connector_type == DRM_MODE_CONNECTOR_HDMIB) |
2066,6 → 2180,10 |
rdev->mode_info.audio_property, |
RADEON_AUDIO_AUTO); |
} |
if (ASIC_IS_DCE5(rdev)) |
drm_object_attach_property(&radeon_connector->base.base, |
rdev->mode_info.output_csc_property, |
RADEON_OUTPUT_CSC_BYPASS); |
connector->interlace_allowed = true; |
/* in theory with a DP to VGA converter... */ |
connector->doublescan_allowed = false; |
2302,3 → 2420,27 |
connector->display_info.subpixel_order = subpixel_order; |
drm_connector_register(connector); |
} |
|
void radeon_setup_mst_connector(struct drm_device *dev) |
{ |
struct radeon_device *rdev = dev->dev_private; |
struct drm_connector *connector; |
struct radeon_connector *radeon_connector; |
|
if (!ASIC_IS_DCE5(rdev)) |
return; |
|
if (radeon_mst == 0) |
return; |
|
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
int ret; |
|
radeon_connector = to_radeon_connector(connector); |
|
if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) |
continue; |
|
ret = radeon_dp_mst_init(radeon_connector); |
} |
} |