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