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