Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
2
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
1135035
Breadcrumbs
linux
/
drivers
/
gpu
/
drm
/
radeon
/
radeon_dp_mst.c
Copy path
Blame
Blame
Latest commit
History
History
792 lines (637 loc) · 23.1 KB
Breadcrumbs
linux
/
drivers
/
gpu
/
drm
/
radeon
/
radeon_dp_mst.c
Top
File metadata and controls
Code
Blame
792 lines (637 loc) · 23.1 KB
Raw
#include <drm/drmP.h> #include <drm/drm_dp_mst_helper.h> #include <drm/drm_fb_helper.h> #include "radeon.h" #include "atom.h" #include "ni_reg.h" static struct radeon_encoder *radeon_dp_create_fake_mst_encoder(struct radeon_connector *connector); static int radeon_atom_set_enc_offset(int id) { static const int offsets[] = { EVERGREEN_CRTC0_REGISTER_OFFSET, EVERGREEN_CRTC1_REGISTER_OFFSET, EVERGREEN_CRTC2_REGISTER_OFFSET, EVERGREEN_CRTC3_REGISTER_OFFSET, EVERGREEN_CRTC4_REGISTER_OFFSET, EVERGREEN_CRTC5_REGISTER_OFFSET, 0x13830 - 0x7030 }; return offsets[id]; } static int radeon_dp_mst_set_be_cntl(struct radeon_encoder *primary, struct radeon_encoder_mst *mst_enc, enum radeon_hpd_id hpd, bool enable) { struct drm_device *dev = primary->base.dev; struct radeon_device *rdev = dev->dev_private; uint32_t reg; int retries = 0; uint32_t temp; reg = RREG32(NI_DIG_BE_CNTL + primary->offset); /* set MST mode */ reg &= ~NI_DIG_FE_DIG_MODE(7); reg |= NI_DIG_FE_DIG_MODE(NI_DIG_MODE_DP_MST); if (enable) reg |= NI_DIG_FE_SOURCE_SELECT(1 << mst_enc->fe); else reg &= ~NI_DIG_FE_SOURCE_SELECT(1 << mst_enc->fe); reg |= NI_DIG_HPD_SELECT(hpd); DRM_DEBUG_KMS("writing 0x%08x 0x%08x\n", NI_DIG_BE_CNTL + primary->offset, reg); WREG32(NI_DIG_BE_CNTL + primary->offset, reg); if (enable) { uint32_t offset = radeon_atom_set_enc_offset(mst_enc->fe); do { temp = RREG32(NI_DIG_FE_CNTL + offset); } while ((temp & NI_DIG_SYMCLK_FE_ON) && retries++ < 10000); if (retries == 10000) DRM_ERROR("timed out waiting for FE %d %d\n", primary->offset, mst_enc->fe); } return 0; } static int radeon_dp_mst_set_stream_attrib(struct radeon_encoder *primary, int stream_number, int fe, int slots) { struct drm_device *dev = primary->base.dev; struct radeon_device *rdev = dev->dev_private; u32 temp, val; int retries = 0; int satreg, satidx; satreg = stream_number >> 1; satidx = stream_number & 1; temp = RREG32(NI_DP_MSE_SAT0 + satreg + primary->offset); val = NI_DP_MSE_SAT_SLOT_COUNT0(slots) | NI_DP_MSE_SAT_SRC0(fe); val <<= (16 * satidx); temp &= ~(0xffff << (16 * satidx)); temp |= val; DRM_DEBUG_KMS("writing 0x%08x 0x%08x\n", NI_DP_MSE_SAT0 + satreg + primary->offset, temp); WREG32(NI_DP_MSE_SAT0 + satreg + primary->offset, temp); WREG32(NI_DP_MSE_SAT_UPDATE + primary->offset, 1); do { temp = RREG32(NI_DP_MSE_SAT_UPDATE + primary->offset); } while ((temp & 0x1) && retries++ < 10000); if (retries == 10000) DRM_ERROR("timed out waitin for SAT update %d\n", primary->offset); /* MTP 16 ? */ return 0; } static int radeon_dp_mst_update_stream_attribs(struct radeon_connector *mst_conn, struct radeon_encoder *primary) { struct drm_device *dev = mst_conn->base.dev; struct stream_attribs new_attribs[6]; int i; int idx = 0; struct radeon_connector *radeon_connector; struct drm_connector *connector; memset(new_attribs, 0, sizeof(new_attribs)); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct radeon_encoder *subenc; struct radeon_encoder_mst *mst_enc; radeon_connector = to_radeon_connector(connector); if (!radeon_connector->is_mst_connector) continue; if (radeon_connector->mst_port != mst_conn) continue; subenc = radeon_connector->mst_encoder; mst_enc = subenc->enc_priv; if (!mst_enc->enc_active) continue; new_attribs[idx].fe = mst_enc->fe; new_attribs[idx].slots = drm_dp_mst_get_vcpi_slots(&mst_conn->mst_mgr, mst_enc->port); idx++; } for (i = 0; i < idx; i++) { if (new_attribs[i].fe != mst_conn->cur_stream_attribs[i].fe || new_attribs[i].slots != mst_conn->cur_stream_attribs[i].slots) { radeon_dp_mst_set_stream_attrib(primary, i, new_attribs[i].fe, new_attribs[i].slots); mst_conn->cur_stream_attribs[i].fe = new_attribs[i].fe; mst_conn->cur_stream_attribs[i].slots = new_attribs[i].slots; } } for (i = idx; i < mst_conn->enabled_attribs; i++) { radeon_dp_mst_set_stream_attrib(primary, i, 0, 0); mst_conn->cur_stream_attribs[i].fe = 0; mst_conn->cur_stream_attribs[i].slots = 0; } mst_conn->enabled_attribs = idx; return 0; } static int radeon_dp_mst_set_vcp_size(struct radeon_encoder *mst, uint32_t x, uint32_t y) { struct drm_device *dev = mst->base.dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder_mst *mst_enc = mst->enc_priv; uint32_t val, temp; uint32_t offset = radeon_atom_set_enc_offset(mst_enc->fe); int retries = 0; val = NI_DP_MSE_RATE_X(x) | NI_DP_MSE_RATE_Y(y); WREG32(NI_DP_MSE_RATE_CNTL + offset, val); do { temp = RREG32(NI_DP_MSE_RATE_UPDATE + offset); } while ((temp & 0x1) && (retries++ < 10000)); if (retries >= 10000) DRM_ERROR("timed out wait for rate cntl %d\n", mst_enc->fe); return 0; } static int radeon_dp_mst_get_ddc_modes(struct drm_connector *connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct radeon_connector *master = radeon_connector->mst_port; struct edid *edid; int ret = 0; edid = drm_dp_mst_get_edid(connector, &master->mst_mgr, radeon_connector->port); radeon_connector->edid = edid; DRM_DEBUG_KMS("edid retrieved %p\n", edid); if (radeon_connector->edid) { drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid); drm_edid_to_eld(&radeon_connector->base, radeon_connector->edid); return ret; } drm_mode_connector_update_edid_property(&radeon_connector->base, NULL); return ret; } static int radeon_dp_mst_get_modes(struct drm_connector *connector) { return radeon_dp_mst_get_ddc_modes(connector); } static enum drm_mode_status radeon_dp_mst_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { /* TODO - validate mode against available PBN for link */ if (mode->clock < 10000) return MODE_CLOCK_LOW; if (mode->flags & DRM_MODE_FLAG_DBLCLK) return MODE_H_ILLEGAL; return MODE_OK; } struct drm_encoder *radeon_mst_best_encoder(struct drm_connector *connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); return &radeon_connector->mst_encoder->base; } static const struct drm_connector_helper_funcs radeon_dp_mst_connector_helper_funcs = { .get_modes = radeon_dp_mst_get_modes, .mode_valid = radeon_dp_mst_mode_valid, .best_encoder = radeon_mst_best_encoder, }; static enum drm_connector_status radeon_dp_mst_detect(struct drm_connector *connector, bool force) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct radeon_connector *master = radeon_connector->mst_port; return drm_dp_mst_detect_port(connector, &master->mst_mgr, radeon_connector->port); } static void radeon_dp_mst_connector_destroy(struct drm_connector *connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct radeon_encoder *radeon_encoder = radeon_connector->mst_encoder; drm_encoder_cleanup(&radeon_encoder->base); kfree(radeon_encoder); drm_connector_cleanup(connector); kfree(radeon_connector); } static int radeon_connector_dpms(struct drm_connector *connector, int mode) { DRM_DEBUG_KMS("\n"); return 0; } static const struct drm_connector_funcs radeon_dp_mst_connector_funcs = { .dpms = radeon_connector_dpms, .detect = radeon_dp_mst_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = radeon_dp_mst_connector_destroy, }; static struct drm_connector *radeon_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, const char *pathprop) { struct radeon_connector *master = container_of(mgr, struct radeon_connector, mst_mgr); struct drm_device *dev = master->base.dev; struct radeon_connector *radeon_connector; struct drm_connector *connector; radeon_connector = kzalloc(sizeof(*radeon_connector), GFP_KERNEL); if (!radeon_connector) return NULL; radeon_connector->is_mst_connector = true; connector = &radeon_connector->base; radeon_connector->port = port; radeon_connector->mst_port = master; DRM_DEBUG_KMS("\n"); drm_connector_init(dev, connector, &radeon_dp_mst_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort); drm_connector_helper_add(connector, &radeon_dp_mst_connector_helper_funcs); radeon_connector->mst_encoder = radeon_dp_create_fake_mst_encoder(master); drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0); drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0); drm_mode_connector_set_path_property(connector, pathprop); return connector; } static void radeon_dp_register_mst_connector(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct radeon_device *rdev = dev->dev_private; drm_modeset_lock_all(dev); radeon_fb_add_connector(rdev, connector); drm_modeset_unlock_all(dev); drm_connector_register(connector); } static void radeon_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_connector *connector) { struct radeon_connector *master = container_of(mgr, struct radeon_connector, mst_mgr); struct drm_device *dev = master->base.dev; struct radeon_device *rdev = dev->dev_private; drm_connector_unregister(connector); /* need to nuke the connector */ drm_modeset_lock_all(dev); /* dpms off */ radeon_fb_remove_connector(rdev, connector); drm_connector_cleanup(connector); drm_modeset_unlock_all(dev); kfree(connector); DRM_DEBUG_KMS("\n"); } static void radeon_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr) { struct radeon_connector *master = container_of(mgr, struct radeon_connector, mst_mgr); struct drm_device *dev = master->base.dev; drm_kms_helper_hotplug_event(dev); } const struct drm_dp_mst_topology_cbs mst_cbs = { .add_connector = radeon_dp_add_mst_connector, .register_connector = radeon_dp_register_mst_connector, .destroy_connector = radeon_dp_destroy_mst_connector, .hotplug = radeon_dp_mst_hotplug, }; struct radeon_connector *radeon_mst_find_connector(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct drm_connector *connector; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); if (!connector->encoder) continue; if (!radeon_connector->is_mst_connector) continue; DRM_DEBUG_KMS("checking %p vs %p\n", connector->encoder, encoder); if (connector->encoder == encoder) return radeon_connector; } return NULL; } void radeon_dp_mst_prepare_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(radeon_crtc->encoder); struct radeon_encoder_mst *mst_enc = radeon_encoder->enc_priv; struct radeon_connector *radeon_connector = radeon_mst_find_connector(&radeon_encoder->base); int dp_clock; struct radeon_connector_atom_dig *dig_connector = mst_enc->connector->con_priv; if (radeon_connector) { radeon_connector->pixelclock_for_modeset = mode->clock; if (radeon_connector->base.display_info.bpc) radeon_crtc->bpc = radeon_connector->base.display_info.bpc; else radeon_crtc->bpc = 8; } DRM_DEBUG_KMS("dp_clock %p %d\n", dig_connector, dig_connector->dp_clock); dp_clock = dig_connector->dp_clock; radeon_crtc->ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &radeon_crtc->ss, ASIC_INTERNAL_SS_ON_DP, dp_clock); } static void radeon_mst_encoder_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder, *primary; struct radeon_encoder_mst *mst_enc; struct radeon_encoder_atom_dig *dig_enc; struct radeon_connector *radeon_connector; struct drm_crtc *crtc; struct radeon_crtc *radeon_crtc; int ret, slots; if (!ASIC_IS_DCE5(rdev)) { DRM_ERROR("got mst dpms on non-DCE5\n"); return; } radeon_connector = radeon_mst_find_connector(encoder); if (!radeon_connector) return; radeon_encoder = to_radeon_encoder(encoder); mst_enc = radeon_encoder->enc_priv; primary = mst_enc->primary; dig_enc = primary->enc_priv; crtc = encoder->crtc; DRM_DEBUG_KMS("got connector %d\n", dig_enc->active_mst_links); switch (mode) { case DRM_MODE_DPMS_ON: dig_enc->active_mst_links++; radeon_crtc = to_radeon_crtc(crtc); if (dig_enc->active_mst_links == 1) { mst_enc->fe = dig_enc->dig_encoder; mst_enc->fe_from_be = true; atombios_set_mst_encoder_crtc_source(encoder, mst_enc->fe); atombios_dig_encoder_setup(&primary->base, ATOM_ENCODER_CMD_SETUP, 0); atombios_dig_transmitter_setup2(&primary->base, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0, dig_enc->dig_encoder); if (radeon_dp_needs_link_train(mst_enc->connector) || dig_enc->active_mst_links == 1) { radeon_dp_link_train(&primary->base, &mst_enc->connector->base); } } else { mst_enc->fe = radeon_atom_pick_dig_encoder(encoder, radeon_crtc->crtc_id); if (mst_enc->fe == -1) DRM_ERROR("failed to get frontend for dig encoder\n"); mst_enc->fe_from_be = false; atombios_set_mst_encoder_crtc_source(encoder, mst_enc->fe); } DRM_DEBUG_KMS("dig encoder is %d %d %d\n", dig_enc->dig_encoder, dig_enc->linkb, radeon_crtc->crtc_id); ret = drm_dp_mst_allocate_vcpi(&radeon_connector->mst_port->mst_mgr, radeon_connector->port, mst_enc->pbn, &slots); ret = drm_dp_update_payload_part1(&radeon_connector->mst_port->mst_mgr); radeon_dp_mst_set_be_cntl(primary, mst_enc, radeon_connector->mst_port->hpd.hpd, true); mst_enc->enc_active = true; radeon_dp_mst_update_stream_attribs(radeon_connector->mst_port, primary); radeon_dp_mst_set_vcp_size(radeon_encoder, slots, 0); atombios_dig_encoder_setup2(&primary->base, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0, mst_enc->fe); ret = drm_dp_check_act_status(&radeon_connector->mst_port->mst_mgr); ret = drm_dp_update_payload_part2(&radeon_connector->mst_port->mst_mgr); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: DRM_ERROR("DPMS OFF %d\n", dig_enc->active_mst_links); if (!mst_enc->enc_active) return; drm_dp_mst_reset_vcpi_slots(&radeon_connector->mst_port->mst_mgr, mst_enc->port); ret = drm_dp_update_payload_part1(&radeon_connector->mst_port->mst_mgr); drm_dp_check_act_status(&radeon_connector->mst_port->mst_mgr); /* and this can also fail */ drm_dp_update_payload_part2(&radeon_connector->mst_port->mst_mgr); drm_dp_mst_deallocate_vcpi(&radeon_connector->mst_port->mst_mgr, mst_enc->port); mst_enc->enc_active = false; radeon_dp_mst_update_stream_attribs(radeon_connector->mst_port, primary); radeon_dp_mst_set_be_cntl(primary, mst_enc, radeon_connector->mst_port->hpd.hpd, false); atombios_dig_encoder_setup2(&primary->base, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0, mst_enc->fe); if (!mst_enc->fe_from_be) radeon_atom_release_dig_encoder(rdev, mst_enc->fe); mst_enc->fe_from_be = false; dig_enc->active_mst_links--; if (dig_enc->active_mst_links == 0) { /* drop link */ } break; } } static bool radeon_mst_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct radeon_encoder_mst *mst_enc; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_connector_atom_dig *dig_connector; int bpp = 24; mst_enc = radeon_encoder->enc_priv; mst_enc->pbn = drm_dp_calc_pbn_mode(adjusted_mode->clock, bpp); mst_enc->primary->active_device = mst_enc->primary->devices & mst_enc->connector->devices; DRM_DEBUG_KMS("setting active device to %08x from %08x %08x for encoder %d\n", mst_enc->primary->active_device, mst_enc->primary->devices, mst_enc->connector->devices, mst_enc->primary->base.encoder_type); drm_mode_set_crtcinfo(adjusted_mode, 0); dig_connector = mst_enc->connector->con_priv; dig_connector->dp_lane_count = drm_dp_max_lane_count(dig_connector->dpcd); dig_connector->dp_clock = drm_dp_max_link_rate(dig_connector->dpcd); DRM_DEBUG_KMS("dig clock %p %d %d\n", dig_connector, dig_connector->dp_lane_count, dig_connector->dp_clock); return true; } static void radeon_mst_encoder_prepare(struct drm_encoder *encoder) { struct radeon_connector *radeon_connector; struct radeon_encoder *radeon_encoder, *primary; struct radeon_encoder_mst *mst_enc; struct radeon_encoder_atom_dig *dig_enc; radeon_connector = radeon_mst_find_connector(encoder); if (!radeon_connector) { DRM_DEBUG_KMS("failed to find connector %p\n", encoder); return; } radeon_encoder = to_radeon_encoder(encoder); radeon_mst_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); mst_enc = radeon_encoder->enc_priv; primary = mst_enc->primary; dig_enc = primary->enc_priv; mst_enc->port = radeon_connector->port; if (dig_enc->dig_encoder == -1) { dig_enc->dig_encoder = radeon_atom_pick_dig_encoder(&primary->base, -1); primary->offset = radeon_atom_set_enc_offset(dig_enc->dig_encoder); atombios_set_mst_encoder_crtc_source(encoder, dig_enc->dig_encoder); } DRM_DEBUG_KMS("%d %d\n", dig_enc->dig_encoder, primary->offset); } static void radeon_mst_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { DRM_DEBUG_KMS("\n"); } static void radeon_mst_encoder_commit(struct drm_encoder *encoder) { radeon_mst_encoder_dpms(encoder, DRM_MODE_DPMS_ON); DRM_DEBUG_KMS("\n"); } static const struct drm_encoder_helper_funcs radeon_mst_helper_funcs = { .dpms = radeon_mst_encoder_dpms, .mode_fixup = radeon_mst_mode_fixup, .prepare = radeon_mst_encoder_prepare, .mode_set = radeon_mst_encoder_mode_set, .commit = radeon_mst_encoder_commit, }; void radeon_dp_mst_encoder_destroy(struct drm_encoder *encoder) { drm_encoder_cleanup(encoder); kfree(encoder); } static const struct drm_encoder_funcs radeon_dp_mst_enc_funcs = { .destroy = radeon_dp_mst_encoder_destroy, }; static struct radeon_encoder * radeon_dp_create_fake_mst_encoder(struct radeon_connector *connector) { struct drm_device *dev = connector->base.dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder; struct radeon_encoder_mst *mst_enc; struct drm_encoder *encoder; const struct drm_connector_helper_funcs *connector_funcs = connector->base.helper_private; struct drm_encoder *enc_master = connector_funcs->best_encoder(&connector->base); DRM_DEBUG_KMS("enc master is %p\n", enc_master); radeon_encoder = kzalloc(sizeof(*radeon_encoder), GFP_KERNEL); if (!radeon_encoder) return NULL; radeon_encoder->enc_priv = kzalloc(sizeof(*mst_enc), GFP_KERNEL); if (!radeon_encoder->enc_priv) { kfree(radeon_encoder); return NULL; } encoder = &radeon_encoder->base; switch (rdev->num_crtc) { case 1: encoder->possible_crtcs = 0x1; break; case 2: default: encoder->possible_crtcs = 0x3; break; case 4: encoder->possible_crtcs = 0xf; break; case 6: encoder->possible_crtcs = 0x3f; break; } drm_encoder_init(dev, &radeon_encoder->base, &radeon_dp_mst_enc_funcs, DRM_MODE_ENCODER_DPMST, NULL); drm_encoder_helper_add(encoder, &radeon_mst_helper_funcs); mst_enc = radeon_encoder->enc_priv; mst_enc->connector = connector; mst_enc->primary = to_radeon_encoder(enc_master); radeon_encoder->is_mst_encoder = true; return radeon_encoder; } int radeon_dp_mst_init(struct radeon_connector *radeon_connector) { struct drm_device *dev = radeon_connector->base.dev; if (!radeon_connector->ddc_bus->has_aux) return 0; radeon_connector->mst_mgr.cbs = &mst_cbs; return drm_dp_mst_topology_mgr_init(&radeon_connector->mst_mgr, dev->dev, &radeon_connector->ddc_bus->aux, 16, 6, radeon_connector->base.base.id); } int radeon_dp_mst_probe(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; int ret; u8 msg[1]; if (!radeon_mst) return 0; if (!ASIC_IS_DCE5(rdev)) return 0; if (dig_connector->dpcd[DP_DPCD_REV] < 0x12) return 0; ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_MSTM_CAP, msg, 1); if (ret) { if (msg[0] & DP_MST_CAP) { DRM_DEBUG_KMS("Sink is MST capable\n"); dig_connector->is_mst = true; } else { DRM_DEBUG_KMS("Sink is not MST capable\n"); dig_connector->is_mst = false; } } drm_dp_mst_topology_mgr_set_mst(&radeon_connector->mst_mgr, dig_connector->is_mst); return dig_connector->is_mst; } int radeon_dp_mst_check_status(struct radeon_connector *radeon_connector) { struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; int retry; if (dig_connector->is_mst) { u8 esi[16] = { 0 }; int dret; int ret = 0; bool handled; dret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_SINK_COUNT_ESI, esi, 8); go_again: if (dret == 8) { DRM_DEBUG_KMS("got esi %02x %02x %02x\n", esi[0], esi[1], esi[2]); ret = drm_dp_mst_hpd_irq(&radeon_connector->mst_mgr, esi, &handled); if (handled) { for (retry = 0; retry < 3; retry++) { int wret; wret = drm_dp_dpcd_write(&radeon_connector->ddc_bus->aux, DP_SINK_COUNT_ESI + 1, &esi[1], 3); if (wret == 3) break; } dret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_SINK_COUNT_ESI, esi, 8); if (dret == 8) { DRM_DEBUG_KMS("got esi2 %02x %02x %02x\n", esi[0], esi[1], esi[2]); goto go_again; } } else ret = 0; return ret; } else { DRM_DEBUG_KMS("failed to get ESI - device may have failed %d\n", ret); dig_connector->is_mst = false; drm_dp_mst_topology_mgr_set_mst(&radeon_connector->mst_mgr, dig_connector->is_mst); /* send a hotplug event */ } } return -EINVAL; } #if defined(CONFIG_DEBUG_FS) static int radeon_debugfs_mst_info(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *)m->private; struct drm_device *dev = node->minor->dev; struct drm_connector *connector; struct radeon_connector *radeon_connector; struct radeon_connector_atom_dig *dig_connector; int i; drm_modeset_lock_all(dev); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) continue; radeon_connector = to_radeon_connector(connector); dig_connector = radeon_connector->con_priv; if (radeon_connector->is_mst_connector) continue; if (!dig_connector->is_mst) continue; drm_dp_mst_dump_topology(m, &radeon_connector->mst_mgr); for (i = 0; i < radeon_connector->enabled_attribs; i++) seq_printf(m, "attrib %d: %d %d\n", i, radeon_connector->cur_stream_attribs[i].fe, radeon_connector->cur_stream_attribs[i].slots); } drm_modeset_unlock_all(dev); return 0; } static struct drm_info_list radeon_debugfs_mst_list[] = { {"radeon_mst_info", &radeon_debugfs_mst_info, 0, NULL}, }; #endif int radeon_mst_debugfs_init(struct radeon_device *rdev) { #if defined(CONFIG_DEBUG_FS) return radeon_debugfs_add_files(rdev, radeon_debugfs_mst_list, 1); #endif return 0; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
You can’t perform that action at this time.