18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: MIT 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci#include <drm/drm_debugfs.h> 48c2ecf20Sopenharmony_ci#include <drm/drm_dp_mst_helper.h> 58c2ecf20Sopenharmony_ci#include <drm/drm_fb_helper.h> 68c2ecf20Sopenharmony_ci#include <drm/drm_file.h> 78c2ecf20Sopenharmony_ci#include <drm/drm_probe_helper.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "atom.h" 108c2ecf20Sopenharmony_ci#include "ni_reg.h" 118c2ecf20Sopenharmony_ci#include "radeon.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistatic struct radeon_encoder *radeon_dp_create_fake_mst_encoder(struct radeon_connector *connector); 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic int radeon_atom_set_enc_offset(int id) 168c2ecf20Sopenharmony_ci{ 178c2ecf20Sopenharmony_ci static const int offsets[] = { EVERGREEN_CRTC0_REGISTER_OFFSET, 188c2ecf20Sopenharmony_ci EVERGREEN_CRTC1_REGISTER_OFFSET, 198c2ecf20Sopenharmony_ci EVERGREEN_CRTC2_REGISTER_OFFSET, 208c2ecf20Sopenharmony_ci EVERGREEN_CRTC3_REGISTER_OFFSET, 218c2ecf20Sopenharmony_ci EVERGREEN_CRTC4_REGISTER_OFFSET, 228c2ecf20Sopenharmony_ci EVERGREEN_CRTC5_REGISTER_OFFSET, 238c2ecf20Sopenharmony_ci 0x13830 - 0x7030 }; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci return offsets[id]; 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic int radeon_dp_mst_set_be_cntl(struct radeon_encoder *primary, 298c2ecf20Sopenharmony_ci struct radeon_encoder_mst *mst_enc, 308c2ecf20Sopenharmony_ci enum radeon_hpd_id hpd, bool enable) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci struct drm_device *dev = primary->base.dev; 338c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 348c2ecf20Sopenharmony_ci uint32_t reg; 358c2ecf20Sopenharmony_ci int retries = 0; 368c2ecf20Sopenharmony_ci uint32_t temp; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci reg = RREG32(NI_DIG_BE_CNTL + primary->offset); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci /* set MST mode */ 418c2ecf20Sopenharmony_ci reg &= ~NI_DIG_FE_DIG_MODE(7); 428c2ecf20Sopenharmony_ci reg |= NI_DIG_FE_DIG_MODE(NI_DIG_MODE_DP_MST); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if (enable) 458c2ecf20Sopenharmony_ci reg |= NI_DIG_FE_SOURCE_SELECT(1 << mst_enc->fe); 468c2ecf20Sopenharmony_ci else 478c2ecf20Sopenharmony_ci reg &= ~NI_DIG_FE_SOURCE_SELECT(1 << mst_enc->fe); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci reg |= NI_DIG_HPD_SELECT(hpd); 508c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("writing 0x%08x 0x%08x\n", NI_DIG_BE_CNTL + primary->offset, reg); 518c2ecf20Sopenharmony_ci WREG32(NI_DIG_BE_CNTL + primary->offset, reg); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci if (enable) { 548c2ecf20Sopenharmony_ci uint32_t offset = radeon_atom_set_enc_offset(mst_enc->fe); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci do { 578c2ecf20Sopenharmony_ci temp = RREG32(NI_DIG_FE_CNTL + offset); 588c2ecf20Sopenharmony_ci } while ((temp & NI_DIG_SYMCLK_FE_ON) && retries++ < 10000); 598c2ecf20Sopenharmony_ci if (retries == 10000) 608c2ecf20Sopenharmony_ci DRM_ERROR("timed out waiting for FE %d %d\n", primary->offset, mst_enc->fe); 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci return 0; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic int radeon_dp_mst_set_stream_attrib(struct radeon_encoder *primary, 668c2ecf20Sopenharmony_ci int stream_number, 678c2ecf20Sopenharmony_ci int fe, 688c2ecf20Sopenharmony_ci int slots) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct drm_device *dev = primary->base.dev; 718c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 728c2ecf20Sopenharmony_ci u32 temp, val; 738c2ecf20Sopenharmony_ci int retries = 0; 748c2ecf20Sopenharmony_ci int satreg, satidx; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci satreg = stream_number >> 1; 778c2ecf20Sopenharmony_ci satidx = stream_number & 1; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci temp = RREG32(NI_DP_MSE_SAT0 + satreg + primary->offset); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci val = NI_DP_MSE_SAT_SLOT_COUNT0(slots) | NI_DP_MSE_SAT_SRC0(fe); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci val <<= (16 * satidx); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci temp &= ~(0xffff << (16 * satidx)); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci temp |= val; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("writing 0x%08x 0x%08x\n", NI_DP_MSE_SAT0 + satreg + primary->offset, temp); 908c2ecf20Sopenharmony_ci WREG32(NI_DP_MSE_SAT0 + satreg + primary->offset, temp); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci WREG32(NI_DP_MSE_SAT_UPDATE + primary->offset, 1); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci do { 958c2ecf20Sopenharmony_ci unsigned value1, value2; 968c2ecf20Sopenharmony_ci udelay(10); 978c2ecf20Sopenharmony_ci temp = RREG32(NI_DP_MSE_SAT_UPDATE + primary->offset); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci value1 = temp & NI_DP_MSE_SAT_UPDATE_MASK; 1008c2ecf20Sopenharmony_ci value2 = temp & NI_DP_MSE_16_MTP_KEEPOUT; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (!value1 && !value2) 1038c2ecf20Sopenharmony_ci break; 1048c2ecf20Sopenharmony_ci } while (retries++ < 50); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (retries == 10000) 1078c2ecf20Sopenharmony_ci DRM_ERROR("timed out waitin for SAT update %d\n", primary->offset); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* MTP 16 ? */ 1108c2ecf20Sopenharmony_ci return 0; 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic int radeon_dp_mst_update_stream_attribs(struct radeon_connector *mst_conn, 1148c2ecf20Sopenharmony_ci struct radeon_encoder *primary) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct drm_device *dev = mst_conn->base.dev; 1178c2ecf20Sopenharmony_ci struct stream_attribs new_attribs[6]; 1188c2ecf20Sopenharmony_ci int i; 1198c2ecf20Sopenharmony_ci int idx = 0; 1208c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector; 1218c2ecf20Sopenharmony_ci struct drm_connector *connector; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci memset(new_attribs, 0, sizeof(new_attribs)); 1248c2ecf20Sopenharmony_ci list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 1258c2ecf20Sopenharmony_ci struct radeon_encoder *subenc; 1268c2ecf20Sopenharmony_ci struct radeon_encoder_mst *mst_enc; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci radeon_connector = to_radeon_connector(connector); 1298c2ecf20Sopenharmony_ci if (!radeon_connector->is_mst_connector) 1308c2ecf20Sopenharmony_ci continue; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (radeon_connector->mst_port != mst_conn) 1338c2ecf20Sopenharmony_ci continue; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci subenc = radeon_connector->mst_encoder; 1368c2ecf20Sopenharmony_ci mst_enc = subenc->enc_priv; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (!mst_enc->enc_active) 1398c2ecf20Sopenharmony_ci continue; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci new_attribs[idx].fe = mst_enc->fe; 1428c2ecf20Sopenharmony_ci new_attribs[idx].slots = drm_dp_mst_get_vcpi_slots(&mst_conn->mst_mgr, mst_enc->port); 1438c2ecf20Sopenharmony_ci idx++; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci for (i = 0; i < idx; i++) { 1478c2ecf20Sopenharmony_ci if (new_attribs[i].fe != mst_conn->cur_stream_attribs[i].fe || 1488c2ecf20Sopenharmony_ci new_attribs[i].slots != mst_conn->cur_stream_attribs[i].slots) { 1498c2ecf20Sopenharmony_ci radeon_dp_mst_set_stream_attrib(primary, i, new_attribs[i].fe, new_attribs[i].slots); 1508c2ecf20Sopenharmony_ci mst_conn->cur_stream_attribs[i].fe = new_attribs[i].fe; 1518c2ecf20Sopenharmony_ci mst_conn->cur_stream_attribs[i].slots = new_attribs[i].slots; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci for (i = idx; i < mst_conn->enabled_attribs; i++) { 1568c2ecf20Sopenharmony_ci radeon_dp_mst_set_stream_attrib(primary, i, 0, 0); 1578c2ecf20Sopenharmony_ci mst_conn->cur_stream_attribs[i].fe = 0; 1588c2ecf20Sopenharmony_ci mst_conn->cur_stream_attribs[i].slots = 0; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci mst_conn->enabled_attribs = idx; 1618c2ecf20Sopenharmony_ci return 0; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int radeon_dp_mst_set_vcp_size(struct radeon_encoder *mst, s64 avg_time_slots_per_mtp) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct drm_device *dev = mst->base.dev; 1678c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 1688c2ecf20Sopenharmony_ci struct radeon_encoder_mst *mst_enc = mst->enc_priv; 1698c2ecf20Sopenharmony_ci uint32_t val, temp; 1708c2ecf20Sopenharmony_ci uint32_t offset = radeon_atom_set_enc_offset(mst_enc->fe); 1718c2ecf20Sopenharmony_ci int retries = 0; 1728c2ecf20Sopenharmony_ci uint32_t x = drm_fixp2int(avg_time_slots_per_mtp); 1738c2ecf20Sopenharmony_ci uint32_t y = drm_fixp2int_ceil((avg_time_slots_per_mtp - x) << 26); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci val = NI_DP_MSE_RATE_X(x) | NI_DP_MSE_RATE_Y(y); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci WREG32(NI_DP_MSE_RATE_CNTL + offset, val); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci do { 1808c2ecf20Sopenharmony_ci temp = RREG32(NI_DP_MSE_RATE_UPDATE + offset); 1818c2ecf20Sopenharmony_ci udelay(10); 1828c2ecf20Sopenharmony_ci } while ((temp & 0x1) && (retries++ < 10000)); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (retries >= 10000) 1858c2ecf20Sopenharmony_ci DRM_ERROR("timed out wait for rate cntl %d\n", mst_enc->fe); 1868c2ecf20Sopenharmony_ci return 0; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic int radeon_dp_mst_get_ddc_modes(struct drm_connector *connector) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1928c2ecf20Sopenharmony_ci struct radeon_connector *master = radeon_connector->mst_port; 1938c2ecf20Sopenharmony_ci struct edid *edid; 1948c2ecf20Sopenharmony_ci int ret = 0; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci edid = drm_dp_mst_get_edid(connector, &master->mst_mgr, radeon_connector->port); 1978c2ecf20Sopenharmony_ci radeon_connector->edid = edid; 1988c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("edid retrieved %p\n", edid); 1998c2ecf20Sopenharmony_ci if (radeon_connector->edid) { 2008c2ecf20Sopenharmony_ci drm_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); 2018c2ecf20Sopenharmony_ci ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid); 2028c2ecf20Sopenharmony_ci return ret; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci drm_connector_update_edid_property(&radeon_connector->base, NULL); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci return ret; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic int radeon_dp_mst_get_modes(struct drm_connector *connector) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci return radeon_dp_mst_get_ddc_modes(connector); 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic enum drm_mode_status 2158c2ecf20Sopenharmony_ciradeon_dp_mst_mode_valid(struct drm_connector *connector, 2168c2ecf20Sopenharmony_ci struct drm_display_mode *mode) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci /* TODO - validate mode against available PBN for link */ 2198c2ecf20Sopenharmony_ci if (mode->clock < 10000) 2208c2ecf20Sopenharmony_ci return MODE_CLOCK_LOW; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_DBLCLK) 2238c2ecf20Sopenharmony_ci return MODE_H_ILLEGAL; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci return MODE_OK; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic struct 2298c2ecf20Sopenharmony_cidrm_encoder *radeon_mst_best_encoder(struct drm_connector *connector) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci return &radeon_connector->mst_encoder->base; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic int 2378c2ecf20Sopenharmony_ciradeon_dp_mst_detect(struct drm_connector *connector, 2388c2ecf20Sopenharmony_ci struct drm_modeset_acquire_ctx *ctx, 2398c2ecf20Sopenharmony_ci bool force) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector = 2428c2ecf20Sopenharmony_ci to_radeon_connector(connector); 2438c2ecf20Sopenharmony_ci struct radeon_connector *master = radeon_connector->mst_port; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (drm_connector_is_unregistered(connector)) 2468c2ecf20Sopenharmony_ci return connector_status_disconnected; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return drm_dp_mst_detect_port(connector, ctx, &master->mst_mgr, 2498c2ecf20Sopenharmony_ci radeon_connector->port); 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic const struct drm_connector_helper_funcs radeon_dp_mst_connector_helper_funcs = { 2538c2ecf20Sopenharmony_ci .get_modes = radeon_dp_mst_get_modes, 2548c2ecf20Sopenharmony_ci .mode_valid = radeon_dp_mst_mode_valid, 2558c2ecf20Sopenharmony_ci .best_encoder = radeon_mst_best_encoder, 2568c2ecf20Sopenharmony_ci .detect_ctx = radeon_dp_mst_detect, 2578c2ecf20Sopenharmony_ci}; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic void 2608c2ecf20Sopenharmony_ciradeon_dp_mst_connector_destroy(struct drm_connector *connector) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 2638c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = radeon_connector->mst_encoder; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci drm_encoder_cleanup(&radeon_encoder->base); 2668c2ecf20Sopenharmony_ci kfree(radeon_encoder); 2678c2ecf20Sopenharmony_ci drm_connector_cleanup(connector); 2688c2ecf20Sopenharmony_ci kfree(radeon_connector); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs radeon_dp_mst_connector_funcs = { 2728c2ecf20Sopenharmony_ci .dpms = drm_helper_connector_dpms, 2738c2ecf20Sopenharmony_ci .fill_modes = drm_helper_probe_single_connector_modes, 2748c2ecf20Sopenharmony_ci .destroy = radeon_dp_mst_connector_destroy, 2758c2ecf20Sopenharmony_ci}; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic struct drm_connector *radeon_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, 2788c2ecf20Sopenharmony_ci struct drm_dp_mst_port *port, 2798c2ecf20Sopenharmony_ci const char *pathprop) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct radeon_connector *master = container_of(mgr, struct radeon_connector, mst_mgr); 2828c2ecf20Sopenharmony_ci struct drm_device *dev = master->base.dev; 2838c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector; 2848c2ecf20Sopenharmony_ci struct drm_connector *connector; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci radeon_connector = kzalloc(sizeof(*radeon_connector), GFP_KERNEL); 2878c2ecf20Sopenharmony_ci if (!radeon_connector) 2888c2ecf20Sopenharmony_ci return NULL; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci radeon_connector->is_mst_connector = true; 2918c2ecf20Sopenharmony_ci connector = &radeon_connector->base; 2928c2ecf20Sopenharmony_ci radeon_connector->port = port; 2938c2ecf20Sopenharmony_ci radeon_connector->mst_port = master; 2948c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("\n"); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci drm_connector_init(dev, connector, &radeon_dp_mst_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort); 2978c2ecf20Sopenharmony_ci drm_connector_helper_add(connector, &radeon_dp_mst_connector_helper_funcs); 2988c2ecf20Sopenharmony_ci radeon_connector->mst_encoder = radeon_dp_create_fake_mst_encoder(master); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0); 3018c2ecf20Sopenharmony_ci drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0); 3028c2ecf20Sopenharmony_ci drm_connector_set_path_property(connector, pathprop); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return connector; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic const struct drm_dp_mst_topology_cbs mst_cbs = { 3088c2ecf20Sopenharmony_ci .add_connector = radeon_dp_add_mst_connector, 3098c2ecf20Sopenharmony_ci}; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic struct 3128c2ecf20Sopenharmony_ciradeon_connector *radeon_mst_find_connector(struct drm_encoder *encoder) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 3158c2ecf20Sopenharmony_ci struct drm_connector *connector; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 3188c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector = to_radeon_connector(connector); 3198c2ecf20Sopenharmony_ci if (!connector->encoder) 3208c2ecf20Sopenharmony_ci continue; 3218c2ecf20Sopenharmony_ci if (!radeon_connector->is_mst_connector) 3228c2ecf20Sopenharmony_ci continue; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("checking %p vs %p\n", connector->encoder, encoder); 3258c2ecf20Sopenharmony_ci if (connector->encoder == encoder) 3268c2ecf20Sopenharmony_ci return radeon_connector; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci return NULL; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_civoid radeon_dp_mst_prepare_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 3348c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 3358c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 3368c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(radeon_crtc->encoder); 3378c2ecf20Sopenharmony_ci struct radeon_encoder_mst *mst_enc = radeon_encoder->enc_priv; 3388c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector = radeon_mst_find_connector(&radeon_encoder->base); 3398c2ecf20Sopenharmony_ci int dp_clock; 3408c2ecf20Sopenharmony_ci struct radeon_connector_atom_dig *dig_connector = mst_enc->connector->con_priv; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (radeon_connector) { 3438c2ecf20Sopenharmony_ci radeon_connector->pixelclock_for_modeset = mode->clock; 3448c2ecf20Sopenharmony_ci if (radeon_connector->base.display_info.bpc) 3458c2ecf20Sopenharmony_ci radeon_crtc->bpc = radeon_connector->base.display_info.bpc; 3468c2ecf20Sopenharmony_ci else 3478c2ecf20Sopenharmony_ci radeon_crtc->bpc = 8; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("dp_clock %p %d\n", dig_connector, dig_connector->dp_clock); 3518c2ecf20Sopenharmony_ci dp_clock = dig_connector->dp_clock; 3528c2ecf20Sopenharmony_ci radeon_crtc->ss_enabled = 3538c2ecf20Sopenharmony_ci radeon_atombios_get_asic_ss_info(rdev, &radeon_crtc->ss, 3548c2ecf20Sopenharmony_ci ASIC_INTERNAL_SS_ON_DP, 3558c2ecf20Sopenharmony_ci dp_clock); 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic void 3598c2ecf20Sopenharmony_ciradeon_mst_encoder_dpms(struct drm_encoder *encoder, int mode) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 3628c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 3638c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder, *primary; 3648c2ecf20Sopenharmony_ci struct radeon_encoder_mst *mst_enc; 3658c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *dig_enc; 3668c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector; 3678c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 3688c2ecf20Sopenharmony_ci struct radeon_crtc *radeon_crtc; 3698c2ecf20Sopenharmony_ci int ret, slots; 3708c2ecf20Sopenharmony_ci s64 fixed_pbn, fixed_pbn_per_slot, avg_time_slots_per_mtp; 3718c2ecf20Sopenharmony_ci if (!ASIC_IS_DCE5(rdev)) { 3728c2ecf20Sopenharmony_ci DRM_ERROR("got mst dpms on non-DCE5\n"); 3738c2ecf20Sopenharmony_ci return; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci radeon_connector = radeon_mst_find_connector(encoder); 3778c2ecf20Sopenharmony_ci if (!radeon_connector) 3788c2ecf20Sopenharmony_ci return; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci radeon_encoder = to_radeon_encoder(encoder); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci mst_enc = radeon_encoder->enc_priv; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci primary = mst_enc->primary; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci dig_enc = primary->enc_priv; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci crtc = encoder->crtc; 3898c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("got connector %d\n", dig_enc->active_mst_links); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci switch (mode) { 3928c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_ON: 3938c2ecf20Sopenharmony_ci dig_enc->active_mst_links++; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci radeon_crtc = to_radeon_crtc(crtc); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (dig_enc->active_mst_links == 1) { 3988c2ecf20Sopenharmony_ci mst_enc->fe = dig_enc->dig_encoder; 3998c2ecf20Sopenharmony_ci mst_enc->fe_from_be = true; 4008c2ecf20Sopenharmony_ci atombios_set_mst_encoder_crtc_source(encoder, mst_enc->fe); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci atombios_dig_encoder_setup(&primary->base, ATOM_ENCODER_CMD_SETUP, 0); 4038c2ecf20Sopenharmony_ci atombios_dig_transmitter_setup2(&primary->base, ATOM_TRANSMITTER_ACTION_ENABLE, 4048c2ecf20Sopenharmony_ci 0, 0, dig_enc->dig_encoder); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (radeon_dp_needs_link_train(mst_enc->connector) || 4078c2ecf20Sopenharmony_ci dig_enc->active_mst_links == 1) { 4088c2ecf20Sopenharmony_ci radeon_dp_link_train(&primary->base, &mst_enc->connector->base); 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci } else { 4128c2ecf20Sopenharmony_ci mst_enc->fe = radeon_atom_pick_dig_encoder(encoder, radeon_crtc->crtc_id); 4138c2ecf20Sopenharmony_ci if (mst_enc->fe == -1) 4148c2ecf20Sopenharmony_ci DRM_ERROR("failed to get frontend for dig encoder\n"); 4158c2ecf20Sopenharmony_ci mst_enc->fe_from_be = false; 4168c2ecf20Sopenharmony_ci atombios_set_mst_encoder_crtc_source(encoder, mst_enc->fe); 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("dig encoder is %d %d %d\n", dig_enc->dig_encoder, 4208c2ecf20Sopenharmony_ci dig_enc->linkb, radeon_crtc->crtc_id); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci slots = drm_dp_find_vcpi_slots(&radeon_connector->mst_port->mst_mgr, 4238c2ecf20Sopenharmony_ci mst_enc->pbn); 4248c2ecf20Sopenharmony_ci ret = drm_dp_mst_allocate_vcpi(&radeon_connector->mst_port->mst_mgr, 4258c2ecf20Sopenharmony_ci radeon_connector->port, 4268c2ecf20Sopenharmony_ci mst_enc->pbn, slots); 4278c2ecf20Sopenharmony_ci ret = drm_dp_update_payload_part1(&radeon_connector->mst_port->mst_mgr); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci radeon_dp_mst_set_be_cntl(primary, mst_enc, 4308c2ecf20Sopenharmony_ci radeon_connector->mst_port->hpd.hpd, true); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci mst_enc->enc_active = true; 4338c2ecf20Sopenharmony_ci radeon_dp_mst_update_stream_attribs(radeon_connector->mst_port, primary); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci fixed_pbn = drm_int2fixp(mst_enc->pbn); 4368c2ecf20Sopenharmony_ci fixed_pbn_per_slot = drm_int2fixp(radeon_connector->mst_port->mst_mgr.pbn_div); 4378c2ecf20Sopenharmony_ci avg_time_slots_per_mtp = drm_fixp_div(fixed_pbn, fixed_pbn_per_slot); 4388c2ecf20Sopenharmony_ci radeon_dp_mst_set_vcp_size(radeon_encoder, avg_time_slots_per_mtp); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci atombios_dig_encoder_setup2(&primary->base, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0, 4418c2ecf20Sopenharmony_ci mst_enc->fe); 4428c2ecf20Sopenharmony_ci ret = drm_dp_check_act_status(&radeon_connector->mst_port->mst_mgr); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci ret = drm_dp_update_payload_part2(&radeon_connector->mst_port->mst_mgr); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci break; 4478c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_STANDBY: 4488c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_SUSPEND: 4498c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_OFF: 4508c2ecf20Sopenharmony_ci DRM_ERROR("DPMS OFF %d\n", dig_enc->active_mst_links); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (!mst_enc->enc_active) 4538c2ecf20Sopenharmony_ci return; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci drm_dp_mst_reset_vcpi_slots(&radeon_connector->mst_port->mst_mgr, mst_enc->port); 4568c2ecf20Sopenharmony_ci ret = drm_dp_update_payload_part1(&radeon_connector->mst_port->mst_mgr); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci drm_dp_check_act_status(&radeon_connector->mst_port->mst_mgr); 4598c2ecf20Sopenharmony_ci /* and this can also fail */ 4608c2ecf20Sopenharmony_ci drm_dp_update_payload_part2(&radeon_connector->mst_port->mst_mgr); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci drm_dp_mst_deallocate_vcpi(&radeon_connector->mst_port->mst_mgr, mst_enc->port); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci mst_enc->enc_active = false; 4658c2ecf20Sopenharmony_ci radeon_dp_mst_update_stream_attribs(radeon_connector->mst_port, primary); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci radeon_dp_mst_set_be_cntl(primary, mst_enc, 4688c2ecf20Sopenharmony_ci radeon_connector->mst_port->hpd.hpd, false); 4698c2ecf20Sopenharmony_ci atombios_dig_encoder_setup2(&primary->base, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0, 4708c2ecf20Sopenharmony_ci mst_enc->fe); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci if (!mst_enc->fe_from_be) 4738c2ecf20Sopenharmony_ci radeon_atom_release_dig_encoder(rdev, mst_enc->fe); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci mst_enc->fe_from_be = false; 4768c2ecf20Sopenharmony_ci dig_enc->active_mst_links--; 4778c2ecf20Sopenharmony_ci if (dig_enc->active_mst_links == 0) { 4788c2ecf20Sopenharmony_ci /* drop link */ 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci break; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic bool radeon_mst_mode_fixup(struct drm_encoder *encoder, 4878c2ecf20Sopenharmony_ci const struct drm_display_mode *mode, 4888c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci struct radeon_encoder_mst *mst_enc; 4918c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 4928c2ecf20Sopenharmony_ci struct radeon_connector_atom_dig *dig_connector; 4938c2ecf20Sopenharmony_ci int bpp = 24; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci mst_enc = radeon_encoder->enc_priv; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci mst_enc->pbn = drm_dp_calc_pbn_mode(adjusted_mode->clock, bpp, false); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci mst_enc->primary->active_device = mst_enc->primary->devices & mst_enc->connector->devices; 5008c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("setting active device to %08x from %08x %08x for encoder %d\n", 5018c2ecf20Sopenharmony_ci mst_enc->primary->active_device, mst_enc->primary->devices, 5028c2ecf20Sopenharmony_ci mst_enc->connector->devices, mst_enc->primary->base.encoder_type); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci drm_mode_set_crtcinfo(adjusted_mode, 0); 5068c2ecf20Sopenharmony_ci dig_connector = mst_enc->connector->con_priv; 5078c2ecf20Sopenharmony_ci dig_connector->dp_lane_count = drm_dp_max_lane_count(dig_connector->dpcd); 5088c2ecf20Sopenharmony_ci dig_connector->dp_clock = drm_dp_max_link_rate(dig_connector->dpcd); 5098c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("dig clock %p %d %d\n", dig_connector, 5108c2ecf20Sopenharmony_ci dig_connector->dp_lane_count, dig_connector->dp_clock); 5118c2ecf20Sopenharmony_ci return true; 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic void radeon_mst_encoder_prepare(struct drm_encoder *encoder) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector; 5178c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder, *primary; 5188c2ecf20Sopenharmony_ci struct radeon_encoder_mst *mst_enc; 5198c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *dig_enc; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci radeon_connector = radeon_mst_find_connector(encoder); 5228c2ecf20Sopenharmony_ci if (!radeon_connector) { 5238c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("failed to find connector %p\n", encoder); 5248c2ecf20Sopenharmony_ci return; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci radeon_encoder = to_radeon_encoder(encoder); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci radeon_mst_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci mst_enc = radeon_encoder->enc_priv; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci primary = mst_enc->primary; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci dig_enc = primary->enc_priv; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci mst_enc->port = radeon_connector->port; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if (dig_enc->dig_encoder == -1) { 5398c2ecf20Sopenharmony_ci dig_enc->dig_encoder = radeon_atom_pick_dig_encoder(&primary->base, -1); 5408c2ecf20Sopenharmony_ci primary->offset = radeon_atom_set_enc_offset(dig_enc->dig_encoder); 5418c2ecf20Sopenharmony_ci atombios_set_mst_encoder_crtc_source(encoder, dig_enc->dig_encoder); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("%d %d\n", dig_enc->dig_encoder, primary->offset); 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic void 5498c2ecf20Sopenharmony_ciradeon_mst_encoder_mode_set(struct drm_encoder *encoder, 5508c2ecf20Sopenharmony_ci struct drm_display_mode *mode, 5518c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("\n"); 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic void radeon_mst_encoder_commit(struct drm_encoder *encoder) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci radeon_mst_encoder_dpms(encoder, DRM_MODE_DPMS_ON); 5598c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("\n"); 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cistatic const struct drm_encoder_helper_funcs radeon_mst_helper_funcs = { 5638c2ecf20Sopenharmony_ci .dpms = radeon_mst_encoder_dpms, 5648c2ecf20Sopenharmony_ci .mode_fixup = radeon_mst_mode_fixup, 5658c2ecf20Sopenharmony_ci .prepare = radeon_mst_encoder_prepare, 5668c2ecf20Sopenharmony_ci .mode_set = radeon_mst_encoder_mode_set, 5678c2ecf20Sopenharmony_ci .commit = radeon_mst_encoder_commit, 5688c2ecf20Sopenharmony_ci}; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic void radeon_dp_mst_encoder_destroy(struct drm_encoder *encoder) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci drm_encoder_cleanup(encoder); 5738c2ecf20Sopenharmony_ci kfree(encoder); 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic const struct drm_encoder_funcs radeon_dp_mst_enc_funcs = { 5778c2ecf20Sopenharmony_ci .destroy = radeon_dp_mst_encoder_destroy, 5788c2ecf20Sopenharmony_ci}; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cistatic struct radeon_encoder * 5818c2ecf20Sopenharmony_ciradeon_dp_create_fake_mst_encoder(struct radeon_connector *connector) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci struct drm_device *dev = connector->base.dev; 5848c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 5858c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder; 5868c2ecf20Sopenharmony_ci struct radeon_encoder_mst *mst_enc; 5878c2ecf20Sopenharmony_ci struct drm_encoder *encoder; 5888c2ecf20Sopenharmony_ci const struct drm_connector_helper_funcs *connector_funcs = connector->base.helper_private; 5898c2ecf20Sopenharmony_ci struct drm_encoder *enc_master = connector_funcs->best_encoder(&connector->base); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("enc master is %p\n", enc_master); 5928c2ecf20Sopenharmony_ci radeon_encoder = kzalloc(sizeof(*radeon_encoder), GFP_KERNEL); 5938c2ecf20Sopenharmony_ci if (!radeon_encoder) 5948c2ecf20Sopenharmony_ci return NULL; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci radeon_encoder->enc_priv = kzalloc(sizeof(*mst_enc), GFP_KERNEL); 5978c2ecf20Sopenharmony_ci if (!radeon_encoder->enc_priv) { 5988c2ecf20Sopenharmony_ci kfree(radeon_encoder); 5998c2ecf20Sopenharmony_ci return NULL; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci encoder = &radeon_encoder->base; 6028c2ecf20Sopenharmony_ci switch (rdev->num_crtc) { 6038c2ecf20Sopenharmony_ci case 1: 6048c2ecf20Sopenharmony_ci encoder->possible_crtcs = 0x1; 6058c2ecf20Sopenharmony_ci break; 6068c2ecf20Sopenharmony_ci case 2: 6078c2ecf20Sopenharmony_ci default: 6088c2ecf20Sopenharmony_ci encoder->possible_crtcs = 0x3; 6098c2ecf20Sopenharmony_ci break; 6108c2ecf20Sopenharmony_ci case 4: 6118c2ecf20Sopenharmony_ci encoder->possible_crtcs = 0xf; 6128c2ecf20Sopenharmony_ci break; 6138c2ecf20Sopenharmony_ci case 6: 6148c2ecf20Sopenharmony_ci encoder->possible_crtcs = 0x3f; 6158c2ecf20Sopenharmony_ci break; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci drm_encoder_init(dev, &radeon_encoder->base, &radeon_dp_mst_enc_funcs, 6198c2ecf20Sopenharmony_ci DRM_MODE_ENCODER_DPMST, NULL); 6208c2ecf20Sopenharmony_ci drm_encoder_helper_add(encoder, &radeon_mst_helper_funcs); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci mst_enc = radeon_encoder->enc_priv; 6238c2ecf20Sopenharmony_ci mst_enc->connector = connector; 6248c2ecf20Sopenharmony_ci mst_enc->primary = to_radeon_encoder(enc_master); 6258c2ecf20Sopenharmony_ci radeon_encoder->is_mst_encoder = true; 6268c2ecf20Sopenharmony_ci return radeon_encoder; 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ciint 6308c2ecf20Sopenharmony_ciradeon_dp_mst_init(struct radeon_connector *radeon_connector) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci struct drm_device *dev = radeon_connector->base.dev; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci if (!radeon_connector->ddc_bus->has_aux) 6358c2ecf20Sopenharmony_ci return 0; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci radeon_connector->mst_mgr.cbs = &mst_cbs; 6388c2ecf20Sopenharmony_ci return drm_dp_mst_topology_mgr_init(&radeon_connector->mst_mgr, dev, 6398c2ecf20Sopenharmony_ci &radeon_connector->ddc_bus->aux, 16, 6, 6408c2ecf20Sopenharmony_ci radeon_connector->base.base.id); 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ciint 6448c2ecf20Sopenharmony_ciradeon_dp_mst_probe(struct radeon_connector *radeon_connector) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; 6478c2ecf20Sopenharmony_ci struct drm_device *dev = radeon_connector->base.dev; 6488c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 6498c2ecf20Sopenharmony_ci int ret; 6508c2ecf20Sopenharmony_ci u8 msg[1]; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci if (!radeon_mst) 6538c2ecf20Sopenharmony_ci return 0; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci if (!ASIC_IS_DCE5(rdev)) 6568c2ecf20Sopenharmony_ci return 0; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci if (dig_connector->dpcd[DP_DPCD_REV] < 0x12) 6598c2ecf20Sopenharmony_ci return 0; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_MSTM_CAP, msg, 6628c2ecf20Sopenharmony_ci 1); 6638c2ecf20Sopenharmony_ci if (ret) { 6648c2ecf20Sopenharmony_ci if (msg[0] & DP_MST_CAP) { 6658c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Sink is MST capable\n"); 6668c2ecf20Sopenharmony_ci dig_connector->is_mst = true; 6678c2ecf20Sopenharmony_ci } else { 6688c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Sink is not MST capable\n"); 6698c2ecf20Sopenharmony_ci dig_connector->is_mst = false; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci drm_dp_mst_topology_mgr_set_mst(&radeon_connector->mst_mgr, 6748c2ecf20Sopenharmony_ci dig_connector->is_mst); 6758c2ecf20Sopenharmony_ci return dig_connector->is_mst; 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ciint 6798c2ecf20Sopenharmony_ciradeon_dp_mst_check_status(struct radeon_connector *radeon_connector) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; 6828c2ecf20Sopenharmony_ci int retry; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (dig_connector->is_mst) { 6858c2ecf20Sopenharmony_ci u8 esi[16] = { 0 }; 6868c2ecf20Sopenharmony_ci int dret; 6878c2ecf20Sopenharmony_ci int ret = 0; 6888c2ecf20Sopenharmony_ci bool handled; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci dret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, 6918c2ecf20Sopenharmony_ci DP_SINK_COUNT_ESI, esi, 8); 6928c2ecf20Sopenharmony_cigo_again: 6938c2ecf20Sopenharmony_ci if (dret == 8) { 6948c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("got esi %3ph\n", esi); 6958c2ecf20Sopenharmony_ci ret = drm_dp_mst_hpd_irq(&radeon_connector->mst_mgr, esi, &handled); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (handled) { 6988c2ecf20Sopenharmony_ci for (retry = 0; retry < 3; retry++) { 6998c2ecf20Sopenharmony_ci int wret; 7008c2ecf20Sopenharmony_ci wret = drm_dp_dpcd_write(&radeon_connector->ddc_bus->aux, 7018c2ecf20Sopenharmony_ci DP_SINK_COUNT_ESI + 1, &esi[1], 3); 7028c2ecf20Sopenharmony_ci if (wret == 3) 7038c2ecf20Sopenharmony_ci break; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci dret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, 7078c2ecf20Sopenharmony_ci DP_SINK_COUNT_ESI, esi, 8); 7088c2ecf20Sopenharmony_ci if (dret == 8) { 7098c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("got esi2 %3ph\n", esi); 7108c2ecf20Sopenharmony_ci goto go_again; 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci } else 7138c2ecf20Sopenharmony_ci ret = 0; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci return ret; 7168c2ecf20Sopenharmony_ci } else { 7178c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("failed to get ESI - device may have failed %d\n", ret); 7188c2ecf20Sopenharmony_ci dig_connector->is_mst = false; 7198c2ecf20Sopenharmony_ci drm_dp_mst_topology_mgr_set_mst(&radeon_connector->mst_mgr, 7208c2ecf20Sopenharmony_ci dig_connector->is_mst); 7218c2ecf20Sopenharmony_ci /* send a hotplug event */ 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci return -EINVAL; 7258c2ecf20Sopenharmony_ci} 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cistatic int radeon_debugfs_mst_info(struct seq_file *m, void *data) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci struct drm_info_node *node = (struct drm_info_node *)m->private; 7328c2ecf20Sopenharmony_ci struct drm_device *dev = node->minor->dev; 7338c2ecf20Sopenharmony_ci struct drm_connector *connector; 7348c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector; 7358c2ecf20Sopenharmony_ci struct radeon_connector_atom_dig *dig_connector; 7368c2ecf20Sopenharmony_ci int i; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci drm_modeset_lock_all(dev); 7398c2ecf20Sopenharmony_ci list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 7408c2ecf20Sopenharmony_ci if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) 7418c2ecf20Sopenharmony_ci continue; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci radeon_connector = to_radeon_connector(connector); 7448c2ecf20Sopenharmony_ci dig_connector = radeon_connector->con_priv; 7458c2ecf20Sopenharmony_ci if (radeon_connector->is_mst_connector) 7468c2ecf20Sopenharmony_ci continue; 7478c2ecf20Sopenharmony_ci if (!dig_connector->is_mst) 7488c2ecf20Sopenharmony_ci continue; 7498c2ecf20Sopenharmony_ci drm_dp_mst_dump_topology(m, &radeon_connector->mst_mgr); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci for (i = 0; i < radeon_connector->enabled_attribs; i++) 7528c2ecf20Sopenharmony_ci seq_printf(m, "attrib %d: %d %d\n", i, 7538c2ecf20Sopenharmony_ci radeon_connector->cur_stream_attribs[i].fe, 7548c2ecf20Sopenharmony_ci radeon_connector->cur_stream_attribs[i].slots); 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci drm_modeset_unlock_all(dev); 7578c2ecf20Sopenharmony_ci return 0; 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cistatic struct drm_info_list radeon_debugfs_mst_list[] = { 7618c2ecf20Sopenharmony_ci {"radeon_mst_info", &radeon_debugfs_mst_info, 0, NULL}, 7628c2ecf20Sopenharmony_ci}; 7638c2ecf20Sopenharmony_ci#endif 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ciint radeon_mst_debugfs_init(struct radeon_device *rdev) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 7688c2ecf20Sopenharmony_ci return radeon_debugfs_add_files(rdev, radeon_debugfs_mst_list, 1); 7698c2ecf20Sopenharmony_ci#endif 7708c2ecf20Sopenharmony_ci return 0; 7718c2ecf20Sopenharmony_ci} 772