18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include "dp_panel.h" 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <drm/drm_connector.h> 98c2ecf20Sopenharmony_ci#include <drm/drm_edid.h> 108c2ecf20Sopenharmony_ci#include <drm/drm_print.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistruct dp_panel_private { 138c2ecf20Sopenharmony_ci struct device *dev; 148c2ecf20Sopenharmony_ci struct dp_panel dp_panel; 158c2ecf20Sopenharmony_ci struct drm_dp_aux *aux; 168c2ecf20Sopenharmony_ci struct dp_link *link; 178c2ecf20Sopenharmony_ci struct dp_catalog *catalog; 188c2ecf20Sopenharmony_ci bool panel_on; 198c2ecf20Sopenharmony_ci bool aux_cfg_update_done; 208c2ecf20Sopenharmony_ci}; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic int dp_panel_read_dpcd(struct dp_panel *dp_panel) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci int rc = 0; 258c2ecf20Sopenharmony_ci size_t len; 268c2ecf20Sopenharmony_ci ssize_t rlen; 278c2ecf20Sopenharmony_ci struct dp_panel_private *panel; 288c2ecf20Sopenharmony_ci struct dp_link_info *link_info; 298c2ecf20Sopenharmony_ci u8 *dpcd, major = 0, minor = 0, temp; 308c2ecf20Sopenharmony_ci u32 offset = DP_DPCD_REV; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci dpcd = dp_panel->dpcd; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci panel = container_of(dp_panel, struct dp_panel_private, dp_panel); 358c2ecf20Sopenharmony_ci link_info = &dp_panel->link_info; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci rlen = drm_dp_dpcd_read(panel->aux, offset, 388c2ecf20Sopenharmony_ci dpcd, (DP_RECEIVER_CAP_SIZE + 1)); 398c2ecf20Sopenharmony_ci if (rlen < (DP_RECEIVER_CAP_SIZE + 1)) { 408c2ecf20Sopenharmony_ci DRM_ERROR("dpcd read failed, rlen=%zd\n", rlen); 418c2ecf20Sopenharmony_ci if (rlen == -ETIMEDOUT) 428c2ecf20Sopenharmony_ci rc = rlen; 438c2ecf20Sopenharmony_ci else 448c2ecf20Sopenharmony_ci rc = -EINVAL; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci goto end; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci temp = dpcd[DP_TRAINING_AUX_RD_INTERVAL]; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci /* check for EXTENDED_RECEIVER_CAPABILITY_FIELD_PRESENT */ 528c2ecf20Sopenharmony_ci if (temp & BIT(7)) { 538c2ecf20Sopenharmony_ci DRM_DEBUG_DP("using EXTENDED_RECEIVER_CAPABILITY_FIELD\n"); 548c2ecf20Sopenharmony_ci offset = DPRX_EXTENDED_DPCD_FIELD; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci rlen = drm_dp_dpcd_read(panel->aux, offset, 588c2ecf20Sopenharmony_ci dpcd, (DP_RECEIVER_CAP_SIZE + 1)); 598c2ecf20Sopenharmony_ci if (rlen < (DP_RECEIVER_CAP_SIZE + 1)) { 608c2ecf20Sopenharmony_ci DRM_ERROR("dpcd read failed, rlen=%zd\n", rlen); 618c2ecf20Sopenharmony_ci if (rlen == -ETIMEDOUT) 628c2ecf20Sopenharmony_ci rc = rlen; 638c2ecf20Sopenharmony_ci else 648c2ecf20Sopenharmony_ci rc = -EINVAL; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci goto end; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci link_info->revision = dpcd[DP_DPCD_REV]; 708c2ecf20Sopenharmony_ci major = (link_info->revision >> 4) & 0x0f; 718c2ecf20Sopenharmony_ci minor = link_info->revision & 0x0f; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci link_info->rate = drm_dp_bw_code_to_link_rate(dpcd[DP_MAX_LINK_RATE]); 748c2ecf20Sopenharmony_ci link_info->num_lanes = dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (link_info->num_lanes > dp_panel->max_dp_lanes) 778c2ecf20Sopenharmony_ci link_info->num_lanes = dp_panel->max_dp_lanes; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci /* Limit support upto HBR2 until HBR3 support is added */ 808c2ecf20Sopenharmony_ci if (link_info->rate >= (drm_dp_bw_code_to_link_rate(DP_LINK_BW_5_4))) 818c2ecf20Sopenharmony_ci link_info->rate = drm_dp_bw_code_to_link_rate(DP_LINK_BW_5_4); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci DRM_DEBUG_DP("version: %d.%d\n", major, minor); 848c2ecf20Sopenharmony_ci DRM_DEBUG_DP("link_rate=%d\n", link_info->rate); 858c2ecf20Sopenharmony_ci DRM_DEBUG_DP("lane_count=%d\n", link_info->num_lanes); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (drm_dp_enhanced_frame_cap(dpcd)) 888c2ecf20Sopenharmony_ci link_info->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci dp_panel->dfp_present = dpcd[DP_DOWNSTREAMPORT_PRESENT]; 918c2ecf20Sopenharmony_ci dp_panel->dfp_present &= DP_DWN_STRM_PORT_PRESENT; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (dp_panel->dfp_present && (dpcd[DP_DPCD_REV] > 0x10)) { 948c2ecf20Sopenharmony_ci dp_panel->ds_port_cnt = dpcd[DP_DOWN_STREAM_PORT_COUNT]; 958c2ecf20Sopenharmony_ci dp_panel->ds_port_cnt &= DP_PORT_COUNT_MASK; 968c2ecf20Sopenharmony_ci len = DP_DOWNSTREAM_PORTS * DP_DOWNSTREAM_CAP_SIZE; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci rlen = drm_dp_dpcd_read(panel->aux, 998c2ecf20Sopenharmony_ci DP_DOWNSTREAM_PORT_0, dp_panel->ds_cap_info, len); 1008c2ecf20Sopenharmony_ci if (rlen < len) { 1018c2ecf20Sopenharmony_ci DRM_ERROR("ds port status failed, rlen=%zd\n", rlen); 1028c2ecf20Sopenharmony_ci rc = -EINVAL; 1038c2ecf20Sopenharmony_ci goto end; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ciend: 1088c2ecf20Sopenharmony_ci return rc; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic u32 dp_panel_get_supported_bpp(struct dp_panel *dp_panel, 1128c2ecf20Sopenharmony_ci u32 mode_edid_bpp, u32 mode_pclk_khz) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct dp_link_info *link_info; 1158c2ecf20Sopenharmony_ci const u32 max_supported_bpp = 30, min_supported_bpp = 18; 1168c2ecf20Sopenharmony_ci u32 bpp = 0, data_rate_khz = 0; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci bpp = min_t(u32, mode_edid_bpp, max_supported_bpp); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci link_info = &dp_panel->link_info; 1218c2ecf20Sopenharmony_ci data_rate_khz = link_info->num_lanes * link_info->rate * 8; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci while (bpp > min_supported_bpp) { 1248c2ecf20Sopenharmony_ci if (mode_pclk_khz * bpp <= data_rate_khz) 1258c2ecf20Sopenharmony_ci break; 1268c2ecf20Sopenharmony_ci bpp -= 6; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci return bpp; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int dp_panel_update_modes(struct drm_connector *connector, 1338c2ecf20Sopenharmony_ci struct edid *edid) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci int rc = 0; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (edid) { 1388c2ecf20Sopenharmony_ci rc = drm_connector_update_edid_property(connector, edid); 1398c2ecf20Sopenharmony_ci if (rc) { 1408c2ecf20Sopenharmony_ci DRM_ERROR("failed to update edid property %d\n", rc); 1418c2ecf20Sopenharmony_ci return rc; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci rc = drm_add_edid_modes(connector, edid); 1448c2ecf20Sopenharmony_ci DRM_DEBUG_DP("%s -", __func__); 1458c2ecf20Sopenharmony_ci return rc; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci rc = drm_connector_update_edid_property(connector, NULL); 1498c2ecf20Sopenharmony_ci if (rc) 1508c2ecf20Sopenharmony_ci DRM_ERROR("failed to update edid property %d\n", rc); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return rc; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ciint dp_panel_read_sink_caps(struct dp_panel *dp_panel, 1568c2ecf20Sopenharmony_ci struct drm_connector *connector) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci int rc = 0, bw_code; 1598c2ecf20Sopenharmony_ci int rlen, count; 1608c2ecf20Sopenharmony_ci struct dp_panel_private *panel; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (!dp_panel || !connector) { 1638c2ecf20Sopenharmony_ci DRM_ERROR("invalid input\n"); 1648c2ecf20Sopenharmony_ci return -EINVAL; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci panel = container_of(dp_panel, struct dp_panel_private, dp_panel); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci rc = dp_panel_read_dpcd(dp_panel); 1708c2ecf20Sopenharmony_ci bw_code = drm_dp_link_rate_to_bw_code(dp_panel->link_info.rate); 1718c2ecf20Sopenharmony_ci if (rc || !is_link_rate_valid(bw_code) || 1728c2ecf20Sopenharmony_ci !is_lane_count_valid(dp_panel->link_info.num_lanes) || 1738c2ecf20Sopenharmony_ci (bw_code > dp_panel->max_bw_code)) { 1748c2ecf20Sopenharmony_ci DRM_ERROR("read dpcd failed %d\n", rc); 1758c2ecf20Sopenharmony_ci return rc; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (dp_panel->dfp_present) { 1798c2ecf20Sopenharmony_ci rlen = drm_dp_dpcd_read(panel->aux, DP_SINK_COUNT, 1808c2ecf20Sopenharmony_ci &count, 1); 1818c2ecf20Sopenharmony_ci if (rlen == 1) { 1828c2ecf20Sopenharmony_ci count = DP_GET_SINK_COUNT(count); 1838c2ecf20Sopenharmony_ci if (!count) { 1848c2ecf20Sopenharmony_ci DRM_ERROR("no downstream ports connected\n"); 1858c2ecf20Sopenharmony_ci panel->link->sink_count = 0; 1868c2ecf20Sopenharmony_ci rc = -ENOTCONN; 1878c2ecf20Sopenharmony_ci goto end; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci kfree(dp_panel->edid); 1938c2ecf20Sopenharmony_ci dp_panel->edid = NULL; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci dp_panel->edid = drm_get_edid(connector, 1968c2ecf20Sopenharmony_ci &panel->aux->ddc); 1978c2ecf20Sopenharmony_ci if (!dp_panel->edid) { 1988c2ecf20Sopenharmony_ci DRM_ERROR("panel edid read failed\n"); 1998c2ecf20Sopenharmony_ci /* check edid read fail is due to unplug */ 2008c2ecf20Sopenharmony_ci if (!dp_catalog_link_is_connected(panel->catalog)) { 2018c2ecf20Sopenharmony_ci rc = -ETIMEDOUT; 2028c2ecf20Sopenharmony_ci goto end; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci /* fail safe edid */ 2068c2ecf20Sopenharmony_ci mutex_lock(&connector->dev->mode_config.mutex); 2078c2ecf20Sopenharmony_ci if (drm_add_modes_noedid(connector, 640, 480)) 2088c2ecf20Sopenharmony_ci drm_set_preferred_mode(connector, 640, 480); 2098c2ecf20Sopenharmony_ci mutex_unlock(&connector->dev->mode_config.mutex); 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (panel->aux_cfg_update_done) { 2138c2ecf20Sopenharmony_ci DRM_DEBUG_DP("read DPCD with updated AUX config\n"); 2148c2ecf20Sopenharmony_ci rc = dp_panel_read_dpcd(dp_panel); 2158c2ecf20Sopenharmony_ci bw_code = drm_dp_link_rate_to_bw_code(dp_panel->link_info.rate); 2168c2ecf20Sopenharmony_ci if (rc || !is_link_rate_valid(bw_code) || 2178c2ecf20Sopenharmony_ci !is_lane_count_valid(dp_panel->link_info.num_lanes) 2188c2ecf20Sopenharmony_ci || (bw_code > dp_panel->max_bw_code)) { 2198c2ecf20Sopenharmony_ci DRM_ERROR("read dpcd failed %d\n", rc); 2208c2ecf20Sopenharmony_ci return rc; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci panel->aux_cfg_update_done = false; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ciend: 2258c2ecf20Sopenharmony_ci return rc; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ciu32 dp_panel_get_mode_bpp(struct dp_panel *dp_panel, 2298c2ecf20Sopenharmony_ci u32 mode_edid_bpp, u32 mode_pclk_khz) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci struct dp_panel_private *panel; 2328c2ecf20Sopenharmony_ci u32 bpp = mode_edid_bpp; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (!dp_panel || !mode_edid_bpp || !mode_pclk_khz) { 2358c2ecf20Sopenharmony_ci DRM_ERROR("invalid input\n"); 2368c2ecf20Sopenharmony_ci return 0; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci panel = container_of(dp_panel, struct dp_panel_private, dp_panel); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (dp_panel->video_test) 2428c2ecf20Sopenharmony_ci bpp = dp_link_bit_depth_to_bpp( 2438c2ecf20Sopenharmony_ci panel->link->test_video.test_bit_depth); 2448c2ecf20Sopenharmony_ci else 2458c2ecf20Sopenharmony_ci bpp = dp_panel_get_supported_bpp(dp_panel, mode_edid_bpp, 2468c2ecf20Sopenharmony_ci mode_pclk_khz); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return bpp; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ciint dp_panel_get_modes(struct dp_panel *dp_panel, 2528c2ecf20Sopenharmony_ci struct drm_connector *connector, struct dp_display_mode *mode) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci if (!dp_panel) { 2558c2ecf20Sopenharmony_ci DRM_ERROR("invalid input\n"); 2568c2ecf20Sopenharmony_ci return -EINVAL; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (dp_panel->edid) 2608c2ecf20Sopenharmony_ci return dp_panel_update_modes(connector, dp_panel->edid); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci return 0; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic u8 dp_panel_get_edid_checksum(struct edid *edid) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci edid += edid->extensions; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return edid->checksum; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_civoid dp_panel_handle_sink_request(struct dp_panel *dp_panel) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct dp_panel_private *panel; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (!dp_panel) { 2778c2ecf20Sopenharmony_ci DRM_ERROR("invalid input\n"); 2788c2ecf20Sopenharmony_ci return; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci panel = container_of(dp_panel, struct dp_panel_private, dp_panel); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (panel->link->sink_request & DP_TEST_LINK_EDID_READ) { 2848c2ecf20Sopenharmony_ci u8 checksum; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (dp_panel->edid) 2878c2ecf20Sopenharmony_ci checksum = dp_panel_get_edid_checksum(dp_panel->edid); 2888c2ecf20Sopenharmony_ci else 2898c2ecf20Sopenharmony_ci checksum = dp_panel->connector->real_edid_checksum; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci dp_link_send_edid_checksum(panel->link, checksum); 2928c2ecf20Sopenharmony_ci dp_link_send_test_response(panel->link); 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_civoid dp_panel_tpg_config(struct dp_panel *dp_panel, bool enable) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci struct dp_catalog *catalog; 2998c2ecf20Sopenharmony_ci struct dp_panel_private *panel; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (!dp_panel) { 3028c2ecf20Sopenharmony_ci DRM_ERROR("invalid input\n"); 3038c2ecf20Sopenharmony_ci return; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci panel = container_of(dp_panel, struct dp_panel_private, dp_panel); 3078c2ecf20Sopenharmony_ci catalog = panel->catalog; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (!panel->panel_on) { 3108c2ecf20Sopenharmony_ci DRM_DEBUG_DP("DP panel not enabled, handle TPG on next on\n"); 3118c2ecf20Sopenharmony_ci return; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (!enable) { 3158c2ecf20Sopenharmony_ci dp_catalog_panel_tpg_disable(catalog); 3168c2ecf20Sopenharmony_ci return; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci DRM_DEBUG_DP("%s: calling catalog tpg_enable\n", __func__); 3208c2ecf20Sopenharmony_ci dp_catalog_panel_tpg_enable(catalog, &panel->dp_panel.dp_mode.drm_mode); 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_civoid dp_panel_dump_regs(struct dp_panel *dp_panel) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct dp_catalog *catalog; 3268c2ecf20Sopenharmony_ci struct dp_panel_private *panel; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci panel = container_of(dp_panel, struct dp_panel_private, dp_panel); 3298c2ecf20Sopenharmony_ci catalog = panel->catalog; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci dp_catalog_dump_regs(catalog); 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ciint dp_panel_timing_cfg(struct dp_panel *dp_panel) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci int rc = 0; 3378c2ecf20Sopenharmony_ci u32 data, total_ver, total_hor; 3388c2ecf20Sopenharmony_ci struct dp_catalog *catalog; 3398c2ecf20Sopenharmony_ci struct dp_panel_private *panel; 3408c2ecf20Sopenharmony_ci struct drm_display_mode *drm_mode; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci panel = container_of(dp_panel, struct dp_panel_private, dp_panel); 3438c2ecf20Sopenharmony_ci catalog = panel->catalog; 3448c2ecf20Sopenharmony_ci drm_mode = &panel->dp_panel.dp_mode.drm_mode; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci DRM_DEBUG_DP("width=%d hporch= %d %d %d\n", 3478c2ecf20Sopenharmony_ci drm_mode->hdisplay, drm_mode->htotal - drm_mode->hsync_end, 3488c2ecf20Sopenharmony_ci drm_mode->hsync_start - drm_mode->hdisplay, 3498c2ecf20Sopenharmony_ci drm_mode->hsync_end - drm_mode->hsync_start); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci DRM_DEBUG_DP("height=%d vporch= %d %d %d\n", 3528c2ecf20Sopenharmony_ci drm_mode->vdisplay, drm_mode->vtotal - drm_mode->vsync_end, 3538c2ecf20Sopenharmony_ci drm_mode->vsync_start - drm_mode->vdisplay, 3548c2ecf20Sopenharmony_ci drm_mode->vsync_end - drm_mode->vsync_start); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci total_hor = drm_mode->htotal; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci total_ver = drm_mode->vtotal; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci data = total_ver; 3618c2ecf20Sopenharmony_ci data <<= 16; 3628c2ecf20Sopenharmony_ci data |= total_hor; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci catalog->total = data; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci data = (drm_mode->vtotal - drm_mode->vsync_start); 3678c2ecf20Sopenharmony_ci data <<= 16; 3688c2ecf20Sopenharmony_ci data |= (drm_mode->htotal - drm_mode->hsync_start); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci catalog->sync_start = data; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci data = drm_mode->vsync_end - drm_mode->vsync_start; 3738c2ecf20Sopenharmony_ci data <<= 16; 3748c2ecf20Sopenharmony_ci data |= (panel->dp_panel.dp_mode.v_active_low << 31); 3758c2ecf20Sopenharmony_ci data |= drm_mode->hsync_end - drm_mode->hsync_start; 3768c2ecf20Sopenharmony_ci data |= (panel->dp_panel.dp_mode.h_active_low << 15); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci catalog->width_blanking = data; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci data = drm_mode->vdisplay; 3818c2ecf20Sopenharmony_ci data <<= 16; 3828c2ecf20Sopenharmony_ci data |= drm_mode->hdisplay; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci catalog->dp_active = data; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci dp_catalog_panel_timing_cfg(catalog); 3878c2ecf20Sopenharmony_ci panel->panel_on = true; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci return rc; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ciint dp_panel_init_panel_info(struct dp_panel *dp_panel) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci int rc = 0; 3958c2ecf20Sopenharmony_ci struct drm_display_mode *drm_mode; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci drm_mode = &dp_panel->dp_mode.drm_mode; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* 4008c2ecf20Sopenharmony_ci * print resolution info as this is a result 4018c2ecf20Sopenharmony_ci * of user initiated action of cable connection 4028c2ecf20Sopenharmony_ci */ 4038c2ecf20Sopenharmony_ci DRM_DEBUG_DP("SET NEW RESOLUTION:\n"); 4048c2ecf20Sopenharmony_ci DRM_DEBUG_DP("%dx%d@%dfps\n", drm_mode->hdisplay, 4058c2ecf20Sopenharmony_ci drm_mode->vdisplay, drm_mode_vrefresh(drm_mode)); 4068c2ecf20Sopenharmony_ci DRM_DEBUG_DP("h_porches(back|front|width) = (%d|%d|%d)\n", 4078c2ecf20Sopenharmony_ci drm_mode->htotal - drm_mode->hsync_end, 4088c2ecf20Sopenharmony_ci drm_mode->hsync_start - drm_mode->hdisplay, 4098c2ecf20Sopenharmony_ci drm_mode->hsync_end - drm_mode->hsync_start); 4108c2ecf20Sopenharmony_ci DRM_DEBUG_DP("v_porches(back|front|width) = (%d|%d|%d)\n", 4118c2ecf20Sopenharmony_ci drm_mode->vtotal - drm_mode->vsync_end, 4128c2ecf20Sopenharmony_ci drm_mode->vsync_start - drm_mode->vdisplay, 4138c2ecf20Sopenharmony_ci drm_mode->vsync_end - drm_mode->vsync_start); 4148c2ecf20Sopenharmony_ci DRM_DEBUG_DP("pixel clock (KHz)=(%d)\n", drm_mode->clock); 4158c2ecf20Sopenharmony_ci DRM_DEBUG_DP("bpp = %d\n", dp_panel->dp_mode.bpp); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci dp_panel->dp_mode.bpp = max_t(u32, 18, 4188c2ecf20Sopenharmony_ci min_t(u32, dp_panel->dp_mode.bpp, 30)); 4198c2ecf20Sopenharmony_ci DRM_DEBUG_DP("updated bpp = %d\n", dp_panel->dp_mode.bpp); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci return rc; 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistruct dp_panel *dp_panel_get(struct dp_panel_in *in) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci struct dp_panel_private *panel; 4278c2ecf20Sopenharmony_ci struct dp_panel *dp_panel; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (!in->dev || !in->catalog || !in->aux || !in->link) { 4308c2ecf20Sopenharmony_ci DRM_ERROR("invalid input\n"); 4318c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci panel = devm_kzalloc(in->dev, sizeof(*panel), GFP_KERNEL); 4358c2ecf20Sopenharmony_ci if (!panel) 4368c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci panel->dev = in->dev; 4398c2ecf20Sopenharmony_ci panel->aux = in->aux; 4408c2ecf20Sopenharmony_ci panel->catalog = in->catalog; 4418c2ecf20Sopenharmony_ci panel->link = in->link; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci dp_panel = &panel->dp_panel; 4448c2ecf20Sopenharmony_ci dp_panel->max_bw_code = DP_LINK_BW_8_1; 4458c2ecf20Sopenharmony_ci panel->aux_cfg_update_done = false; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci return dp_panel; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_civoid dp_panel_put(struct dp_panel *dp_panel) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci if (!dp_panel) 4538c2ecf20Sopenharmony_ci return; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci kfree(dp_panel->edid); 4568c2ecf20Sopenharmony_ci} 457