162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include "dp_panel.h" 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <drm/drm_connector.h> 962306a36Sopenharmony_ci#include <drm/drm_edid.h> 1062306a36Sopenharmony_ci#include <drm/drm_print.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistruct dp_panel_private { 1362306a36Sopenharmony_ci struct device *dev; 1462306a36Sopenharmony_ci struct drm_device *drm_dev; 1562306a36Sopenharmony_ci struct dp_panel dp_panel; 1662306a36Sopenharmony_ci struct drm_dp_aux *aux; 1762306a36Sopenharmony_ci struct dp_link *link; 1862306a36Sopenharmony_ci struct dp_catalog *catalog; 1962306a36Sopenharmony_ci bool panel_on; 2062306a36Sopenharmony_ci bool aux_cfg_update_done; 2162306a36Sopenharmony_ci}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic void dp_panel_read_psr_cap(struct dp_panel_private *panel) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci ssize_t rlen; 2662306a36Sopenharmony_ci struct dp_panel *dp_panel; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci dp_panel = &panel->dp_panel; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci /* edp sink */ 3162306a36Sopenharmony_ci if (dp_panel->dpcd[DP_EDP_CONFIGURATION_CAP]) { 3262306a36Sopenharmony_ci rlen = drm_dp_dpcd_read(panel->aux, DP_PSR_SUPPORT, 3362306a36Sopenharmony_ci &dp_panel->psr_cap, sizeof(dp_panel->psr_cap)); 3462306a36Sopenharmony_ci if (rlen == sizeof(dp_panel->psr_cap)) { 3562306a36Sopenharmony_ci drm_dbg_dp(panel->drm_dev, 3662306a36Sopenharmony_ci "psr version: 0x%x, psr_cap: 0x%x\n", 3762306a36Sopenharmony_ci dp_panel->psr_cap.version, 3862306a36Sopenharmony_ci dp_panel->psr_cap.capabilities); 3962306a36Sopenharmony_ci } else 4062306a36Sopenharmony_ci DRM_ERROR("failed to read psr info, rlen=%zd\n", rlen); 4162306a36Sopenharmony_ci } 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic int dp_panel_read_dpcd(struct dp_panel *dp_panel) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci int rc = 0; 4762306a36Sopenharmony_ci size_t len; 4862306a36Sopenharmony_ci ssize_t rlen; 4962306a36Sopenharmony_ci struct dp_panel_private *panel; 5062306a36Sopenharmony_ci struct dp_link_info *link_info; 5162306a36Sopenharmony_ci u8 *dpcd, major = 0, minor = 0, temp; 5262306a36Sopenharmony_ci u32 offset = DP_DPCD_REV; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci dpcd = dp_panel->dpcd; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci panel = container_of(dp_panel, struct dp_panel_private, dp_panel); 5762306a36Sopenharmony_ci link_info = &dp_panel->link_info; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci rlen = drm_dp_dpcd_read(panel->aux, offset, 6062306a36Sopenharmony_ci dpcd, (DP_RECEIVER_CAP_SIZE + 1)); 6162306a36Sopenharmony_ci if (rlen < (DP_RECEIVER_CAP_SIZE + 1)) { 6262306a36Sopenharmony_ci DRM_ERROR("dpcd read failed, rlen=%zd\n", rlen); 6362306a36Sopenharmony_ci if (rlen == -ETIMEDOUT) 6462306a36Sopenharmony_ci rc = rlen; 6562306a36Sopenharmony_ci else 6662306a36Sopenharmony_ci rc = -EINVAL; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci goto end; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci temp = dpcd[DP_TRAINING_AUX_RD_INTERVAL]; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci /* check for EXTENDED_RECEIVER_CAPABILITY_FIELD_PRESENT */ 7462306a36Sopenharmony_ci if (temp & BIT(7)) { 7562306a36Sopenharmony_ci drm_dbg_dp(panel->drm_dev, 7662306a36Sopenharmony_ci "using EXTENDED_RECEIVER_CAPABILITY_FIELD\n"); 7762306a36Sopenharmony_ci offset = DPRX_EXTENDED_DPCD_FIELD; 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci rlen = drm_dp_dpcd_read(panel->aux, offset, 8162306a36Sopenharmony_ci dpcd, (DP_RECEIVER_CAP_SIZE + 1)); 8262306a36Sopenharmony_ci if (rlen < (DP_RECEIVER_CAP_SIZE + 1)) { 8362306a36Sopenharmony_ci DRM_ERROR("dpcd read failed, rlen=%zd\n", rlen); 8462306a36Sopenharmony_ci if (rlen == -ETIMEDOUT) 8562306a36Sopenharmony_ci rc = rlen; 8662306a36Sopenharmony_ci else 8762306a36Sopenharmony_ci rc = -EINVAL; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci goto end; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci link_info->revision = dpcd[DP_DPCD_REV]; 9362306a36Sopenharmony_ci major = (link_info->revision >> 4) & 0x0f; 9462306a36Sopenharmony_ci minor = link_info->revision & 0x0f; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci link_info->rate = drm_dp_bw_code_to_link_rate(dpcd[DP_MAX_LINK_RATE]); 9762306a36Sopenharmony_ci link_info->num_lanes = dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* Limit data lanes from data-lanes of endpoint property of dtsi */ 10062306a36Sopenharmony_ci if (link_info->num_lanes > dp_panel->max_dp_lanes) 10162306a36Sopenharmony_ci link_info->num_lanes = dp_panel->max_dp_lanes; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci /* Limit link rate from link-frequencies of endpoint property of dtsi */ 10462306a36Sopenharmony_ci if (link_info->rate > dp_panel->max_dp_link_rate) 10562306a36Sopenharmony_ci link_info->rate = dp_panel->max_dp_link_rate; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci drm_dbg_dp(panel->drm_dev, "version: %d.%d\n", major, minor); 10862306a36Sopenharmony_ci drm_dbg_dp(panel->drm_dev, "link_rate=%d\n", link_info->rate); 10962306a36Sopenharmony_ci drm_dbg_dp(panel->drm_dev, "lane_count=%d\n", link_info->num_lanes); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (drm_dp_enhanced_frame_cap(dpcd)) 11262306a36Sopenharmony_ci link_info->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci dp_panel->dfp_present = dpcd[DP_DOWNSTREAMPORT_PRESENT]; 11562306a36Sopenharmony_ci dp_panel->dfp_present &= DP_DWN_STRM_PORT_PRESENT; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if (dp_panel->dfp_present && (dpcd[DP_DPCD_REV] > 0x10)) { 11862306a36Sopenharmony_ci dp_panel->ds_port_cnt = dpcd[DP_DOWN_STREAM_PORT_COUNT]; 11962306a36Sopenharmony_ci dp_panel->ds_port_cnt &= DP_PORT_COUNT_MASK; 12062306a36Sopenharmony_ci len = DP_DOWNSTREAM_PORTS * DP_DOWNSTREAM_CAP_SIZE; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci rlen = drm_dp_dpcd_read(panel->aux, 12362306a36Sopenharmony_ci DP_DOWNSTREAM_PORT_0, dp_panel->ds_cap_info, len); 12462306a36Sopenharmony_ci if (rlen < len) { 12562306a36Sopenharmony_ci DRM_ERROR("ds port status failed, rlen=%zd\n", rlen); 12662306a36Sopenharmony_ci rc = -EINVAL; 12762306a36Sopenharmony_ci goto end; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci dp_panel_read_psr_cap(panel); 13262306a36Sopenharmony_ciend: 13362306a36Sopenharmony_ci return rc; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic u32 dp_panel_get_supported_bpp(struct dp_panel *dp_panel, 13762306a36Sopenharmony_ci u32 mode_edid_bpp, u32 mode_pclk_khz) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci struct dp_link_info *link_info; 14062306a36Sopenharmony_ci const u32 max_supported_bpp = 30, min_supported_bpp = 18; 14162306a36Sopenharmony_ci u32 bpp = 0, data_rate_khz = 0; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci bpp = min_t(u32, mode_edid_bpp, max_supported_bpp); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci link_info = &dp_panel->link_info; 14662306a36Sopenharmony_ci data_rate_khz = link_info->num_lanes * link_info->rate * 8; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci while (bpp > min_supported_bpp) { 14962306a36Sopenharmony_ci if (mode_pclk_khz * bpp <= data_rate_khz) 15062306a36Sopenharmony_ci break; 15162306a36Sopenharmony_ci bpp -= 6; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci return bpp; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic int dp_panel_update_modes(struct drm_connector *connector, 15862306a36Sopenharmony_ci struct edid *edid) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci int rc = 0; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (edid) { 16362306a36Sopenharmony_ci rc = drm_connector_update_edid_property(connector, edid); 16462306a36Sopenharmony_ci if (rc) { 16562306a36Sopenharmony_ci DRM_ERROR("failed to update edid property %d\n", rc); 16662306a36Sopenharmony_ci return rc; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci rc = drm_add_edid_modes(connector, edid); 16962306a36Sopenharmony_ci return rc; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci rc = drm_connector_update_edid_property(connector, NULL); 17362306a36Sopenharmony_ci if (rc) 17462306a36Sopenharmony_ci DRM_ERROR("failed to update edid property %d\n", rc); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci return rc; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ciint dp_panel_read_sink_caps(struct dp_panel *dp_panel, 18062306a36Sopenharmony_ci struct drm_connector *connector) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci int rc = 0, bw_code; 18362306a36Sopenharmony_ci int rlen, count; 18462306a36Sopenharmony_ci struct dp_panel_private *panel; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (!dp_panel || !connector) { 18762306a36Sopenharmony_ci DRM_ERROR("invalid input\n"); 18862306a36Sopenharmony_ci return -EINVAL; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci panel = container_of(dp_panel, struct dp_panel_private, dp_panel); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci rc = dp_panel_read_dpcd(dp_panel); 19462306a36Sopenharmony_ci if (rc) { 19562306a36Sopenharmony_ci DRM_ERROR("read dpcd failed %d\n", rc); 19662306a36Sopenharmony_ci return rc; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci bw_code = drm_dp_link_rate_to_bw_code(dp_panel->link_info.rate); 20062306a36Sopenharmony_ci if (!is_link_rate_valid(bw_code) || 20162306a36Sopenharmony_ci !is_lane_count_valid(dp_panel->link_info.num_lanes) || 20262306a36Sopenharmony_ci (bw_code > dp_panel->max_bw_code)) { 20362306a36Sopenharmony_ci DRM_ERROR("Illegal link rate=%d lane=%d\n", dp_panel->link_info.rate, 20462306a36Sopenharmony_ci dp_panel->link_info.num_lanes); 20562306a36Sopenharmony_ci return -EINVAL; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (dp_panel->dfp_present) { 20962306a36Sopenharmony_ci rlen = drm_dp_dpcd_read(panel->aux, DP_SINK_COUNT, 21062306a36Sopenharmony_ci &count, 1); 21162306a36Sopenharmony_ci if (rlen == 1) { 21262306a36Sopenharmony_ci count = DP_GET_SINK_COUNT(count); 21362306a36Sopenharmony_ci if (!count) { 21462306a36Sopenharmony_ci DRM_ERROR("no downstream ports connected\n"); 21562306a36Sopenharmony_ci panel->link->sink_count = 0; 21662306a36Sopenharmony_ci rc = -ENOTCONN; 21762306a36Sopenharmony_ci goto end; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci kfree(dp_panel->edid); 22362306a36Sopenharmony_ci dp_panel->edid = NULL; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci dp_panel->edid = drm_get_edid(connector, 22662306a36Sopenharmony_ci &panel->aux->ddc); 22762306a36Sopenharmony_ci if (!dp_panel->edid) { 22862306a36Sopenharmony_ci DRM_ERROR("panel edid read failed\n"); 22962306a36Sopenharmony_ci /* check edid read fail is due to unplug */ 23062306a36Sopenharmony_ci if (!dp_catalog_link_is_connected(panel->catalog)) { 23162306a36Sopenharmony_ci rc = -ETIMEDOUT; 23262306a36Sopenharmony_ci goto end; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (panel->aux_cfg_update_done) { 23762306a36Sopenharmony_ci drm_dbg_dp(panel->drm_dev, 23862306a36Sopenharmony_ci "read DPCD with updated AUX config\n"); 23962306a36Sopenharmony_ci rc = dp_panel_read_dpcd(dp_panel); 24062306a36Sopenharmony_ci bw_code = drm_dp_link_rate_to_bw_code(dp_panel->link_info.rate); 24162306a36Sopenharmony_ci if (rc || !is_link_rate_valid(bw_code) || 24262306a36Sopenharmony_ci !is_lane_count_valid(dp_panel->link_info.num_lanes) 24362306a36Sopenharmony_ci || (bw_code > dp_panel->max_bw_code)) { 24462306a36Sopenharmony_ci DRM_ERROR("read dpcd failed %d\n", rc); 24562306a36Sopenharmony_ci return rc; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci panel->aux_cfg_update_done = false; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ciend: 25062306a36Sopenharmony_ci return rc; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ciu32 dp_panel_get_mode_bpp(struct dp_panel *dp_panel, 25462306a36Sopenharmony_ci u32 mode_edid_bpp, u32 mode_pclk_khz) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct dp_panel_private *panel; 25762306a36Sopenharmony_ci u32 bpp; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (!dp_panel || !mode_edid_bpp || !mode_pclk_khz) { 26062306a36Sopenharmony_ci DRM_ERROR("invalid input\n"); 26162306a36Sopenharmony_ci return 0; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci panel = container_of(dp_panel, struct dp_panel_private, dp_panel); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (dp_panel->video_test) 26762306a36Sopenharmony_ci bpp = dp_link_bit_depth_to_bpp( 26862306a36Sopenharmony_ci panel->link->test_video.test_bit_depth); 26962306a36Sopenharmony_ci else 27062306a36Sopenharmony_ci bpp = dp_panel_get_supported_bpp(dp_panel, mode_edid_bpp, 27162306a36Sopenharmony_ci mode_pclk_khz); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci return bpp; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ciint dp_panel_get_modes(struct dp_panel *dp_panel, 27762306a36Sopenharmony_ci struct drm_connector *connector) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci if (!dp_panel) { 28062306a36Sopenharmony_ci DRM_ERROR("invalid input\n"); 28162306a36Sopenharmony_ci return -EINVAL; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (dp_panel->edid) 28562306a36Sopenharmony_ci return dp_panel_update_modes(connector, dp_panel->edid); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci return 0; 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic u8 dp_panel_get_edid_checksum(struct edid *edid) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci edid += edid->extensions; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci return edid->checksum; 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_civoid dp_panel_handle_sink_request(struct dp_panel *dp_panel) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct dp_panel_private *panel; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (!dp_panel) { 30262306a36Sopenharmony_ci DRM_ERROR("invalid input\n"); 30362306a36Sopenharmony_ci return; 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci panel = container_of(dp_panel, struct dp_panel_private, dp_panel); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (panel->link->sink_request & DP_TEST_LINK_EDID_READ) { 30962306a36Sopenharmony_ci u8 checksum; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (dp_panel->edid) 31262306a36Sopenharmony_ci checksum = dp_panel_get_edid_checksum(dp_panel->edid); 31362306a36Sopenharmony_ci else 31462306a36Sopenharmony_ci checksum = dp_panel->connector->real_edid_checksum; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci dp_link_send_edid_checksum(panel->link, checksum); 31762306a36Sopenharmony_ci dp_link_send_test_response(panel->link); 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_civoid dp_panel_tpg_config(struct dp_panel *dp_panel, bool enable) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci struct dp_catalog *catalog; 32462306a36Sopenharmony_ci struct dp_panel_private *panel; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (!dp_panel) { 32762306a36Sopenharmony_ci DRM_ERROR("invalid input\n"); 32862306a36Sopenharmony_ci return; 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci panel = container_of(dp_panel, struct dp_panel_private, dp_panel); 33262306a36Sopenharmony_ci catalog = panel->catalog; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (!panel->panel_on) { 33562306a36Sopenharmony_ci drm_dbg_dp(panel->drm_dev, 33662306a36Sopenharmony_ci "DP panel not enabled, handle TPG on next on\n"); 33762306a36Sopenharmony_ci return; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (!enable) { 34162306a36Sopenharmony_ci dp_catalog_panel_tpg_disable(catalog); 34262306a36Sopenharmony_ci return; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci drm_dbg_dp(panel->drm_dev, "calling catalog tpg_enable\n"); 34662306a36Sopenharmony_ci dp_catalog_panel_tpg_enable(catalog, &panel->dp_panel.dp_mode.drm_mode); 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_civoid dp_panel_dump_regs(struct dp_panel *dp_panel) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci struct dp_catalog *catalog; 35262306a36Sopenharmony_ci struct dp_panel_private *panel; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci panel = container_of(dp_panel, struct dp_panel_private, dp_panel); 35562306a36Sopenharmony_ci catalog = panel->catalog; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci dp_catalog_dump_regs(catalog); 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ciint dp_panel_timing_cfg(struct dp_panel *dp_panel) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci u32 data, total_ver, total_hor; 36362306a36Sopenharmony_ci struct dp_catalog *catalog; 36462306a36Sopenharmony_ci struct dp_panel_private *panel; 36562306a36Sopenharmony_ci struct drm_display_mode *drm_mode; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci panel = container_of(dp_panel, struct dp_panel_private, dp_panel); 36862306a36Sopenharmony_ci catalog = panel->catalog; 36962306a36Sopenharmony_ci drm_mode = &panel->dp_panel.dp_mode.drm_mode; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci drm_dbg_dp(panel->drm_dev, "width=%d hporch= %d %d %d\n", 37262306a36Sopenharmony_ci drm_mode->hdisplay, drm_mode->htotal - drm_mode->hsync_end, 37362306a36Sopenharmony_ci drm_mode->hsync_start - drm_mode->hdisplay, 37462306a36Sopenharmony_ci drm_mode->hsync_end - drm_mode->hsync_start); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci drm_dbg_dp(panel->drm_dev, "height=%d vporch= %d %d %d\n", 37762306a36Sopenharmony_ci drm_mode->vdisplay, drm_mode->vtotal - drm_mode->vsync_end, 37862306a36Sopenharmony_ci drm_mode->vsync_start - drm_mode->vdisplay, 37962306a36Sopenharmony_ci drm_mode->vsync_end - drm_mode->vsync_start); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci total_hor = drm_mode->htotal; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci total_ver = drm_mode->vtotal; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci data = total_ver; 38662306a36Sopenharmony_ci data <<= 16; 38762306a36Sopenharmony_ci data |= total_hor; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci catalog->total = data; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci data = (drm_mode->vtotal - drm_mode->vsync_start); 39262306a36Sopenharmony_ci data <<= 16; 39362306a36Sopenharmony_ci data |= (drm_mode->htotal - drm_mode->hsync_start); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci catalog->sync_start = data; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci data = drm_mode->vsync_end - drm_mode->vsync_start; 39862306a36Sopenharmony_ci data <<= 16; 39962306a36Sopenharmony_ci data |= (panel->dp_panel.dp_mode.v_active_low << 31); 40062306a36Sopenharmony_ci data |= drm_mode->hsync_end - drm_mode->hsync_start; 40162306a36Sopenharmony_ci data |= (panel->dp_panel.dp_mode.h_active_low << 15); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci catalog->width_blanking = data; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci data = drm_mode->vdisplay; 40662306a36Sopenharmony_ci data <<= 16; 40762306a36Sopenharmony_ci data |= drm_mode->hdisplay; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci catalog->dp_active = data; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci dp_catalog_panel_timing_cfg(catalog); 41262306a36Sopenharmony_ci panel->panel_on = true; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci return 0; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ciint dp_panel_init_panel_info(struct dp_panel *dp_panel) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci struct drm_display_mode *drm_mode; 42062306a36Sopenharmony_ci struct dp_panel_private *panel; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci drm_mode = &dp_panel->dp_mode.drm_mode; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci panel = container_of(dp_panel, struct dp_panel_private, dp_panel); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci /* 42762306a36Sopenharmony_ci * print resolution info as this is a result 42862306a36Sopenharmony_ci * of user initiated action of cable connection 42962306a36Sopenharmony_ci */ 43062306a36Sopenharmony_ci drm_dbg_dp(panel->drm_dev, "SET NEW RESOLUTION:\n"); 43162306a36Sopenharmony_ci drm_dbg_dp(panel->drm_dev, "%dx%d@%dfps\n", 43262306a36Sopenharmony_ci drm_mode->hdisplay, drm_mode->vdisplay, drm_mode_vrefresh(drm_mode)); 43362306a36Sopenharmony_ci drm_dbg_dp(panel->drm_dev, 43462306a36Sopenharmony_ci "h_porches(back|front|width) = (%d|%d|%d)\n", 43562306a36Sopenharmony_ci drm_mode->htotal - drm_mode->hsync_end, 43662306a36Sopenharmony_ci drm_mode->hsync_start - drm_mode->hdisplay, 43762306a36Sopenharmony_ci drm_mode->hsync_end - drm_mode->hsync_start); 43862306a36Sopenharmony_ci drm_dbg_dp(panel->drm_dev, 43962306a36Sopenharmony_ci "v_porches(back|front|width) = (%d|%d|%d)\n", 44062306a36Sopenharmony_ci drm_mode->vtotal - drm_mode->vsync_end, 44162306a36Sopenharmony_ci drm_mode->vsync_start - drm_mode->vdisplay, 44262306a36Sopenharmony_ci drm_mode->vsync_end - drm_mode->vsync_start); 44362306a36Sopenharmony_ci drm_dbg_dp(panel->drm_dev, "pixel clock (KHz)=(%d)\n", 44462306a36Sopenharmony_ci drm_mode->clock); 44562306a36Sopenharmony_ci drm_dbg_dp(panel->drm_dev, "bpp = %d\n", dp_panel->dp_mode.bpp); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci dp_panel->dp_mode.bpp = max_t(u32, 18, 44862306a36Sopenharmony_ci min_t(u32, dp_panel->dp_mode.bpp, 30)); 44962306a36Sopenharmony_ci drm_dbg_dp(panel->drm_dev, "updated bpp = %d\n", 45062306a36Sopenharmony_ci dp_panel->dp_mode.bpp); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci return 0; 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistruct dp_panel *dp_panel_get(struct dp_panel_in *in) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci struct dp_panel_private *panel; 45862306a36Sopenharmony_ci struct dp_panel *dp_panel; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci if (!in->dev || !in->catalog || !in->aux || !in->link) { 46162306a36Sopenharmony_ci DRM_ERROR("invalid input\n"); 46262306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci panel = devm_kzalloc(in->dev, sizeof(*panel), GFP_KERNEL); 46662306a36Sopenharmony_ci if (!panel) 46762306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci panel->dev = in->dev; 47062306a36Sopenharmony_ci panel->aux = in->aux; 47162306a36Sopenharmony_ci panel->catalog = in->catalog; 47262306a36Sopenharmony_ci panel->link = in->link; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci dp_panel = &panel->dp_panel; 47562306a36Sopenharmony_ci dp_panel->max_bw_code = DP_LINK_BW_8_1; 47662306a36Sopenharmony_ci panel->aux_cfg_update_done = false; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci return dp_panel; 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_civoid dp_panel_put(struct dp_panel *dp_panel) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci if (!dp_panel) 48462306a36Sopenharmony_ci return; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci kfree(dp_panel->edid); 48762306a36Sopenharmony_ci} 488