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#define pr_fmt(fmt)	"[drm-dp] %s: " fmt, __func__
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/types.h>
98c2ecf20Sopenharmony_ci#include <linux/completion.h>
108c2ecf20Sopenharmony_ci#include <linux/delay.h>
118c2ecf20Sopenharmony_ci#include <linux/phy/phy.h>
128c2ecf20Sopenharmony_ci#include <linux/phy/phy-dp.h>
138c2ecf20Sopenharmony_ci#include <drm/drm_fixed.h>
148c2ecf20Sopenharmony_ci#include <drm/drm_dp_helper.h>
158c2ecf20Sopenharmony_ci#include <drm/drm_print.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include "dp_reg.h"
188c2ecf20Sopenharmony_ci#include "dp_ctrl.h"
198c2ecf20Sopenharmony_ci#include "dp_link.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define DP_KHZ_TO_HZ 1000
228c2ecf20Sopenharmony_ci#define IDLE_PATTERN_COMPLETION_TIMEOUT_JIFFIES	(30 * HZ / 1000) /* 30 ms */
238c2ecf20Sopenharmony_ci#define WAIT_FOR_VIDEO_READY_TIMEOUT_JIFFIES (HZ / 2)
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define DP_CTRL_INTR_READY_FOR_VIDEO     BIT(0)
268c2ecf20Sopenharmony_ci#define DP_CTRL_INTR_IDLE_PATTERN_SENT  BIT(3)
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define MR_LINK_TRAINING1  0x8
298c2ecf20Sopenharmony_ci#define MR_LINK_SYMBOL_ERM 0x80
308c2ecf20Sopenharmony_ci#define MR_LINK_PRBS7 0x100
318c2ecf20Sopenharmony_ci#define MR_LINK_CUSTOM80 0x200
328c2ecf20Sopenharmony_ci#define MR_LINK_TRAINING4  0x40
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cienum {
358c2ecf20Sopenharmony_ci	DP_TRAINING_NONE,
368c2ecf20Sopenharmony_ci	DP_TRAINING_1,
378c2ecf20Sopenharmony_ci	DP_TRAINING_2,
388c2ecf20Sopenharmony_ci};
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistruct dp_tu_calc_input {
418c2ecf20Sopenharmony_ci	u64 lclk;        /* 162, 270, 540 and 810 */
428c2ecf20Sopenharmony_ci	u64 pclk_khz;    /* in KHz */
438c2ecf20Sopenharmony_ci	u64 hactive;     /* active h-width */
448c2ecf20Sopenharmony_ci	u64 hporch;      /* bp + fp + pulse */
458c2ecf20Sopenharmony_ci	int nlanes;      /* no.of.lanes */
468c2ecf20Sopenharmony_ci	int bpp;         /* bits */
478c2ecf20Sopenharmony_ci	int pixel_enc;   /* 444, 420, 422 */
488c2ecf20Sopenharmony_ci	int dsc_en;     /* dsc on/off */
498c2ecf20Sopenharmony_ci	int async_en;   /* async mode */
508c2ecf20Sopenharmony_ci	int fec_en;     /* fec */
518c2ecf20Sopenharmony_ci	int compress_ratio; /* 2:1 = 200, 3:1 = 300, 3.75:1 = 375 */
528c2ecf20Sopenharmony_ci	int num_of_dsc_slices; /* number of slices per line */
538c2ecf20Sopenharmony_ci};
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistruct dp_vc_tu_mapping_table {
568c2ecf20Sopenharmony_ci	u32 vic;
578c2ecf20Sopenharmony_ci	u8 lanes;
588c2ecf20Sopenharmony_ci	u8 lrate; /* DP_LINK_RATE -> 162(6), 270(10), 540(20), 810 (30) */
598c2ecf20Sopenharmony_ci	u8 bpp;
608c2ecf20Sopenharmony_ci	u8 valid_boundary_link;
618c2ecf20Sopenharmony_ci	u16 delay_start_link;
628c2ecf20Sopenharmony_ci	bool boundary_moderation_en;
638c2ecf20Sopenharmony_ci	u8 valid_lower_boundary_link;
648c2ecf20Sopenharmony_ci	u8 upper_boundary_count;
658c2ecf20Sopenharmony_ci	u8 lower_boundary_count;
668c2ecf20Sopenharmony_ci	u8 tu_size_minus1;
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistruct dp_ctrl_private {
708c2ecf20Sopenharmony_ci	struct dp_ctrl dp_ctrl;
718c2ecf20Sopenharmony_ci	struct device *dev;
728c2ecf20Sopenharmony_ci	struct drm_dp_aux *aux;
738c2ecf20Sopenharmony_ci	struct dp_panel *panel;
748c2ecf20Sopenharmony_ci	struct dp_link *link;
758c2ecf20Sopenharmony_ci	struct dp_power *power;
768c2ecf20Sopenharmony_ci	struct dp_parser *parser;
778c2ecf20Sopenharmony_ci	struct dp_catalog *catalog;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	struct completion idle_comp;
808c2ecf20Sopenharmony_ci	struct completion video_comp;
818c2ecf20Sopenharmony_ci};
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistruct dp_cr_status {
848c2ecf20Sopenharmony_ci	u8 lane_0_1;
858c2ecf20Sopenharmony_ci	u8 lane_2_3;
868c2ecf20Sopenharmony_ci};
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci#define DP_LANE0_1_CR_DONE	0x11
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic int dp_aux_link_configure(struct drm_dp_aux *aux,
918c2ecf20Sopenharmony_ci					struct dp_link_info *link)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	u8 values[2];
948c2ecf20Sopenharmony_ci	int err;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	values[0] = drm_dp_link_rate_to_bw_code(link->rate);
978c2ecf20Sopenharmony_ci	values[1] = link->num_lanes;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	if (link->capabilities & DP_LINK_CAP_ENHANCED_FRAMING)
1008c2ecf20Sopenharmony_ci		values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	err = drm_dp_dpcd_write(aux, DP_LINK_BW_SET, values, sizeof(values));
1038c2ecf20Sopenharmony_ci	if (err < 0)
1048c2ecf20Sopenharmony_ci		return err;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	return 0;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_civoid dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	struct dp_ctrl_private *ctrl;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	reinit_completion(&ctrl->idle_comp);
1168c2ecf20Sopenharmony_ci	dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_PUSH_IDLE);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	if (!wait_for_completion_timeout(&ctrl->idle_comp,
1198c2ecf20Sopenharmony_ci			IDLE_PATTERN_COMPLETION_TIMEOUT_JIFFIES))
1208c2ecf20Sopenharmony_ci		pr_warn("PUSH_IDLE pattern timedout\n");
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	pr_debug("mainlink off done\n");
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	u32 config = 0, tbd;
1288c2ecf20Sopenharmony_ci	u8 *dpcd = ctrl->panel->dpcd;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	/* Default-> LSCLK DIV: 1/4 LCLK  */
1318c2ecf20Sopenharmony_ci	config |= (2 << DP_CONFIGURATION_CTRL_LSCLK_DIV_SHIFT);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	/* Scrambler reset enable */
1348c2ecf20Sopenharmony_ci	if (dpcd[DP_EDP_CONFIGURATION_CAP] & DP_ALTERNATE_SCRAMBLER_RESET_CAP)
1358c2ecf20Sopenharmony_ci		config |= DP_CONFIGURATION_CTRL_ASSR;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	tbd = dp_link_get_test_bits_depth(ctrl->link,
1388c2ecf20Sopenharmony_ci			ctrl->panel->dp_mode.bpp);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	if (tbd == DP_TEST_BIT_DEPTH_UNKNOWN) {
1418c2ecf20Sopenharmony_ci		pr_debug("BIT_DEPTH not set. Configure default\n");
1428c2ecf20Sopenharmony_ci		tbd = DP_TEST_BIT_DEPTH_8;
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	config |= tbd << DP_CONFIGURATION_CTRL_BPC_SHIFT;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	/* Num of Lanes */
1488c2ecf20Sopenharmony_ci	config |= ((ctrl->link->link_params.num_lanes - 1)
1498c2ecf20Sopenharmony_ci			<< DP_CONFIGURATION_CTRL_NUM_OF_LANES_SHIFT);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	if (drm_dp_enhanced_frame_cap(dpcd))
1528c2ecf20Sopenharmony_ci		config |= DP_CONFIGURATION_CTRL_ENHANCED_FRAMING;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	config |= DP_CONFIGURATION_CTRL_P_INTERLACED; /* progressive video */
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	/* sync clock & static Mvid */
1578c2ecf20Sopenharmony_ci	config |= DP_CONFIGURATION_CTRL_STATIC_DYNAMIC_CN;
1588c2ecf20Sopenharmony_ci	config |= DP_CONFIGURATION_CTRL_SYNC_ASYNC_CLK;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	dp_catalog_ctrl_config_ctrl(ctrl->catalog, config);
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic void dp_ctrl_configure_source_params(struct dp_ctrl_private *ctrl)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	u32 cc, tb;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	dp_catalog_ctrl_lane_mapping(ctrl->catalog);
1688c2ecf20Sopenharmony_ci	dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	dp_ctrl_config_ctrl(ctrl);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	tb = dp_link_get_test_bits_depth(ctrl->link,
1738c2ecf20Sopenharmony_ci		ctrl->panel->dp_mode.bpp);
1748c2ecf20Sopenharmony_ci	cc = dp_link_get_colorimetry_config(ctrl->link);
1758c2ecf20Sopenharmony_ci	dp_catalog_ctrl_config_misc(ctrl->catalog, cc, tb);
1768c2ecf20Sopenharmony_ci	dp_panel_timing_cfg(ctrl->panel);
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci/*
1808c2ecf20Sopenharmony_ci * The structure and few functions present below are IP/Hardware
1818c2ecf20Sopenharmony_ci * specific implementation. Most of the implementation will not
1828c2ecf20Sopenharmony_ci * have coding comments
1838c2ecf20Sopenharmony_ci */
1848c2ecf20Sopenharmony_cistruct tu_algo_data {
1858c2ecf20Sopenharmony_ci	s64 lclk_fp;
1868c2ecf20Sopenharmony_ci	s64 pclk_fp;
1878c2ecf20Sopenharmony_ci	s64 lwidth;
1888c2ecf20Sopenharmony_ci	s64 lwidth_fp;
1898c2ecf20Sopenharmony_ci	s64 hbp_relative_to_pclk;
1908c2ecf20Sopenharmony_ci	s64 hbp_relative_to_pclk_fp;
1918c2ecf20Sopenharmony_ci	int nlanes;
1928c2ecf20Sopenharmony_ci	int bpp;
1938c2ecf20Sopenharmony_ci	int pixelEnc;
1948c2ecf20Sopenharmony_ci	int dsc_en;
1958c2ecf20Sopenharmony_ci	int async_en;
1968c2ecf20Sopenharmony_ci	int bpc;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	uint delay_start_link_extra_pixclk;
1998c2ecf20Sopenharmony_ci	int extra_buffer_margin;
2008c2ecf20Sopenharmony_ci	s64 ratio_fp;
2018c2ecf20Sopenharmony_ci	s64 original_ratio_fp;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	s64 err_fp;
2048c2ecf20Sopenharmony_ci	s64 n_err_fp;
2058c2ecf20Sopenharmony_ci	s64 n_n_err_fp;
2068c2ecf20Sopenharmony_ci	int tu_size;
2078c2ecf20Sopenharmony_ci	int tu_size_desired;
2088c2ecf20Sopenharmony_ci	int tu_size_minus1;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	int valid_boundary_link;
2118c2ecf20Sopenharmony_ci	s64 resulting_valid_fp;
2128c2ecf20Sopenharmony_ci	s64 total_valid_fp;
2138c2ecf20Sopenharmony_ci	s64 effective_valid_fp;
2148c2ecf20Sopenharmony_ci	s64 effective_valid_recorded_fp;
2158c2ecf20Sopenharmony_ci	int n_tus;
2168c2ecf20Sopenharmony_ci	int n_tus_per_lane;
2178c2ecf20Sopenharmony_ci	int paired_tus;
2188c2ecf20Sopenharmony_ci	int remainder_tus;
2198c2ecf20Sopenharmony_ci	int remainder_tus_upper;
2208c2ecf20Sopenharmony_ci	int remainder_tus_lower;
2218c2ecf20Sopenharmony_ci	int extra_bytes;
2228c2ecf20Sopenharmony_ci	int filler_size;
2238c2ecf20Sopenharmony_ci	int delay_start_link;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	int extra_pclk_cycles;
2268c2ecf20Sopenharmony_ci	int extra_pclk_cycles_in_link_clk;
2278c2ecf20Sopenharmony_ci	s64 ratio_by_tu_fp;
2288c2ecf20Sopenharmony_ci	s64 average_valid2_fp;
2298c2ecf20Sopenharmony_ci	int new_valid_boundary_link;
2308c2ecf20Sopenharmony_ci	int remainder_symbols_exist;
2318c2ecf20Sopenharmony_ci	int n_symbols;
2328c2ecf20Sopenharmony_ci	s64 n_remainder_symbols_per_lane_fp;
2338c2ecf20Sopenharmony_ci	s64 last_partial_tu_fp;
2348c2ecf20Sopenharmony_ci	s64 TU_ratio_err_fp;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	int n_tus_incl_last_incomplete_tu;
2378c2ecf20Sopenharmony_ci	int extra_pclk_cycles_tmp;
2388c2ecf20Sopenharmony_ci	int extra_pclk_cycles_in_link_clk_tmp;
2398c2ecf20Sopenharmony_ci	int extra_required_bytes_new_tmp;
2408c2ecf20Sopenharmony_ci	int filler_size_tmp;
2418c2ecf20Sopenharmony_ci	int lower_filler_size_tmp;
2428c2ecf20Sopenharmony_ci	int delay_start_link_tmp;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	bool boundary_moderation_en;
2458c2ecf20Sopenharmony_ci	int boundary_mod_lower_err;
2468c2ecf20Sopenharmony_ci	int upper_boundary_count;
2478c2ecf20Sopenharmony_ci	int lower_boundary_count;
2488c2ecf20Sopenharmony_ci	int i_upper_boundary_count;
2498c2ecf20Sopenharmony_ci	int i_lower_boundary_count;
2508c2ecf20Sopenharmony_ci	int valid_lower_boundary_link;
2518c2ecf20Sopenharmony_ci	int even_distribution_BF;
2528c2ecf20Sopenharmony_ci	int even_distribution_legacy;
2538c2ecf20Sopenharmony_ci	int even_distribution;
2548c2ecf20Sopenharmony_ci	int min_hblank_violated;
2558c2ecf20Sopenharmony_ci	s64 delay_start_time_fp;
2568c2ecf20Sopenharmony_ci	s64 hbp_time_fp;
2578c2ecf20Sopenharmony_ci	s64 hactive_time_fp;
2588c2ecf20Sopenharmony_ci	s64 diff_abs_fp;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	s64 ratio;
2618c2ecf20Sopenharmony_ci};
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cistatic int _tu_param_compare(s64 a, s64 b)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci	u32 a_sign;
2668c2ecf20Sopenharmony_ci	u32 b_sign;
2678c2ecf20Sopenharmony_ci	s64 a_temp, b_temp, minus_1;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	if (a == b)
2708c2ecf20Sopenharmony_ci		return 0;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	minus_1 = drm_fixp_from_fraction(-1, 1);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	a_sign = (a >> 32) & 0x80000000 ? 1 : 0;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	b_sign = (b >> 32) & 0x80000000 ? 1 : 0;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	if (a_sign > b_sign)
2798c2ecf20Sopenharmony_ci		return 2;
2808c2ecf20Sopenharmony_ci	else if (b_sign > a_sign)
2818c2ecf20Sopenharmony_ci		return 1;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	if (!a_sign && !b_sign) { /* positive */
2848c2ecf20Sopenharmony_ci		if (a > b)
2858c2ecf20Sopenharmony_ci			return 1;
2868c2ecf20Sopenharmony_ci		else
2878c2ecf20Sopenharmony_ci			return 2;
2888c2ecf20Sopenharmony_ci	} else { /* negative */
2898c2ecf20Sopenharmony_ci		a_temp = drm_fixp_mul(a, minus_1);
2908c2ecf20Sopenharmony_ci		b_temp = drm_fixp_mul(b, minus_1);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci		if (a_temp > b_temp)
2938c2ecf20Sopenharmony_ci			return 2;
2948c2ecf20Sopenharmony_ci		else
2958c2ecf20Sopenharmony_ci			return 1;
2968c2ecf20Sopenharmony_ci	}
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_cistatic void dp_panel_update_tu_timings(struct dp_tu_calc_input *in,
3008c2ecf20Sopenharmony_ci					struct tu_algo_data *tu)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	int nlanes = in->nlanes;
3038c2ecf20Sopenharmony_ci	int dsc_num_slices = in->num_of_dsc_slices;
3048c2ecf20Sopenharmony_ci	int dsc_num_bytes  = 0;
3058c2ecf20Sopenharmony_ci	int numerator;
3068c2ecf20Sopenharmony_ci	s64 pclk_dsc_fp;
3078c2ecf20Sopenharmony_ci	s64 dwidth_dsc_fp;
3088c2ecf20Sopenharmony_ci	s64 hbp_dsc_fp;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	int tot_num_eoc_symbols = 0;
3118c2ecf20Sopenharmony_ci	int tot_num_hor_bytes   = 0;
3128c2ecf20Sopenharmony_ci	int tot_num_dummy_bytes = 0;
3138c2ecf20Sopenharmony_ci	int dwidth_dsc_bytes    = 0;
3148c2ecf20Sopenharmony_ci	int  eoc_bytes           = 0;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	s64 temp1_fp, temp2_fp, temp3_fp;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	tu->lclk_fp              = drm_fixp_from_fraction(in->lclk, 1);
3198c2ecf20Sopenharmony_ci	tu->pclk_fp              = drm_fixp_from_fraction(in->pclk_khz, 1000);
3208c2ecf20Sopenharmony_ci	tu->lwidth               = in->hactive;
3218c2ecf20Sopenharmony_ci	tu->hbp_relative_to_pclk = in->hporch;
3228c2ecf20Sopenharmony_ci	tu->nlanes               = in->nlanes;
3238c2ecf20Sopenharmony_ci	tu->bpp                  = in->bpp;
3248c2ecf20Sopenharmony_ci	tu->pixelEnc             = in->pixel_enc;
3258c2ecf20Sopenharmony_ci	tu->dsc_en               = in->dsc_en;
3268c2ecf20Sopenharmony_ci	tu->async_en             = in->async_en;
3278c2ecf20Sopenharmony_ci	tu->lwidth_fp            = drm_fixp_from_fraction(in->hactive, 1);
3288c2ecf20Sopenharmony_ci	tu->hbp_relative_to_pclk_fp = drm_fixp_from_fraction(in->hporch, 1);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	if (tu->pixelEnc == 420) {
3318c2ecf20Sopenharmony_ci		temp1_fp = drm_fixp_from_fraction(2, 1);
3328c2ecf20Sopenharmony_ci		tu->pclk_fp = drm_fixp_div(tu->pclk_fp, temp1_fp);
3338c2ecf20Sopenharmony_ci		tu->lwidth_fp = drm_fixp_div(tu->lwidth_fp, temp1_fp);
3348c2ecf20Sopenharmony_ci		tu->hbp_relative_to_pclk_fp =
3358c2ecf20Sopenharmony_ci				drm_fixp_div(tu->hbp_relative_to_pclk_fp, 2);
3368c2ecf20Sopenharmony_ci	}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	if (tu->pixelEnc == 422) {
3398c2ecf20Sopenharmony_ci		switch (tu->bpp) {
3408c2ecf20Sopenharmony_ci		case 24:
3418c2ecf20Sopenharmony_ci			tu->bpp = 16;
3428c2ecf20Sopenharmony_ci			tu->bpc = 8;
3438c2ecf20Sopenharmony_ci			break;
3448c2ecf20Sopenharmony_ci		case 30:
3458c2ecf20Sopenharmony_ci			tu->bpp = 20;
3468c2ecf20Sopenharmony_ci			tu->bpc = 10;
3478c2ecf20Sopenharmony_ci			break;
3488c2ecf20Sopenharmony_ci		default:
3498c2ecf20Sopenharmony_ci			tu->bpp = 16;
3508c2ecf20Sopenharmony_ci			tu->bpc = 8;
3518c2ecf20Sopenharmony_ci			break;
3528c2ecf20Sopenharmony_ci		}
3538c2ecf20Sopenharmony_ci	} else {
3548c2ecf20Sopenharmony_ci		tu->bpc = tu->bpp/3;
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	if (!in->dsc_en)
3588c2ecf20Sopenharmony_ci		goto fec_check;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(in->compress_ratio, 100);
3618c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_from_fraction(in->bpp, 1);
3628c2ecf20Sopenharmony_ci	temp3_fp = drm_fixp_div(temp2_fp, temp1_fp);
3638c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_mul(tu->lwidth_fp, temp3_fp);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(8, 1);
3668c2ecf20Sopenharmony_ci	temp3_fp = drm_fixp_div(temp2_fp, temp1_fp);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	numerator = drm_fixp2int(temp3_fp);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	dsc_num_bytes  = numerator / dsc_num_slices;
3718c2ecf20Sopenharmony_ci	eoc_bytes           = dsc_num_bytes % nlanes;
3728c2ecf20Sopenharmony_ci	tot_num_eoc_symbols = nlanes * dsc_num_slices;
3738c2ecf20Sopenharmony_ci	tot_num_hor_bytes   = dsc_num_bytes * dsc_num_slices;
3748c2ecf20Sopenharmony_ci	tot_num_dummy_bytes = (nlanes - eoc_bytes) * dsc_num_slices;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	if (dsc_num_bytes == 0)
3778c2ecf20Sopenharmony_ci		pr_info("incorrect no of bytes per slice=%d\n", dsc_num_bytes);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	dwidth_dsc_bytes = (tot_num_hor_bytes +
3808c2ecf20Sopenharmony_ci				tot_num_eoc_symbols +
3818c2ecf20Sopenharmony_ci				(eoc_bytes == 0 ? 0 : tot_num_dummy_bytes));
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	dwidth_dsc_fp = drm_fixp_from_fraction(dwidth_dsc_bytes, 3);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_mul(tu->pclk_fp, dwidth_dsc_fp);
3868c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_div(temp2_fp, tu->lwidth_fp);
3878c2ecf20Sopenharmony_ci	pclk_dsc_fp = temp1_fp;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_div(pclk_dsc_fp, tu->pclk_fp);
3908c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_mul(tu->hbp_relative_to_pclk_fp, temp1_fp);
3918c2ecf20Sopenharmony_ci	hbp_dsc_fp = temp2_fp;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	/* output */
3948c2ecf20Sopenharmony_ci	tu->pclk_fp = pclk_dsc_fp;
3958c2ecf20Sopenharmony_ci	tu->lwidth_fp = dwidth_dsc_fp;
3968c2ecf20Sopenharmony_ci	tu->hbp_relative_to_pclk_fp = hbp_dsc_fp;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_cifec_check:
3998c2ecf20Sopenharmony_ci	if (in->fec_en) {
4008c2ecf20Sopenharmony_ci		temp1_fp = drm_fixp_from_fraction(976, 1000); /* 0.976 */
4018c2ecf20Sopenharmony_ci		tu->lclk_fp = drm_fixp_mul(tu->lclk_fp, temp1_fp);
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_cistatic void _tu_valid_boundary_calc(struct tu_algo_data *tu)
4068c2ecf20Sopenharmony_ci{
4078c2ecf20Sopenharmony_ci	s64 temp1_fp, temp2_fp, temp, temp1, temp2;
4088c2ecf20Sopenharmony_ci	int compare_result_1, compare_result_2, compare_result_3;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
4118c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	tu->new_valid_boundary_link = drm_fixp2int_ceil(temp2_fp);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	temp = (tu->i_upper_boundary_count *
4168c2ecf20Sopenharmony_ci				tu->new_valid_boundary_link +
4178c2ecf20Sopenharmony_ci				tu->i_lower_boundary_count *
4188c2ecf20Sopenharmony_ci				(tu->new_valid_boundary_link-1));
4198c2ecf20Sopenharmony_ci	tu->average_valid2_fp = drm_fixp_from_fraction(temp,
4208c2ecf20Sopenharmony_ci					(tu->i_upper_boundary_count +
4218c2ecf20Sopenharmony_ci					tu->i_lower_boundary_count));
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
4248c2ecf20Sopenharmony_ci	temp2_fp = tu->lwidth_fp;
4258c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
4268c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_div(temp1_fp, tu->average_valid2_fp);
4278c2ecf20Sopenharmony_ci	tu->n_tus = drm_fixp2int(temp2_fp);
4288c2ecf20Sopenharmony_ci	if ((temp2_fp & 0xFFFFFFFF) > 0xFFFFF000)
4298c2ecf20Sopenharmony_ci		tu->n_tus += 1;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu->n_tus, 1);
4328c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_mul(temp1_fp, tu->average_valid2_fp);
4338c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu->n_symbols, 1);
4348c2ecf20Sopenharmony_ci	temp2_fp = temp1_fp - temp2_fp;
4358c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu->nlanes, 1);
4368c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_div(temp2_fp, temp1_fp);
4378c2ecf20Sopenharmony_ci	tu->n_remainder_symbols_per_lane_fp = temp2_fp;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
4408c2ecf20Sopenharmony_ci	tu->last_partial_tu_fp =
4418c2ecf20Sopenharmony_ci			drm_fixp_div(tu->n_remainder_symbols_per_lane_fp,
4428c2ecf20Sopenharmony_ci					temp1_fp);
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	if (tu->n_remainder_symbols_per_lane_fp != 0)
4458c2ecf20Sopenharmony_ci		tu->remainder_symbols_exist = 1;
4468c2ecf20Sopenharmony_ci	else
4478c2ecf20Sopenharmony_ci		tu->remainder_symbols_exist = 0;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu->n_tus, tu->nlanes);
4508c2ecf20Sopenharmony_ci	tu->n_tus_per_lane = drm_fixp2int(temp1_fp);
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	tu->paired_tus = (int)((tu->n_tus_per_lane) /
4538c2ecf20Sopenharmony_ci					(tu->i_upper_boundary_count +
4548c2ecf20Sopenharmony_ci					 tu->i_lower_boundary_count));
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	tu->remainder_tus = tu->n_tus_per_lane - tu->paired_tus *
4578c2ecf20Sopenharmony_ci						(tu->i_upper_boundary_count +
4588c2ecf20Sopenharmony_ci						tu->i_lower_boundary_count);
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	if ((tu->remainder_tus - tu->i_upper_boundary_count) > 0) {
4618c2ecf20Sopenharmony_ci		tu->remainder_tus_upper = tu->i_upper_boundary_count;
4628c2ecf20Sopenharmony_ci		tu->remainder_tus_lower = tu->remainder_tus -
4638c2ecf20Sopenharmony_ci						tu->i_upper_boundary_count;
4648c2ecf20Sopenharmony_ci	} else {
4658c2ecf20Sopenharmony_ci		tu->remainder_tus_upper = tu->remainder_tus;
4668c2ecf20Sopenharmony_ci		tu->remainder_tus_lower = 0;
4678c2ecf20Sopenharmony_ci	}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	temp = tu->paired_tus * (tu->i_upper_boundary_count *
4708c2ecf20Sopenharmony_ci				tu->new_valid_boundary_link +
4718c2ecf20Sopenharmony_ci				tu->i_lower_boundary_count *
4728c2ecf20Sopenharmony_ci				(tu->new_valid_boundary_link - 1)) +
4738c2ecf20Sopenharmony_ci				(tu->remainder_tus_upper *
4748c2ecf20Sopenharmony_ci				 tu->new_valid_boundary_link) +
4758c2ecf20Sopenharmony_ci				(tu->remainder_tus_lower *
4768c2ecf20Sopenharmony_ci				(tu->new_valid_boundary_link - 1));
4778c2ecf20Sopenharmony_ci	tu->total_valid_fp = drm_fixp_from_fraction(temp, 1);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	if (tu->remainder_symbols_exist) {
4808c2ecf20Sopenharmony_ci		temp1_fp = tu->total_valid_fp +
4818c2ecf20Sopenharmony_ci				tu->n_remainder_symbols_per_lane_fp;
4828c2ecf20Sopenharmony_ci		temp2_fp = drm_fixp_from_fraction(tu->n_tus_per_lane, 1);
4838c2ecf20Sopenharmony_ci		temp2_fp = temp2_fp + tu->last_partial_tu_fp;
4848c2ecf20Sopenharmony_ci		temp1_fp = drm_fixp_div(temp1_fp, temp2_fp);
4858c2ecf20Sopenharmony_ci	} else {
4868c2ecf20Sopenharmony_ci		temp2_fp = drm_fixp_from_fraction(tu->n_tus_per_lane, 1);
4878c2ecf20Sopenharmony_ci		temp1_fp = drm_fixp_div(tu->total_valid_fp, temp2_fp);
4888c2ecf20Sopenharmony_ci	}
4898c2ecf20Sopenharmony_ci	tu->effective_valid_fp = temp1_fp;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
4928c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
4938c2ecf20Sopenharmony_ci	tu->n_n_err_fp = tu->effective_valid_fp - temp2_fp;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
4968c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
4978c2ecf20Sopenharmony_ci	tu->n_err_fp = tu->average_valid2_fp - temp2_fp;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	tu->even_distribution = tu->n_tus % tu->nlanes == 0 ? 1 : 0;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
5028c2ecf20Sopenharmony_ci	temp2_fp = tu->lwidth_fp;
5038c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
5048c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_div(temp1_fp, tu->average_valid2_fp);
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	if (temp2_fp)
5078c2ecf20Sopenharmony_ci		tu->n_tus_incl_last_incomplete_tu = drm_fixp2int_ceil(temp2_fp);
5088c2ecf20Sopenharmony_ci	else
5098c2ecf20Sopenharmony_ci		tu->n_tus_incl_last_incomplete_tu = 0;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	temp1 = 0;
5128c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
5138c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp);
5148c2ecf20Sopenharmony_ci	temp1_fp = tu->average_valid2_fp - temp2_fp;
5158c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_from_fraction(tu->n_tus_incl_last_incomplete_tu, 1);
5168c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	if (temp1_fp)
5198c2ecf20Sopenharmony_ci		temp1 = drm_fixp2int_ceil(temp1_fp);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	temp = tu->i_upper_boundary_count * tu->nlanes;
5228c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
5238c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp);
5248c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu->new_valid_boundary_link, 1);
5258c2ecf20Sopenharmony_ci	temp2_fp = temp1_fp - temp2_fp;
5268c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(temp, 1);
5278c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	if (temp2_fp)
5308c2ecf20Sopenharmony_ci		temp2 = drm_fixp2int_ceil(temp2_fp);
5318c2ecf20Sopenharmony_ci	else
5328c2ecf20Sopenharmony_ci		temp2 = 0;
5338c2ecf20Sopenharmony_ci	tu->extra_required_bytes_new_tmp = (int)(temp1 + temp2);
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(8, tu->bpp);
5368c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_from_fraction(
5378c2ecf20Sopenharmony_ci	tu->extra_required_bytes_new_tmp, 1);
5388c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	if (temp1_fp)
5418c2ecf20Sopenharmony_ci		tu->extra_pclk_cycles_tmp = drm_fixp2int_ceil(temp1_fp);
5428c2ecf20Sopenharmony_ci	else
5438c2ecf20Sopenharmony_ci		tu->extra_pclk_cycles_tmp = 0;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu->extra_pclk_cycles_tmp, 1);
5468c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp);
5478c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	if (temp1_fp)
5508c2ecf20Sopenharmony_ci		tu->extra_pclk_cycles_in_link_clk_tmp =
5518c2ecf20Sopenharmony_ci						drm_fixp2int_ceil(temp1_fp);
5528c2ecf20Sopenharmony_ci	else
5538c2ecf20Sopenharmony_ci		tu->extra_pclk_cycles_in_link_clk_tmp = 0;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	tu->filler_size_tmp = tu->tu_size - tu->new_valid_boundary_link;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	tu->lower_filler_size_tmp = tu->filler_size_tmp + 1;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	tu->delay_start_link_tmp = tu->extra_pclk_cycles_in_link_clk_tmp +
5608c2ecf20Sopenharmony_ci					tu->lower_filler_size_tmp +
5618c2ecf20Sopenharmony_ci					tu->extra_buffer_margin;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu->delay_start_link_tmp, 1);
5648c2ecf20Sopenharmony_ci	tu->delay_start_time_fp = drm_fixp_div(temp1_fp, tu->lclk_fp);
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	compare_result_1 = _tu_param_compare(tu->n_n_err_fp, tu->diff_abs_fp);
5678c2ecf20Sopenharmony_ci	if (compare_result_1 == 2)
5688c2ecf20Sopenharmony_ci		compare_result_1 = 1;
5698c2ecf20Sopenharmony_ci	else
5708c2ecf20Sopenharmony_ci		compare_result_1 = 0;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	compare_result_2 = _tu_param_compare(tu->n_n_err_fp, tu->err_fp);
5738c2ecf20Sopenharmony_ci	if (compare_result_2 == 2)
5748c2ecf20Sopenharmony_ci		compare_result_2 = 1;
5758c2ecf20Sopenharmony_ci	else
5768c2ecf20Sopenharmony_ci		compare_result_2 = 0;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	compare_result_3 = _tu_param_compare(tu->hbp_time_fp,
5798c2ecf20Sopenharmony_ci					tu->delay_start_time_fp);
5808c2ecf20Sopenharmony_ci	if (compare_result_3 == 2)
5818c2ecf20Sopenharmony_ci		compare_result_3 = 0;
5828c2ecf20Sopenharmony_ci	else
5838c2ecf20Sopenharmony_ci		compare_result_3 = 1;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	if (((tu->even_distribution == 1) ||
5868c2ecf20Sopenharmony_ci			((tu->even_distribution_BF == 0) &&
5878c2ecf20Sopenharmony_ci			(tu->even_distribution_legacy == 0))) &&
5888c2ecf20Sopenharmony_ci			tu->n_err_fp >= 0 && tu->n_n_err_fp >= 0 &&
5898c2ecf20Sopenharmony_ci			compare_result_2 &&
5908c2ecf20Sopenharmony_ci			(compare_result_1 || (tu->min_hblank_violated == 1)) &&
5918c2ecf20Sopenharmony_ci			(tu->new_valid_boundary_link - 1) > 0 &&
5928c2ecf20Sopenharmony_ci			compare_result_3 &&
5938c2ecf20Sopenharmony_ci			(tu->delay_start_link_tmp <= 1023)) {
5948c2ecf20Sopenharmony_ci		tu->upper_boundary_count = tu->i_upper_boundary_count;
5958c2ecf20Sopenharmony_ci		tu->lower_boundary_count = tu->i_lower_boundary_count;
5968c2ecf20Sopenharmony_ci		tu->err_fp = tu->n_n_err_fp;
5978c2ecf20Sopenharmony_ci		tu->boundary_moderation_en = true;
5988c2ecf20Sopenharmony_ci		tu->tu_size_desired = tu->tu_size;
5998c2ecf20Sopenharmony_ci		tu->valid_boundary_link = tu->new_valid_boundary_link;
6008c2ecf20Sopenharmony_ci		tu->effective_valid_recorded_fp = tu->effective_valid_fp;
6018c2ecf20Sopenharmony_ci		tu->even_distribution_BF = 1;
6028c2ecf20Sopenharmony_ci		tu->delay_start_link = tu->delay_start_link_tmp;
6038c2ecf20Sopenharmony_ci	} else if (tu->boundary_mod_lower_err == 0) {
6048c2ecf20Sopenharmony_ci		compare_result_1 = _tu_param_compare(tu->n_n_err_fp,
6058c2ecf20Sopenharmony_ci							tu->diff_abs_fp);
6068c2ecf20Sopenharmony_ci		if (compare_result_1 == 2)
6078c2ecf20Sopenharmony_ci			tu->boundary_mod_lower_err = 1;
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_cistatic void _dp_ctrl_calc_tu(struct dp_tu_calc_input *in,
6128c2ecf20Sopenharmony_ci				   struct dp_vc_tu_mapping_table *tu_table)
6138c2ecf20Sopenharmony_ci{
6148c2ecf20Sopenharmony_ci	struct tu_algo_data tu;
6158c2ecf20Sopenharmony_ci	int compare_result_1, compare_result_2;
6168c2ecf20Sopenharmony_ci	u64 temp = 0;
6178c2ecf20Sopenharmony_ci	s64 temp_fp = 0, temp1_fp = 0, temp2_fp = 0;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	s64 LCLK_FAST_SKEW_fp = drm_fixp_from_fraction(6, 10000); /* 0.0006 */
6208c2ecf20Sopenharmony_ci	s64 const_p49_fp = drm_fixp_from_fraction(49, 100); /* 0.49 */
6218c2ecf20Sopenharmony_ci	s64 const_p56_fp = drm_fixp_from_fraction(56, 100); /* 0.56 */
6228c2ecf20Sopenharmony_ci	s64 RATIO_SCALE_fp = drm_fixp_from_fraction(1001, 1000);
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	u8 DP_BRUTE_FORCE = 1;
6258c2ecf20Sopenharmony_ci	s64 BRUTE_FORCE_THRESHOLD_fp = drm_fixp_from_fraction(1, 10); /* 0.1 */
6268c2ecf20Sopenharmony_ci	uint EXTRA_PIXCLK_CYCLE_DELAY = 4;
6278c2ecf20Sopenharmony_ci	uint HBLANK_MARGIN = 4;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	memset(&tu, 0, sizeof(tu));
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	dp_panel_update_tu_timings(in, &tu);
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	tu.err_fp = drm_fixp_from_fraction(1000, 1); /* 1000 */
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(4, 1);
6368c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_mul(temp1_fp, tu.lclk_fp);
6378c2ecf20Sopenharmony_ci	temp_fp = drm_fixp_div(temp2_fp, tu.pclk_fp);
6388c2ecf20Sopenharmony_ci	tu.extra_buffer_margin = drm_fixp2int_ceil(temp_fp);
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
6418c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_mul(tu.pclk_fp, temp1_fp);
6428c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1);
6438c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_div(temp2_fp, temp1_fp);
6448c2ecf20Sopenharmony_ci	tu.ratio_fp = drm_fixp_div(temp2_fp, tu.lclk_fp);
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	tu.original_ratio_fp = tu.ratio_fp;
6478c2ecf20Sopenharmony_ci	tu.boundary_moderation_en = false;
6488c2ecf20Sopenharmony_ci	tu.upper_boundary_count = 0;
6498c2ecf20Sopenharmony_ci	tu.lower_boundary_count = 0;
6508c2ecf20Sopenharmony_ci	tu.i_upper_boundary_count = 0;
6518c2ecf20Sopenharmony_ci	tu.i_lower_boundary_count = 0;
6528c2ecf20Sopenharmony_ci	tu.valid_lower_boundary_link = 0;
6538c2ecf20Sopenharmony_ci	tu.even_distribution_BF = 0;
6548c2ecf20Sopenharmony_ci	tu.even_distribution_legacy = 0;
6558c2ecf20Sopenharmony_ci	tu.even_distribution = 0;
6568c2ecf20Sopenharmony_ci	tu.delay_start_time_fp = 0;
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	tu.err_fp = drm_fixp_from_fraction(1000, 1);
6598c2ecf20Sopenharmony_ci	tu.n_err_fp = 0;
6608c2ecf20Sopenharmony_ci	tu.n_n_err_fp = 0;
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	tu.ratio = drm_fixp2int(tu.ratio_fp);
6638c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1);
6648c2ecf20Sopenharmony_ci	div64_u64_rem(tu.lwidth_fp, temp1_fp, &temp2_fp);
6658c2ecf20Sopenharmony_ci	if (temp2_fp != 0 &&
6668c2ecf20Sopenharmony_ci			!tu.ratio && tu.dsc_en == 0) {
6678c2ecf20Sopenharmony_ci		tu.ratio_fp = drm_fixp_mul(tu.ratio_fp, RATIO_SCALE_fp);
6688c2ecf20Sopenharmony_ci		tu.ratio = drm_fixp2int(tu.ratio_fp);
6698c2ecf20Sopenharmony_ci		if (tu.ratio)
6708c2ecf20Sopenharmony_ci			tu.ratio_fp = drm_fixp_from_fraction(1, 1);
6718c2ecf20Sopenharmony_ci	}
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	if (tu.ratio > 1)
6748c2ecf20Sopenharmony_ci		tu.ratio = 1;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	if (tu.ratio == 1)
6778c2ecf20Sopenharmony_ci		goto tu_size_calc;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	compare_result_1 = _tu_param_compare(tu.ratio_fp, const_p49_fp);
6808c2ecf20Sopenharmony_ci	if (!compare_result_1 || compare_result_1 == 1)
6818c2ecf20Sopenharmony_ci		compare_result_1 = 1;
6828c2ecf20Sopenharmony_ci	else
6838c2ecf20Sopenharmony_ci		compare_result_1 = 0;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	compare_result_2 = _tu_param_compare(tu.ratio_fp, const_p56_fp);
6868c2ecf20Sopenharmony_ci	if (!compare_result_2 || compare_result_2 == 2)
6878c2ecf20Sopenharmony_ci		compare_result_2 = 1;
6888c2ecf20Sopenharmony_ci	else
6898c2ecf20Sopenharmony_ci		compare_result_2 = 0;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	if (tu.dsc_en && compare_result_1 && compare_result_2) {
6928c2ecf20Sopenharmony_ci		HBLANK_MARGIN += 4;
6938c2ecf20Sopenharmony_ci		DRM_DEBUG_DP("Info: increase HBLANK_MARGIN to %d\n",
6948c2ecf20Sopenharmony_ci				HBLANK_MARGIN);
6958c2ecf20Sopenharmony_ci	}
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_citu_size_calc:
6988c2ecf20Sopenharmony_ci	for (tu.tu_size = 32; tu.tu_size <= 64; tu.tu_size++) {
6998c2ecf20Sopenharmony_ci		temp1_fp = drm_fixp_from_fraction(tu.tu_size, 1);
7008c2ecf20Sopenharmony_ci		temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp);
7018c2ecf20Sopenharmony_ci		temp = drm_fixp2int_ceil(temp2_fp);
7028c2ecf20Sopenharmony_ci		temp1_fp = drm_fixp_from_fraction(temp, 1);
7038c2ecf20Sopenharmony_ci		tu.n_err_fp = temp1_fp - temp2_fp;
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci		if (tu.n_err_fp < tu.err_fp) {
7068c2ecf20Sopenharmony_ci			tu.err_fp = tu.n_err_fp;
7078c2ecf20Sopenharmony_ci			tu.tu_size_desired = tu.tu_size;
7088c2ecf20Sopenharmony_ci		}
7098c2ecf20Sopenharmony_ci	}
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	tu.tu_size_minus1 = tu.tu_size_desired - 1;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
7148c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp);
7158c2ecf20Sopenharmony_ci	tu.valid_boundary_link = drm_fixp2int_ceil(temp2_fp);
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
7188c2ecf20Sopenharmony_ci	temp2_fp = tu.lwidth_fp;
7198c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_mul(temp2_fp, temp1_fp);
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu.valid_boundary_link, 1);
7228c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_div(temp2_fp, temp1_fp);
7238c2ecf20Sopenharmony_ci	tu.n_tus = drm_fixp2int(temp2_fp);
7248c2ecf20Sopenharmony_ci	if ((temp2_fp & 0xFFFFFFFF) > 0xFFFFF000)
7258c2ecf20Sopenharmony_ci		tu.n_tus += 1;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	tu.even_distribution_legacy = tu.n_tus % tu.nlanes == 0 ? 1 : 0;
7288c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("Info: n_sym = %d, num_of_tus = %d\n",
7298c2ecf20Sopenharmony_ci		tu.valid_boundary_link, tu.n_tus);
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
7328c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_mul(tu.original_ratio_fp, temp1_fp);
7338c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu.valid_boundary_link, 1);
7348c2ecf20Sopenharmony_ci	temp2_fp = temp1_fp - temp2_fp;
7358c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu.n_tus + 1, 1);
7368c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	temp = drm_fixp2int(temp2_fp);
7398c2ecf20Sopenharmony_ci	if (temp && temp2_fp)
7408c2ecf20Sopenharmony_ci		tu.extra_bytes = drm_fixp2int_ceil(temp2_fp);
7418c2ecf20Sopenharmony_ci	else
7428c2ecf20Sopenharmony_ci		tu.extra_bytes = 0;
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu.extra_bytes, 1);
7458c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_from_fraction(8, tu.bpp);
7468c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp);
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	if (temp && temp1_fp)
7498c2ecf20Sopenharmony_ci		tu.extra_pclk_cycles = drm_fixp2int_ceil(temp1_fp);
7508c2ecf20Sopenharmony_ci	else
7518c2ecf20Sopenharmony_ci		tu.extra_pclk_cycles = drm_fixp2int(temp1_fp);
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_div(tu.lclk_fp, tu.pclk_fp);
7548c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_from_fraction(tu.extra_pclk_cycles, 1);
7558c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	if (temp1_fp)
7588c2ecf20Sopenharmony_ci		tu.extra_pclk_cycles_in_link_clk = drm_fixp2int_ceil(temp1_fp);
7598c2ecf20Sopenharmony_ci	else
7608c2ecf20Sopenharmony_ci		tu.extra_pclk_cycles_in_link_clk = drm_fixp2int(temp1_fp);
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	tu.filler_size = tu.tu_size_desired - tu.valid_boundary_link;
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
7658c2ecf20Sopenharmony_ci	tu.ratio_by_tu_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	tu.delay_start_link = tu.extra_pclk_cycles_in_link_clk +
7688c2ecf20Sopenharmony_ci				tu.filler_size + tu.extra_buffer_margin;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	tu.resulting_valid_fp =
7718c2ecf20Sopenharmony_ci			drm_fixp_from_fraction(tu.valid_boundary_link, 1);
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
7748c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_div(tu.resulting_valid_fp, temp1_fp);
7758c2ecf20Sopenharmony_ci	tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp;
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(HBLANK_MARGIN, 1);
7788c2ecf20Sopenharmony_ci	temp1_fp = tu.hbp_relative_to_pclk_fp - temp1_fp;
7798c2ecf20Sopenharmony_ci	tu.hbp_time_fp = drm_fixp_div(temp1_fp, tu.pclk_fp);
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1);
7828c2ecf20Sopenharmony_ci	tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp);
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	compare_result_1 = _tu_param_compare(tu.hbp_time_fp,
7858c2ecf20Sopenharmony_ci					tu.delay_start_time_fp);
7868c2ecf20Sopenharmony_ci	if (compare_result_1 == 2) /* if (hbp_time_fp < delay_start_time_fp) */
7878c2ecf20Sopenharmony_ci		tu.min_hblank_violated = 1;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	tu.hactive_time_fp = drm_fixp_div(tu.lwidth_fp, tu.pclk_fp);
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	compare_result_2 = _tu_param_compare(tu.hactive_time_fp,
7928c2ecf20Sopenharmony_ci						tu.delay_start_time_fp);
7938c2ecf20Sopenharmony_ci	if (compare_result_2 == 2)
7948c2ecf20Sopenharmony_ci		tu.min_hblank_violated = 1;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	tu.delay_start_time_fp = 0;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	/* brute force */
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	tu.delay_start_link_extra_pixclk = EXTRA_PIXCLK_CYCLE_DELAY;
8018c2ecf20Sopenharmony_ci	tu.diff_abs_fp = tu.resulting_valid_fp - tu.ratio_by_tu_fp;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	temp = drm_fixp2int(tu.diff_abs_fp);
8048c2ecf20Sopenharmony_ci	if (!temp && tu.diff_abs_fp <= 0xffff)
8058c2ecf20Sopenharmony_ci		tu.diff_abs_fp = 0;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	/* if(diff_abs < 0) diff_abs *= -1 */
8088c2ecf20Sopenharmony_ci	if (tu.diff_abs_fp < 0)
8098c2ecf20Sopenharmony_ci		tu.diff_abs_fp = drm_fixp_mul(tu.diff_abs_fp, -1);
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	tu.boundary_mod_lower_err = 0;
8128c2ecf20Sopenharmony_ci	if ((tu.diff_abs_fp != 0 &&
8138c2ecf20Sopenharmony_ci			((tu.diff_abs_fp > BRUTE_FORCE_THRESHOLD_fp) ||
8148c2ecf20Sopenharmony_ci			 (tu.even_distribution_legacy == 0) ||
8158c2ecf20Sopenharmony_ci			 (DP_BRUTE_FORCE == 1))) ||
8168c2ecf20Sopenharmony_ci			(tu.min_hblank_violated == 1)) {
8178c2ecf20Sopenharmony_ci		do {
8188c2ecf20Sopenharmony_ci			tu.err_fp = drm_fixp_from_fraction(1000, 1);
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci			temp1_fp = drm_fixp_div(tu.lclk_fp, tu.pclk_fp);
8218c2ecf20Sopenharmony_ci			temp2_fp = drm_fixp_from_fraction(
8228c2ecf20Sopenharmony_ci					tu.delay_start_link_extra_pixclk, 1);
8238c2ecf20Sopenharmony_ci			temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci			if (temp1_fp)
8268c2ecf20Sopenharmony_ci				tu.extra_buffer_margin =
8278c2ecf20Sopenharmony_ci					drm_fixp2int_ceil(temp1_fp);
8288c2ecf20Sopenharmony_ci			else
8298c2ecf20Sopenharmony_ci				tu.extra_buffer_margin = 0;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci			temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
8328c2ecf20Sopenharmony_ci			temp1_fp = drm_fixp_mul(tu.lwidth_fp, temp1_fp);
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci			if (temp1_fp)
8358c2ecf20Sopenharmony_ci				tu.n_symbols = drm_fixp2int_ceil(temp1_fp);
8368c2ecf20Sopenharmony_ci			else
8378c2ecf20Sopenharmony_ci				tu.n_symbols = 0;
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci			for (tu.tu_size = 32; tu.tu_size <= 64; tu.tu_size++) {
8408c2ecf20Sopenharmony_ci				for (tu.i_upper_boundary_count = 1;
8418c2ecf20Sopenharmony_ci					tu.i_upper_boundary_count <= 15;
8428c2ecf20Sopenharmony_ci					tu.i_upper_boundary_count++) {
8438c2ecf20Sopenharmony_ci					for (tu.i_lower_boundary_count = 1;
8448c2ecf20Sopenharmony_ci						tu.i_lower_boundary_count <= 15;
8458c2ecf20Sopenharmony_ci						tu.i_lower_boundary_count++) {
8468c2ecf20Sopenharmony_ci						_tu_valid_boundary_calc(&tu);
8478c2ecf20Sopenharmony_ci					}
8488c2ecf20Sopenharmony_ci				}
8498c2ecf20Sopenharmony_ci			}
8508c2ecf20Sopenharmony_ci			tu.delay_start_link_extra_pixclk--;
8518c2ecf20Sopenharmony_ci		} while (tu.boundary_moderation_en != true &&
8528c2ecf20Sopenharmony_ci			tu.boundary_mod_lower_err == 1 &&
8538c2ecf20Sopenharmony_ci			tu.delay_start_link_extra_pixclk != 0);
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci		if (tu.boundary_moderation_en == true) {
8568c2ecf20Sopenharmony_ci			temp1_fp = drm_fixp_from_fraction(
8578c2ecf20Sopenharmony_ci					(tu.upper_boundary_count *
8588c2ecf20Sopenharmony_ci					tu.valid_boundary_link +
8598c2ecf20Sopenharmony_ci					tu.lower_boundary_count *
8608c2ecf20Sopenharmony_ci					(tu.valid_boundary_link - 1)), 1);
8618c2ecf20Sopenharmony_ci			temp2_fp = drm_fixp_from_fraction(
8628c2ecf20Sopenharmony_ci					(tu.upper_boundary_count +
8638c2ecf20Sopenharmony_ci					tu.lower_boundary_count), 1);
8648c2ecf20Sopenharmony_ci			tu.resulting_valid_fp =
8658c2ecf20Sopenharmony_ci					drm_fixp_div(temp1_fp, temp2_fp);
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci			temp1_fp = drm_fixp_from_fraction(
8688c2ecf20Sopenharmony_ci					tu.tu_size_desired, 1);
8698c2ecf20Sopenharmony_ci			tu.ratio_by_tu_fp =
8708c2ecf20Sopenharmony_ci				drm_fixp_mul(tu.original_ratio_fp, temp1_fp);
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci			tu.valid_lower_boundary_link =
8738c2ecf20Sopenharmony_ci				tu.valid_boundary_link - 1;
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci			temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
8768c2ecf20Sopenharmony_ci			temp1_fp = drm_fixp_mul(tu.lwidth_fp, temp1_fp);
8778c2ecf20Sopenharmony_ci			temp2_fp = drm_fixp_div(temp1_fp,
8788c2ecf20Sopenharmony_ci						tu.resulting_valid_fp);
8798c2ecf20Sopenharmony_ci			tu.n_tus = drm_fixp2int(temp2_fp);
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci			tu.tu_size_minus1 = tu.tu_size_desired - 1;
8828c2ecf20Sopenharmony_ci			tu.even_distribution_BF = 1;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci			temp1_fp =
8858c2ecf20Sopenharmony_ci				drm_fixp_from_fraction(tu.tu_size_desired, 1);
8868c2ecf20Sopenharmony_ci			temp2_fp =
8878c2ecf20Sopenharmony_ci				drm_fixp_div(tu.resulting_valid_fp, temp1_fp);
8888c2ecf20Sopenharmony_ci			tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp;
8898c2ecf20Sopenharmony_ci		}
8908c2ecf20Sopenharmony_ci	}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_mul(LCLK_FAST_SKEW_fp, tu.lwidth_fp);
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	if (temp2_fp)
8958c2ecf20Sopenharmony_ci		temp = drm_fixp2int_ceil(temp2_fp);
8968c2ecf20Sopenharmony_ci	else
8978c2ecf20Sopenharmony_ci		temp = 0;
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1);
9008c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_mul(tu.original_ratio_fp, temp1_fp);
9018c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
9028c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_div(temp1_fp, temp2_fp);
9038c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(temp, 1);
9048c2ecf20Sopenharmony_ci	temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
9058c2ecf20Sopenharmony_ci	temp = drm_fixp2int(temp2_fp);
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	if (tu.async_en)
9088c2ecf20Sopenharmony_ci		tu.delay_start_link += (int)temp;
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1);
9118c2ecf20Sopenharmony_ci	tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp);
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	/* OUTPUTS */
9148c2ecf20Sopenharmony_ci	tu_table->valid_boundary_link       = tu.valid_boundary_link;
9158c2ecf20Sopenharmony_ci	tu_table->delay_start_link          = tu.delay_start_link;
9168c2ecf20Sopenharmony_ci	tu_table->boundary_moderation_en    = tu.boundary_moderation_en;
9178c2ecf20Sopenharmony_ci	tu_table->valid_lower_boundary_link = tu.valid_lower_boundary_link;
9188c2ecf20Sopenharmony_ci	tu_table->upper_boundary_count      = tu.upper_boundary_count;
9198c2ecf20Sopenharmony_ci	tu_table->lower_boundary_count      = tu.lower_boundary_count;
9208c2ecf20Sopenharmony_ci	tu_table->tu_size_minus1            = tu.tu_size_minus1;
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("TU: valid_boundary_link: %d\n",
9238c2ecf20Sopenharmony_ci				tu_table->valid_boundary_link);
9248c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("TU: delay_start_link: %d\n",
9258c2ecf20Sopenharmony_ci				tu_table->delay_start_link);
9268c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("TU: boundary_moderation_en: %d\n",
9278c2ecf20Sopenharmony_ci			tu_table->boundary_moderation_en);
9288c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("TU: valid_lower_boundary_link: %d\n",
9298c2ecf20Sopenharmony_ci			tu_table->valid_lower_boundary_link);
9308c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("TU: upper_boundary_count: %d\n",
9318c2ecf20Sopenharmony_ci			tu_table->upper_boundary_count);
9328c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("TU: lower_boundary_count: %d\n",
9338c2ecf20Sopenharmony_ci			tu_table->lower_boundary_count);
9348c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("TU: tu_size_minus1: %d\n", tu_table->tu_size_minus1);
9358c2ecf20Sopenharmony_ci}
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_cistatic void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl,
9388c2ecf20Sopenharmony_ci		struct dp_vc_tu_mapping_table *tu_table)
9398c2ecf20Sopenharmony_ci{
9408c2ecf20Sopenharmony_ci	struct dp_tu_calc_input in;
9418c2ecf20Sopenharmony_ci	struct drm_display_mode *drm_mode;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	drm_mode = &ctrl->panel->dp_mode.drm_mode;
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	in.lclk = ctrl->link->link_params.rate / 1000;
9468c2ecf20Sopenharmony_ci	in.pclk_khz = drm_mode->clock;
9478c2ecf20Sopenharmony_ci	in.hactive = drm_mode->hdisplay;
9488c2ecf20Sopenharmony_ci	in.hporch = drm_mode->htotal - drm_mode->hdisplay;
9498c2ecf20Sopenharmony_ci	in.nlanes = ctrl->link->link_params.num_lanes;
9508c2ecf20Sopenharmony_ci	in.bpp = ctrl->panel->dp_mode.bpp;
9518c2ecf20Sopenharmony_ci	in.pixel_enc = 444;
9528c2ecf20Sopenharmony_ci	in.dsc_en = 0;
9538c2ecf20Sopenharmony_ci	in.async_en = 0;
9548c2ecf20Sopenharmony_ci	in.fec_en = 0;
9558c2ecf20Sopenharmony_ci	in.num_of_dsc_slices = 0;
9568c2ecf20Sopenharmony_ci	in.compress_ratio = 100;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	_dp_ctrl_calc_tu(&in, tu_table);
9598c2ecf20Sopenharmony_ci}
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_cistatic void dp_ctrl_setup_tr_unit(struct dp_ctrl_private *ctrl)
9628c2ecf20Sopenharmony_ci{
9638c2ecf20Sopenharmony_ci	u32 dp_tu = 0x0;
9648c2ecf20Sopenharmony_ci	u32 valid_boundary = 0x0;
9658c2ecf20Sopenharmony_ci	u32 valid_boundary2 = 0x0;
9668c2ecf20Sopenharmony_ci	struct dp_vc_tu_mapping_table tu_calc_table;
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	dp_ctrl_calc_tu_parameters(ctrl, &tu_calc_table);
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	dp_tu |= tu_calc_table.tu_size_minus1;
9718c2ecf20Sopenharmony_ci	valid_boundary |= tu_calc_table.valid_boundary_link;
9728c2ecf20Sopenharmony_ci	valid_boundary |= (tu_calc_table.delay_start_link << 16);
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	valid_boundary2 |= (tu_calc_table.valid_lower_boundary_link << 1);
9758c2ecf20Sopenharmony_ci	valid_boundary2 |= (tu_calc_table.upper_boundary_count << 16);
9768c2ecf20Sopenharmony_ci	valid_boundary2 |= (tu_calc_table.lower_boundary_count << 20);
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	if (tu_calc_table.boundary_moderation_en)
9798c2ecf20Sopenharmony_ci		valid_boundary2 |= BIT(0);
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	pr_debug("dp_tu=0x%x, valid_boundary=0x%x, valid_boundary2=0x%x\n",
9828c2ecf20Sopenharmony_ci			dp_tu, valid_boundary, valid_boundary2);
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	dp_catalog_ctrl_update_transfer_unit(ctrl->catalog,
9858c2ecf20Sopenharmony_ci				dp_tu, valid_boundary, valid_boundary2);
9868c2ecf20Sopenharmony_ci}
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_cistatic int dp_ctrl_wait4video_ready(struct dp_ctrl_private *ctrl)
9898c2ecf20Sopenharmony_ci{
9908c2ecf20Sopenharmony_ci	int ret = 0;
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	if (!wait_for_completion_timeout(&ctrl->video_comp,
9938c2ecf20Sopenharmony_ci				WAIT_FOR_VIDEO_READY_TIMEOUT_JIFFIES)) {
9948c2ecf20Sopenharmony_ci		DRM_ERROR("wait4video timedout\n");
9958c2ecf20Sopenharmony_ci		ret = -ETIMEDOUT;
9968c2ecf20Sopenharmony_ci	}
9978c2ecf20Sopenharmony_ci	return ret;
9988c2ecf20Sopenharmony_ci}
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_cistatic int dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl)
10018c2ecf20Sopenharmony_ci{
10028c2ecf20Sopenharmony_ci	struct dp_link *link = ctrl->link;
10038c2ecf20Sopenharmony_ci	int ret = 0, lane, lane_cnt;
10048c2ecf20Sopenharmony_ci	u8 buf[4];
10058c2ecf20Sopenharmony_ci	u32 max_level_reached = 0;
10068c2ecf20Sopenharmony_ci	u32 voltage_swing_level = link->phy_params.v_level;
10078c2ecf20Sopenharmony_ci	u32 pre_emphasis_level = link->phy_params.p_level;
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	ret = dp_catalog_ctrl_update_vx_px(ctrl->catalog,
10108c2ecf20Sopenharmony_ci		voltage_swing_level, pre_emphasis_level);
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	if (ret)
10138c2ecf20Sopenharmony_ci		return ret;
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	if (voltage_swing_level >= DP_TRAIN_VOLTAGE_SWING_MAX) {
10168c2ecf20Sopenharmony_ci		DRM_DEBUG_DP("max. voltage swing level reached %d\n",
10178c2ecf20Sopenharmony_ci				voltage_swing_level);
10188c2ecf20Sopenharmony_ci		max_level_reached |= DP_TRAIN_MAX_SWING_REACHED;
10198c2ecf20Sopenharmony_ci	}
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	if (pre_emphasis_level >= DP_TRAIN_PRE_EMPHASIS_MAX) {
10228c2ecf20Sopenharmony_ci		DRM_DEBUG_DP("max. pre-emphasis level reached %d\n",
10238c2ecf20Sopenharmony_ci				pre_emphasis_level);
10248c2ecf20Sopenharmony_ci		max_level_reached  |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
10258c2ecf20Sopenharmony_ci	}
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	pre_emphasis_level <<= DP_TRAIN_PRE_EMPHASIS_SHIFT;
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	lane_cnt = ctrl->link->link_params.num_lanes;
10308c2ecf20Sopenharmony_ci	for (lane = 0; lane < lane_cnt; lane++)
10318c2ecf20Sopenharmony_ci		buf[lane] = voltage_swing_level | pre_emphasis_level
10328c2ecf20Sopenharmony_ci				| max_level_reached;
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("sink: p|v=0x%x\n", voltage_swing_level
10358c2ecf20Sopenharmony_ci					| pre_emphasis_level);
10368c2ecf20Sopenharmony_ci	ret = drm_dp_dpcd_write(ctrl->aux, DP_TRAINING_LANE0_SET,
10378c2ecf20Sopenharmony_ci					buf, lane_cnt);
10388c2ecf20Sopenharmony_ci	if (ret == lane_cnt)
10398c2ecf20Sopenharmony_ci		ret = 0;
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	return ret;
10428c2ecf20Sopenharmony_ci}
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_cistatic bool dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl,
10458c2ecf20Sopenharmony_ci		u8 pattern)
10468c2ecf20Sopenharmony_ci{
10478c2ecf20Sopenharmony_ci	u8 buf;
10488c2ecf20Sopenharmony_ci	int ret = 0;
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("sink: pattern=%x\n", pattern);
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	buf = pattern;
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	if (pattern && pattern != DP_TRAINING_PATTERN_4)
10558c2ecf20Sopenharmony_ci		buf |= DP_LINK_SCRAMBLING_DISABLE;
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	ret = drm_dp_dpcd_writeb(ctrl->aux, DP_TRAINING_PATTERN_SET, buf);
10588c2ecf20Sopenharmony_ci	return ret == 1;
10598c2ecf20Sopenharmony_ci}
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_cistatic int dp_ctrl_read_link_status(struct dp_ctrl_private *ctrl,
10628c2ecf20Sopenharmony_ci				    u8 *link_status)
10638c2ecf20Sopenharmony_ci{
10648c2ecf20Sopenharmony_ci	int ret = 0, len;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	len = drm_dp_dpcd_read_link_status(ctrl->aux, link_status);
10678c2ecf20Sopenharmony_ci	if (len != DP_LINK_STATUS_SIZE) {
10688c2ecf20Sopenharmony_ci		DRM_ERROR("DP link status read failed, err: %d\n", len);
10698c2ecf20Sopenharmony_ci		ret = -EINVAL;
10708c2ecf20Sopenharmony_ci	}
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	return ret;
10738c2ecf20Sopenharmony_ci}
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_cistatic int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl,
10768c2ecf20Sopenharmony_ci		struct dp_cr_status *cr, int *training_step)
10778c2ecf20Sopenharmony_ci{
10788c2ecf20Sopenharmony_ci	int tries, old_v_level, ret = 0;
10798c2ecf20Sopenharmony_ci	u8 link_status[DP_LINK_STATUS_SIZE];
10808c2ecf20Sopenharmony_ci	int const maximum_retries = 4;
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	*training_step = DP_TRAINING_1;
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	ret = dp_catalog_ctrl_set_pattern(ctrl->catalog, DP_TRAINING_PATTERN_1);
10878c2ecf20Sopenharmony_ci	if (ret)
10888c2ecf20Sopenharmony_ci		return ret;
10898c2ecf20Sopenharmony_ci	dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 |
10908c2ecf20Sopenharmony_ci		DP_LINK_SCRAMBLING_DISABLE);
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	ret = dp_ctrl_update_vx_px(ctrl);
10938c2ecf20Sopenharmony_ci	if (ret)
10948c2ecf20Sopenharmony_ci		return ret;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	tries = 0;
10978c2ecf20Sopenharmony_ci	old_v_level = ctrl->link->phy_params.v_level;
10988c2ecf20Sopenharmony_ci	for (tries = 0; tries < maximum_retries; tries++) {
10998c2ecf20Sopenharmony_ci		drm_dp_link_train_clock_recovery_delay(ctrl->panel->dpcd);
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci		ret = dp_ctrl_read_link_status(ctrl, link_status);
11028c2ecf20Sopenharmony_ci		if (ret)
11038c2ecf20Sopenharmony_ci			return ret;
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci		cr->lane_0_1 = link_status[0];
11068c2ecf20Sopenharmony_ci		cr->lane_2_3 = link_status[1];
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci		if (drm_dp_clock_recovery_ok(link_status,
11098c2ecf20Sopenharmony_ci			ctrl->link->link_params.num_lanes)) {
11108c2ecf20Sopenharmony_ci			return 0;
11118c2ecf20Sopenharmony_ci		}
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci		if (ctrl->link->phy_params.v_level >=
11148c2ecf20Sopenharmony_ci			DP_TRAIN_VOLTAGE_SWING_MAX) {
11158c2ecf20Sopenharmony_ci			DRM_ERROR_RATELIMITED("max v_level reached\n");
11168c2ecf20Sopenharmony_ci			return -EAGAIN;
11178c2ecf20Sopenharmony_ci		}
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci		if (old_v_level != ctrl->link->phy_params.v_level) {
11208c2ecf20Sopenharmony_ci			tries = 0;
11218c2ecf20Sopenharmony_ci			old_v_level = ctrl->link->phy_params.v_level;
11228c2ecf20Sopenharmony_ci		}
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci		DRM_DEBUG_DP("clock recovery not done, adjusting vx px\n");
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci		dp_link_adjust_levels(ctrl->link, link_status);
11278c2ecf20Sopenharmony_ci		ret = dp_ctrl_update_vx_px(ctrl);
11288c2ecf20Sopenharmony_ci		if (ret)
11298c2ecf20Sopenharmony_ci			return ret;
11308c2ecf20Sopenharmony_ci	}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	DRM_ERROR("max tries reached\n");
11338c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
11348c2ecf20Sopenharmony_ci}
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_cistatic int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl)
11378c2ecf20Sopenharmony_ci{
11388c2ecf20Sopenharmony_ci	int ret = 0;
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	switch (ctrl->link->link_params.rate) {
11418c2ecf20Sopenharmony_ci	case 810000:
11428c2ecf20Sopenharmony_ci		ctrl->link->link_params.rate = 540000;
11438c2ecf20Sopenharmony_ci		break;
11448c2ecf20Sopenharmony_ci	case 540000:
11458c2ecf20Sopenharmony_ci		ctrl->link->link_params.rate = 270000;
11468c2ecf20Sopenharmony_ci		break;
11478c2ecf20Sopenharmony_ci	case 270000:
11488c2ecf20Sopenharmony_ci		ctrl->link->link_params.rate = 162000;
11498c2ecf20Sopenharmony_ci		break;
11508c2ecf20Sopenharmony_ci	case 162000:
11518c2ecf20Sopenharmony_ci	default:
11528c2ecf20Sopenharmony_ci		ret = -EINVAL;
11538c2ecf20Sopenharmony_ci		break;
11548c2ecf20Sopenharmony_ci	};
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci	if (!ret)
11578c2ecf20Sopenharmony_ci		DRM_DEBUG_DP("new rate=0x%x\n", ctrl->link->link_params.rate);
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	return ret;
11608c2ecf20Sopenharmony_ci}
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_cistatic int dp_ctrl_link_lane_down_shift(struct dp_ctrl_private *ctrl)
11638c2ecf20Sopenharmony_ci{
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	if (ctrl->link->link_params.num_lanes == 1)
11668c2ecf20Sopenharmony_ci		return -1;
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	ctrl->link->link_params.num_lanes /= 2;
11698c2ecf20Sopenharmony_ci	ctrl->link->link_params.rate = ctrl->panel->link_info.rate;
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	ctrl->link->phy_params.p_level = 0;
11728c2ecf20Sopenharmony_ci	ctrl->link->phy_params.v_level = 0;
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci	return 0;
11758c2ecf20Sopenharmony_ci}
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_cistatic void dp_ctrl_clear_training_pattern(struct dp_ctrl_private *ctrl)
11788c2ecf20Sopenharmony_ci{
11798c2ecf20Sopenharmony_ci	dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_DISABLE);
11808c2ecf20Sopenharmony_ci	drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
11818c2ecf20Sopenharmony_ci}
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_cistatic int dp_ctrl_link_train_2(struct dp_ctrl_private *ctrl,
11848c2ecf20Sopenharmony_ci		struct dp_cr_status *cr, int *training_step)
11858c2ecf20Sopenharmony_ci{
11868c2ecf20Sopenharmony_ci	int tries = 0, ret = 0;
11878c2ecf20Sopenharmony_ci	char pattern;
11888c2ecf20Sopenharmony_ci	int const maximum_retries = 5;
11898c2ecf20Sopenharmony_ci	u8 link_status[DP_LINK_STATUS_SIZE];
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	*training_step = DP_TRAINING_2;
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	if (drm_dp_tps3_supported(ctrl->panel->dpcd))
11968c2ecf20Sopenharmony_ci		pattern = DP_TRAINING_PATTERN_3;
11978c2ecf20Sopenharmony_ci	else
11988c2ecf20Sopenharmony_ci		pattern = DP_TRAINING_PATTERN_2;
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	ret = dp_ctrl_update_vx_px(ctrl);
12018c2ecf20Sopenharmony_ci	if (ret)
12028c2ecf20Sopenharmony_ci		return ret;
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci	ret = dp_catalog_ctrl_set_pattern(ctrl->catalog, pattern);
12058c2ecf20Sopenharmony_ci	if (ret)
12068c2ecf20Sopenharmony_ci		return ret;
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	dp_ctrl_train_pattern_set(ctrl, pattern);
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	for (tries = 0; tries <= maximum_retries; tries++) {
12118c2ecf20Sopenharmony_ci		drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci		ret = dp_ctrl_read_link_status(ctrl, link_status);
12148c2ecf20Sopenharmony_ci		if (ret)
12158c2ecf20Sopenharmony_ci			return ret;
12168c2ecf20Sopenharmony_ci		cr->lane_0_1 = link_status[0];
12178c2ecf20Sopenharmony_ci		cr->lane_2_3 = link_status[1];
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci		if (drm_dp_channel_eq_ok(link_status,
12208c2ecf20Sopenharmony_ci			ctrl->link->link_params.num_lanes)) {
12218c2ecf20Sopenharmony_ci			return 0;
12228c2ecf20Sopenharmony_ci		}
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci		dp_link_adjust_levels(ctrl->link, link_status);
12258c2ecf20Sopenharmony_ci		ret = dp_ctrl_update_vx_px(ctrl);
12268c2ecf20Sopenharmony_ci		if (ret)
12278c2ecf20Sopenharmony_ci			return ret;
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci	}
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
12328c2ecf20Sopenharmony_ci}
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_cistatic int dp_ctrl_reinitialize_mainlink(struct dp_ctrl_private *ctrl);
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_cistatic int dp_ctrl_link_train(struct dp_ctrl_private *ctrl,
12378c2ecf20Sopenharmony_ci		struct dp_cr_status *cr, int *training_step)
12388c2ecf20Sopenharmony_ci{
12398c2ecf20Sopenharmony_ci	int ret = 0;
12408c2ecf20Sopenharmony_ci	u8 encoding = DP_SET_ANSI_8B10B;
12418c2ecf20Sopenharmony_ci	struct dp_link_info link_info = {0};
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	dp_ctrl_config_ctrl(ctrl);
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci	link_info.num_lanes = ctrl->link->link_params.num_lanes;
12468c2ecf20Sopenharmony_ci	link_info.rate = ctrl->link->link_params.rate;
12478c2ecf20Sopenharmony_ci	link_info.capabilities = DP_LINK_CAP_ENHANCED_FRAMING;
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci	dp_aux_link_configure(ctrl->aux, &link_info);
12508c2ecf20Sopenharmony_ci	drm_dp_dpcd_write(ctrl->aux, DP_MAIN_LINK_CHANNEL_CODING_SET,
12518c2ecf20Sopenharmony_ci				&encoding, 1);
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	ret = dp_ctrl_link_train_1(ctrl, cr, training_step);
12548c2ecf20Sopenharmony_ci	if (ret) {
12558c2ecf20Sopenharmony_ci		DRM_ERROR("link training #1 failed. ret=%d\n", ret);
12568c2ecf20Sopenharmony_ci		goto end;
12578c2ecf20Sopenharmony_ci	}
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	/* print success info as this is a result of user initiated action */
12608c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("link training #1 successful\n");
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci	ret = dp_ctrl_link_train_2(ctrl, cr, training_step);
12638c2ecf20Sopenharmony_ci	if (ret) {
12648c2ecf20Sopenharmony_ci		DRM_ERROR("link training #2 failed. ret=%d\n", ret);
12658c2ecf20Sopenharmony_ci		goto end;
12668c2ecf20Sopenharmony_ci	}
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci	/* print success info as this is a result of user initiated action */
12698c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("link training #2 successful\n");
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ciend:
12728c2ecf20Sopenharmony_ci	dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	return ret;
12758c2ecf20Sopenharmony_ci}
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_cistatic int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl,
12788c2ecf20Sopenharmony_ci		struct dp_cr_status *cr, int *training_step)
12798c2ecf20Sopenharmony_ci{
12808c2ecf20Sopenharmony_ci	int ret = 0;
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci	dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true);
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
12858c2ecf20Sopenharmony_ci		return ret;
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	/*
12888c2ecf20Sopenharmony_ci	 * As part of previous calls, DP controller state might have
12898c2ecf20Sopenharmony_ci	 * transitioned to PUSH_IDLE. In order to start transmitting
12908c2ecf20Sopenharmony_ci	 * a link training pattern, we have to first do soft reset.
12918c2ecf20Sopenharmony_ci	 */
12928c2ecf20Sopenharmony_ci	dp_catalog_ctrl_reset(ctrl->catalog);
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	ret = dp_ctrl_link_train(ctrl, cr, training_step);
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci	return ret;
12978c2ecf20Sopenharmony_ci}
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_cistatic void dp_ctrl_set_clock_rate(struct dp_ctrl_private *ctrl,
13008c2ecf20Sopenharmony_ci			enum dp_pm_type module, char *name, unsigned long rate)
13018c2ecf20Sopenharmony_ci{
13028c2ecf20Sopenharmony_ci	u32 num = ctrl->parser->mp[module].num_clk;
13038c2ecf20Sopenharmony_ci	struct dss_clk *cfg = ctrl->parser->mp[module].clk_config;
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci	while (num && strcmp(cfg->clk_name, name)) {
13068c2ecf20Sopenharmony_ci		num--;
13078c2ecf20Sopenharmony_ci		cfg++;
13088c2ecf20Sopenharmony_ci	}
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("setting rate=%lu on clk=%s\n", rate, name);
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	if (num)
13138c2ecf20Sopenharmony_ci		cfg->rate = rate;
13148c2ecf20Sopenharmony_ci	else
13158c2ecf20Sopenharmony_ci		DRM_ERROR("%s clock doesn't exit to set rate %lu\n",
13168c2ecf20Sopenharmony_ci				name, rate);
13178c2ecf20Sopenharmony_ci}
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_cistatic int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl)
13208c2ecf20Sopenharmony_ci{
13218c2ecf20Sopenharmony_ci	int ret = 0;
13228c2ecf20Sopenharmony_ci	struct dp_io *dp_io = &ctrl->parser->io;
13238c2ecf20Sopenharmony_ci	struct phy *phy = dp_io->phy;
13248c2ecf20Sopenharmony_ci	struct phy_configure_opts_dp *opts_dp = &dp_io->phy_opts.dp;
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci	opts_dp->lanes = ctrl->link->link_params.num_lanes;
13278c2ecf20Sopenharmony_ci	opts_dp->link_rate = ctrl->link->link_params.rate / 100;
13288c2ecf20Sopenharmony_ci	dp_ctrl_set_clock_rate(ctrl, DP_CTRL_PM, "ctrl_link",
13298c2ecf20Sopenharmony_ci					ctrl->link->link_params.rate * 1000);
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci	phy_configure(phy, &dp_io->phy_opts);
13328c2ecf20Sopenharmony_ci	phy_power_on(phy);
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci	ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, true);
13358c2ecf20Sopenharmony_ci	if (ret)
13368c2ecf20Sopenharmony_ci		DRM_ERROR("Unable to start link clocks. ret=%d\n", ret);
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("link rate=%d pixel_clk=%d\n",
13398c2ecf20Sopenharmony_ci		ctrl->link->link_params.rate, ctrl->dp_ctrl.pixel_rate);
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci	return ret;
13428c2ecf20Sopenharmony_ci}
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_cistatic int dp_ctrl_enable_stream_clocks(struct dp_ctrl_private *ctrl)
13458c2ecf20Sopenharmony_ci{
13468c2ecf20Sopenharmony_ci	int ret = 0;
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	dp_ctrl_set_clock_rate(ctrl, DP_STREAM_PM, "stream_pixel",
13498c2ecf20Sopenharmony_ci					ctrl->dp_ctrl.pixel_rate * 1000);
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	ret = dp_power_clk_enable(ctrl->power, DP_STREAM_PM, true);
13528c2ecf20Sopenharmony_ci	if (ret)
13538c2ecf20Sopenharmony_ci		DRM_ERROR("Unabled to start pixel clocks. ret=%d\n", ret);
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("link rate=%d pixel_clk=%d\n",
13568c2ecf20Sopenharmony_ci			ctrl->link->link_params.rate, ctrl->dp_ctrl.pixel_rate);
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	return ret;
13598c2ecf20Sopenharmony_ci}
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ciint dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip)
13628c2ecf20Sopenharmony_ci{
13638c2ecf20Sopenharmony_ci	struct dp_ctrl_private *ctrl;
13648c2ecf20Sopenharmony_ci	struct dp_io *dp_io;
13658c2ecf20Sopenharmony_ci	struct phy *phy;
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	if (!dp_ctrl) {
13688c2ecf20Sopenharmony_ci		DRM_ERROR("Invalid input data\n");
13698c2ecf20Sopenharmony_ci		return -EINVAL;
13708c2ecf20Sopenharmony_ci	}
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_ci	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
13738c2ecf20Sopenharmony_ci	dp_io = &ctrl->parser->io;
13748c2ecf20Sopenharmony_ci	phy = dp_io->phy;
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci	ctrl->dp_ctrl.orientation = flip;
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	dp_catalog_ctrl_phy_reset(ctrl->catalog);
13798c2ecf20Sopenharmony_ci	phy_init(phy);
13808c2ecf20Sopenharmony_ci	dp_catalog_ctrl_enable_irq(ctrl->catalog, true);
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	return 0;
13838c2ecf20Sopenharmony_ci}
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci/**
13868c2ecf20Sopenharmony_ci * dp_ctrl_host_deinit() - Uninitialize DP controller
13878c2ecf20Sopenharmony_ci * @dp_ctrl: Display Port Driver data
13888c2ecf20Sopenharmony_ci *
13898c2ecf20Sopenharmony_ci * Perform required steps to uninitialize DP controller
13908c2ecf20Sopenharmony_ci * and its resources.
13918c2ecf20Sopenharmony_ci */
13928c2ecf20Sopenharmony_civoid dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl)
13938c2ecf20Sopenharmony_ci{
13948c2ecf20Sopenharmony_ci	struct dp_ctrl_private *ctrl;
13958c2ecf20Sopenharmony_ci	struct dp_io *dp_io;
13968c2ecf20Sopenharmony_ci	struct phy *phy;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	if (!dp_ctrl) {
13998c2ecf20Sopenharmony_ci		DRM_ERROR("Invalid input data\n");
14008c2ecf20Sopenharmony_ci		return;
14018c2ecf20Sopenharmony_ci	}
14028c2ecf20Sopenharmony_ci
14038c2ecf20Sopenharmony_ci	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
14048c2ecf20Sopenharmony_ci	dp_io = &ctrl->parser->io;
14058c2ecf20Sopenharmony_ci	phy = dp_io->phy;
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci	dp_catalog_ctrl_enable_irq(ctrl->catalog, false);
14088c2ecf20Sopenharmony_ci	phy_exit(phy);
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("Host deinitialized successfully\n");
14118c2ecf20Sopenharmony_ci}
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_cistatic bool dp_ctrl_use_fixed_nvid(struct dp_ctrl_private *ctrl)
14148c2ecf20Sopenharmony_ci{
14158c2ecf20Sopenharmony_ci	u8 *dpcd = ctrl->panel->dpcd;
14168c2ecf20Sopenharmony_ci	u32 edid_quirks = 0;
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	edid_quirks = drm_dp_get_edid_quirks(ctrl->panel->edid);
14198c2ecf20Sopenharmony_ci	/*
14208c2ecf20Sopenharmony_ci	 * For better interop experience, used a fixed NVID=0x8000
14218c2ecf20Sopenharmony_ci	 * whenever connected to a VGA dongle downstream.
14228c2ecf20Sopenharmony_ci	 */
14238c2ecf20Sopenharmony_ci	if (drm_dp_is_branch(dpcd))
14248c2ecf20Sopenharmony_ci		return (drm_dp_has_quirk(&ctrl->panel->desc, edid_quirks,
14258c2ecf20Sopenharmony_ci				DP_DPCD_QUIRK_CONSTANT_N));
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci	return false;
14288c2ecf20Sopenharmony_ci}
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_cistatic int dp_ctrl_reinitialize_mainlink(struct dp_ctrl_private *ctrl)
14318c2ecf20Sopenharmony_ci{
14328c2ecf20Sopenharmony_ci	int ret = 0;
14338c2ecf20Sopenharmony_ci	struct dp_io *dp_io = &ctrl->parser->io;
14348c2ecf20Sopenharmony_ci	struct phy *phy = dp_io->phy;
14358c2ecf20Sopenharmony_ci	struct phy_configure_opts_dp *opts_dp = &dp_io->phy_opts.dp;
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci	dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
14388c2ecf20Sopenharmony_ci	opts_dp->lanes = ctrl->link->link_params.num_lanes;
14398c2ecf20Sopenharmony_ci	phy_configure(phy, &dp_io->phy_opts);
14408c2ecf20Sopenharmony_ci	/*
14418c2ecf20Sopenharmony_ci	 * Disable and re-enable the mainlink clock since the
14428c2ecf20Sopenharmony_ci	 * link clock might have been adjusted as part of the
14438c2ecf20Sopenharmony_ci	 * link maintenance.
14448c2ecf20Sopenharmony_ci	 */
14458c2ecf20Sopenharmony_ci	ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false);
14468c2ecf20Sopenharmony_ci	if (ret) {
14478c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to disable clocks. ret=%d\n", ret);
14488c2ecf20Sopenharmony_ci		return ret;
14498c2ecf20Sopenharmony_ci	}
14508c2ecf20Sopenharmony_ci	phy_power_off(phy);
14518c2ecf20Sopenharmony_ci	/* hw recommended delay before re-enabling clocks */
14528c2ecf20Sopenharmony_ci	msleep(20);
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	ret = dp_ctrl_enable_mainlink_clocks(ctrl);
14558c2ecf20Sopenharmony_ci	if (ret) {
14568c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to enable mainlink clks. ret=%d\n", ret);
14578c2ecf20Sopenharmony_ci		return ret;
14588c2ecf20Sopenharmony_ci	}
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci	return ret;
14618c2ecf20Sopenharmony_ci}
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_cistatic int dp_ctrl_deinitialize_mainlink(struct dp_ctrl_private *ctrl)
14648c2ecf20Sopenharmony_ci{
14658c2ecf20Sopenharmony_ci	struct dp_io *dp_io;
14668c2ecf20Sopenharmony_ci	struct phy *phy;
14678c2ecf20Sopenharmony_ci	int ret;
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci	dp_io = &ctrl->parser->io;
14708c2ecf20Sopenharmony_ci	phy = dp_io->phy;
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci	dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
14738c2ecf20Sopenharmony_ci
14748c2ecf20Sopenharmony_ci	dp_catalog_ctrl_reset(ctrl->catalog);
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci	ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false);
14778c2ecf20Sopenharmony_ci	if (ret) {
14788c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret);
14798c2ecf20Sopenharmony_ci	}
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	phy_power_off(phy);
14828c2ecf20Sopenharmony_ci	phy_exit(phy);
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	return 0;
14858c2ecf20Sopenharmony_ci}
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_cistatic int dp_ctrl_link_maintenance(struct dp_ctrl_private *ctrl)
14888c2ecf20Sopenharmony_ci{
14898c2ecf20Sopenharmony_ci	int ret = 0;
14908c2ecf20Sopenharmony_ci	struct dp_cr_status cr;
14918c2ecf20Sopenharmony_ci	int training_step = DP_TRAINING_NONE;
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_ci	dp_ctrl_push_idle(&ctrl->dp_ctrl);
14948c2ecf20Sopenharmony_ci	dp_catalog_ctrl_reset(ctrl->catalog);
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	ctrl->dp_ctrl.pixel_rate = ctrl->panel->dp_mode.drm_mode.clock;
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci	ret = dp_ctrl_setup_main_link(ctrl, &cr, &training_step);
14998c2ecf20Sopenharmony_ci	if (ret)
15008c2ecf20Sopenharmony_ci		goto end;
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	dp_ctrl_clear_training_pattern(ctrl);
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO);
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci	ret = dp_ctrl_wait4video_ready(ctrl);
15078c2ecf20Sopenharmony_ciend:
15088c2ecf20Sopenharmony_ci	return ret;
15098c2ecf20Sopenharmony_ci}
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_cistatic int dp_ctrl_process_phy_test_request(struct dp_ctrl_private *ctrl)
15128c2ecf20Sopenharmony_ci{
15138c2ecf20Sopenharmony_ci	int ret = 0;
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci	if (!ctrl->link->phy_params.phy_test_pattern_sel) {
15168c2ecf20Sopenharmony_ci		DRM_DEBUG_DP("no test pattern selected by sink\n");
15178c2ecf20Sopenharmony_ci		return ret;
15188c2ecf20Sopenharmony_ci	}
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci	/*
15218c2ecf20Sopenharmony_ci	 * The global reset will need DP link related clocks to be
15228c2ecf20Sopenharmony_ci	 * running. Add the global reset just before disabling the
15238c2ecf20Sopenharmony_ci	 * link clocks and core clocks.
15248c2ecf20Sopenharmony_ci	 */
15258c2ecf20Sopenharmony_ci	ret = dp_ctrl_off(&ctrl->dp_ctrl);
15268c2ecf20Sopenharmony_ci	if (ret) {
15278c2ecf20Sopenharmony_ci		DRM_ERROR("failed to disable DP controller\n");
15288c2ecf20Sopenharmony_ci		return ret;
15298c2ecf20Sopenharmony_ci	}
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci	ret = dp_ctrl_on_link(&ctrl->dp_ctrl);
15328c2ecf20Sopenharmony_ci	if (!ret)
15338c2ecf20Sopenharmony_ci		ret = dp_ctrl_on_stream(&ctrl->dp_ctrl);
15348c2ecf20Sopenharmony_ci	else
15358c2ecf20Sopenharmony_ci		DRM_ERROR("failed to enable DP link controller\n");
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	return ret;
15388c2ecf20Sopenharmony_ci}
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_cistatic bool dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl)
15418c2ecf20Sopenharmony_ci{
15428c2ecf20Sopenharmony_ci	bool success = false;
15438c2ecf20Sopenharmony_ci	u32 pattern_sent = 0x0;
15448c2ecf20Sopenharmony_ci	u32 pattern_requested = ctrl->link->phy_params.phy_test_pattern_sel;
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("request: 0x%x\n", pattern_requested);
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci	if (dp_catalog_ctrl_update_vx_px(ctrl->catalog,
15498c2ecf20Sopenharmony_ci			ctrl->link->phy_params.v_level,
15508c2ecf20Sopenharmony_ci			ctrl->link->phy_params.p_level)) {
15518c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to set v/p levels\n");
15528c2ecf20Sopenharmony_ci		return false;
15538c2ecf20Sopenharmony_ci	}
15548c2ecf20Sopenharmony_ci	dp_catalog_ctrl_send_phy_pattern(ctrl->catalog, pattern_requested);
15558c2ecf20Sopenharmony_ci	dp_ctrl_update_vx_px(ctrl);
15568c2ecf20Sopenharmony_ci	dp_link_send_test_response(ctrl->link);
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci	pattern_sent = dp_catalog_ctrl_read_phy_pattern(ctrl->catalog);
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	switch (pattern_sent) {
15618c2ecf20Sopenharmony_ci	case MR_LINK_TRAINING1:
15628c2ecf20Sopenharmony_ci		success = (pattern_requested ==
15638c2ecf20Sopenharmony_ci				DP_PHY_TEST_PATTERN_D10_2);
15648c2ecf20Sopenharmony_ci		break;
15658c2ecf20Sopenharmony_ci	case MR_LINK_SYMBOL_ERM:
15668c2ecf20Sopenharmony_ci		success = ((pattern_requested ==
15678c2ecf20Sopenharmony_ci			DP_PHY_TEST_PATTERN_ERROR_COUNT) ||
15688c2ecf20Sopenharmony_ci				(pattern_requested ==
15698c2ecf20Sopenharmony_ci				DP_PHY_TEST_PATTERN_CP2520));
15708c2ecf20Sopenharmony_ci		break;
15718c2ecf20Sopenharmony_ci	case MR_LINK_PRBS7:
15728c2ecf20Sopenharmony_ci		success = (pattern_requested ==
15738c2ecf20Sopenharmony_ci				DP_PHY_TEST_PATTERN_PRBS7);
15748c2ecf20Sopenharmony_ci		break;
15758c2ecf20Sopenharmony_ci	case MR_LINK_CUSTOM80:
15768c2ecf20Sopenharmony_ci		success = (pattern_requested ==
15778c2ecf20Sopenharmony_ci				DP_PHY_TEST_PATTERN_80BIT_CUSTOM);
15788c2ecf20Sopenharmony_ci		break;
15798c2ecf20Sopenharmony_ci	case MR_LINK_TRAINING4:
15808c2ecf20Sopenharmony_ci		success = (pattern_requested ==
15818c2ecf20Sopenharmony_ci				DP_PHY_TEST_PATTERN_SEL_MASK);
15828c2ecf20Sopenharmony_ci		break;
15838c2ecf20Sopenharmony_ci	default:
15848c2ecf20Sopenharmony_ci		success = false;
15858c2ecf20Sopenharmony_ci	}
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("%s: test->0x%x\n", success ? "success" : "failed",
15888c2ecf20Sopenharmony_ci						pattern_requested);
15898c2ecf20Sopenharmony_ci	return success;
15908c2ecf20Sopenharmony_ci}
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_civoid dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl)
15938c2ecf20Sopenharmony_ci{
15948c2ecf20Sopenharmony_ci	struct dp_ctrl_private *ctrl;
15958c2ecf20Sopenharmony_ci	u32 sink_request = 0x0;
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	if (!dp_ctrl) {
15988c2ecf20Sopenharmony_ci		DRM_ERROR("invalid input\n");
15998c2ecf20Sopenharmony_ci		return;
16008c2ecf20Sopenharmony_ci	}
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
16038c2ecf20Sopenharmony_ci	sink_request = ctrl->link->sink_request;
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci	if (sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
16068c2ecf20Sopenharmony_ci		DRM_DEBUG_DP("PHY_TEST_PATTERN request\n");
16078c2ecf20Sopenharmony_ci		if (dp_ctrl_process_phy_test_request(ctrl)) {
16088c2ecf20Sopenharmony_ci			DRM_ERROR("process phy_test_req failed\n");
16098c2ecf20Sopenharmony_ci			return;
16108c2ecf20Sopenharmony_ci		}
16118c2ecf20Sopenharmony_ci	}
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci	if (sink_request & DP_LINK_STATUS_UPDATED) {
16148c2ecf20Sopenharmony_ci		if (dp_ctrl_link_maintenance(ctrl)) {
16158c2ecf20Sopenharmony_ci			DRM_ERROR("LM failed: TEST_LINK_TRAINING\n");
16168c2ecf20Sopenharmony_ci			return;
16178c2ecf20Sopenharmony_ci		}
16188c2ecf20Sopenharmony_ci	}
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci	if (sink_request & DP_TEST_LINK_TRAINING) {
16218c2ecf20Sopenharmony_ci		dp_link_send_test_response(ctrl->link);
16228c2ecf20Sopenharmony_ci		if (dp_ctrl_link_maintenance(ctrl)) {
16238c2ecf20Sopenharmony_ci			DRM_ERROR("LM failed: TEST_LINK_TRAINING\n");
16248c2ecf20Sopenharmony_ci			return;
16258c2ecf20Sopenharmony_ci		}
16268c2ecf20Sopenharmony_ci	}
16278c2ecf20Sopenharmony_ci}
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_ciint dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
16308c2ecf20Sopenharmony_ci{
16318c2ecf20Sopenharmony_ci	int rc = 0;
16328c2ecf20Sopenharmony_ci	struct dp_ctrl_private *ctrl;
16338c2ecf20Sopenharmony_ci	u32 rate = 0;
16348c2ecf20Sopenharmony_ci	int link_train_max_retries = 5;
16358c2ecf20Sopenharmony_ci	u32 const phy_cts_pixel_clk_khz = 148500;
16368c2ecf20Sopenharmony_ci	struct dp_cr_status cr;
16378c2ecf20Sopenharmony_ci	unsigned int training_step;
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci	if (!dp_ctrl)
16408c2ecf20Sopenharmony_ci		return -EINVAL;
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_ci	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci	rate = ctrl->panel->link_info.rate;
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_ci	dp_power_clk_enable(ctrl->power, DP_CORE_PM, true);
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci	if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
16498c2ecf20Sopenharmony_ci		DRM_DEBUG_DP("using phy test link parameters\n");
16508c2ecf20Sopenharmony_ci		if (!ctrl->panel->dp_mode.drm_mode.clock)
16518c2ecf20Sopenharmony_ci			ctrl->dp_ctrl.pixel_rate = phy_cts_pixel_clk_khz;
16528c2ecf20Sopenharmony_ci	} else {
16538c2ecf20Sopenharmony_ci		ctrl->link->link_params.rate = rate;
16548c2ecf20Sopenharmony_ci		ctrl->link->link_params.num_lanes =
16558c2ecf20Sopenharmony_ci			ctrl->panel->link_info.num_lanes;
16568c2ecf20Sopenharmony_ci		ctrl->dp_ctrl.pixel_rate = ctrl->panel->dp_mode.drm_mode.clock;
16578c2ecf20Sopenharmony_ci	}
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("rate=%d, num_lanes=%d, pixel_rate=%d\n",
16608c2ecf20Sopenharmony_ci		ctrl->link->link_params.rate,
16618c2ecf20Sopenharmony_ci		ctrl->link->link_params.num_lanes, ctrl->dp_ctrl.pixel_rate);
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_ci	rc = dp_ctrl_enable_mainlink_clocks(ctrl);
16648c2ecf20Sopenharmony_ci	if (rc)
16658c2ecf20Sopenharmony_ci		return rc;
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci	while (--link_train_max_retries) {
16688c2ecf20Sopenharmony_ci		training_step = DP_TRAINING_NONE;
16698c2ecf20Sopenharmony_ci		rc = dp_ctrl_setup_main_link(ctrl, &cr, &training_step);
16708c2ecf20Sopenharmony_ci		if (rc == 0) {
16718c2ecf20Sopenharmony_ci			/* training completed successfully */
16728c2ecf20Sopenharmony_ci			break;
16738c2ecf20Sopenharmony_ci		} else if (training_step == DP_TRAINING_1) {
16748c2ecf20Sopenharmony_ci			/* link train_1 failed */
16758c2ecf20Sopenharmony_ci			if (!dp_catalog_link_is_connected(ctrl->catalog)) {
16768c2ecf20Sopenharmony_ci				break;
16778c2ecf20Sopenharmony_ci			}
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_ci			rc = dp_ctrl_link_rate_down_shift(ctrl);
16808c2ecf20Sopenharmony_ci			if (rc < 0) { /* already in RBR = 1.6G */
16818c2ecf20Sopenharmony_ci				if (cr.lane_0_1 & DP_LANE0_1_CR_DONE) {
16828c2ecf20Sopenharmony_ci					/*
16838c2ecf20Sopenharmony_ci					 * some lanes are ready,
16848c2ecf20Sopenharmony_ci					 * reduce lane number
16858c2ecf20Sopenharmony_ci					 */
16868c2ecf20Sopenharmony_ci					rc = dp_ctrl_link_lane_down_shift(ctrl);
16878c2ecf20Sopenharmony_ci					if (rc < 0) { /* lane == 1 already */
16888c2ecf20Sopenharmony_ci						/* end with failure */
16898c2ecf20Sopenharmony_ci						break;
16908c2ecf20Sopenharmony_ci					}
16918c2ecf20Sopenharmony_ci				} else {
16928c2ecf20Sopenharmony_ci					/* end with failure */
16938c2ecf20Sopenharmony_ci					break; /* lane == 1 already */
16948c2ecf20Sopenharmony_ci				}
16958c2ecf20Sopenharmony_ci			}
16968c2ecf20Sopenharmony_ci		} else if (training_step == DP_TRAINING_2) {
16978c2ecf20Sopenharmony_ci			/* link train_2 failed, lower lane rate */
16988c2ecf20Sopenharmony_ci			if (!dp_catalog_link_is_connected(ctrl->catalog)) {
16998c2ecf20Sopenharmony_ci				break;
17008c2ecf20Sopenharmony_ci			}
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci			rc = dp_ctrl_link_lane_down_shift(ctrl);
17038c2ecf20Sopenharmony_ci			if (rc < 0) {
17048c2ecf20Sopenharmony_ci				/* end with failure */
17058c2ecf20Sopenharmony_ci				break; /* lane == 1 already */
17068c2ecf20Sopenharmony_ci			}
17078c2ecf20Sopenharmony_ci		}
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci		rc = dp_ctrl_reinitialize_mainlink(ctrl);
17108c2ecf20Sopenharmony_ci		if (rc) {
17118c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to reinitialize mainlink. rc=%d\n", rc);
17128c2ecf20Sopenharmony_ci			break;
17138c2ecf20Sopenharmony_ci		}
17148c2ecf20Sopenharmony_ci	}
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_ci	if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
17178c2ecf20Sopenharmony_ci		return rc;
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci	/* stop txing train pattern */
17208c2ecf20Sopenharmony_ci	dp_ctrl_clear_training_pattern(ctrl);
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	/*
17238c2ecf20Sopenharmony_ci	 * keep transmitting idle pattern until video ready
17248c2ecf20Sopenharmony_ci	 * to avoid main link from loss of sync
17258c2ecf20Sopenharmony_ci	 */
17268c2ecf20Sopenharmony_ci	if (rc == 0)  /* link train successfully */
17278c2ecf20Sopenharmony_ci		dp_ctrl_push_idle(dp_ctrl);
17288c2ecf20Sopenharmony_ci	else  {
17298c2ecf20Sopenharmony_ci		/* link training failed */
17308c2ecf20Sopenharmony_ci		dp_ctrl_deinitialize_mainlink(ctrl);
17318c2ecf20Sopenharmony_ci		rc = -ECONNRESET;
17328c2ecf20Sopenharmony_ci	}
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	return rc;
17358c2ecf20Sopenharmony_ci}
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_ciint dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl)
17388c2ecf20Sopenharmony_ci{
17398c2ecf20Sopenharmony_ci	u32 rate = 0;
17408c2ecf20Sopenharmony_ci	int ret = 0;
17418c2ecf20Sopenharmony_ci	bool mainlink_ready = false;
17428c2ecf20Sopenharmony_ci	struct dp_ctrl_private *ctrl;
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_ci	if (!dp_ctrl)
17458c2ecf20Sopenharmony_ci		return -EINVAL;
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_ci	rate = ctrl->panel->link_info.rate;
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci	ctrl->link->link_params.rate = rate;
17528c2ecf20Sopenharmony_ci	ctrl->link->link_params.num_lanes = ctrl->panel->link_info.num_lanes;
17538c2ecf20Sopenharmony_ci	ctrl->dp_ctrl.pixel_rate = ctrl->panel->dp_mode.drm_mode.clock;
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("rate=%d, num_lanes=%d, pixel_rate=%d\n",
17568c2ecf20Sopenharmony_ci		ctrl->link->link_params.rate,
17578c2ecf20Sopenharmony_ci		ctrl->link->link_params.num_lanes, ctrl->dp_ctrl.pixel_rate);
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci	if (!dp_power_clk_status(ctrl->power, DP_CTRL_PM)) { /* link clk is off */
17608c2ecf20Sopenharmony_ci		ret = dp_ctrl_enable_mainlink_clocks(ctrl);
17618c2ecf20Sopenharmony_ci		if (ret) {
17628c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to start link clocks. ret=%d\n", ret);
17638c2ecf20Sopenharmony_ci			goto end;
17648c2ecf20Sopenharmony_ci		}
17658c2ecf20Sopenharmony_ci	}
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ci	ret = dp_ctrl_enable_stream_clocks(ctrl);
17688c2ecf20Sopenharmony_ci	if (ret) {
17698c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to start pixel clocks. ret=%d\n", ret);
17708c2ecf20Sopenharmony_ci		goto end;
17718c2ecf20Sopenharmony_ci	}
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
17748c2ecf20Sopenharmony_ci		dp_ctrl_send_phy_test_pattern(ctrl);
17758c2ecf20Sopenharmony_ci		return 0;
17768c2ecf20Sopenharmony_ci	}
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_ci	/*
17798c2ecf20Sopenharmony_ci	 * Set up transfer unit values and set controller state to send
17808c2ecf20Sopenharmony_ci	 * video.
17818c2ecf20Sopenharmony_ci	 */
17828c2ecf20Sopenharmony_ci	dp_ctrl_configure_source_params(ctrl);
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci	dp_catalog_ctrl_config_msa(ctrl->catalog,
17858c2ecf20Sopenharmony_ci		ctrl->link->link_params.rate,
17868c2ecf20Sopenharmony_ci		ctrl->dp_ctrl.pixel_rate, dp_ctrl_use_fixed_nvid(ctrl));
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_ci	reinit_completion(&ctrl->video_comp);
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci	dp_ctrl_setup_tr_unit(ctrl);
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci	dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO);
17938c2ecf20Sopenharmony_ci
17948c2ecf20Sopenharmony_ci	ret = dp_ctrl_wait4video_ready(ctrl);
17958c2ecf20Sopenharmony_ci	if (ret)
17968c2ecf20Sopenharmony_ci		return ret;
17978c2ecf20Sopenharmony_ci
17988c2ecf20Sopenharmony_ci	mainlink_ready = dp_catalog_ctrl_mainlink_ready(ctrl->catalog);
17998c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("mainlink %s\n", mainlink_ready ? "READY" : "NOT READY");
18008c2ecf20Sopenharmony_ci
18018c2ecf20Sopenharmony_ciend:
18028c2ecf20Sopenharmony_ci	return ret;
18038c2ecf20Sopenharmony_ci}
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ciint dp_ctrl_off(struct dp_ctrl *dp_ctrl)
18068c2ecf20Sopenharmony_ci{
18078c2ecf20Sopenharmony_ci	struct dp_ctrl_private *ctrl;
18088c2ecf20Sopenharmony_ci	struct dp_io *dp_io;
18098c2ecf20Sopenharmony_ci	struct phy *phy;
18108c2ecf20Sopenharmony_ci	int ret = 0;
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_ci	if (!dp_ctrl)
18138c2ecf20Sopenharmony_ci		return -EINVAL;
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
18168c2ecf20Sopenharmony_ci	dp_io = &ctrl->parser->io;
18178c2ecf20Sopenharmony_ci	phy = dp_io->phy;
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci	dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_ci	dp_catalog_ctrl_reset(ctrl->catalog);
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_ci	ret = dp_power_clk_enable(ctrl->power, DP_STREAM_PM, false);
18248c2ecf20Sopenharmony_ci	if (ret)
18258c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to disable pixel clocks. ret=%d\n", ret);
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_ci	ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false);
18288c2ecf20Sopenharmony_ci	if (ret) {
18298c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret);
18308c2ecf20Sopenharmony_ci	}
18318c2ecf20Sopenharmony_ci
18328c2ecf20Sopenharmony_ci	phy_power_off(phy);
18338c2ecf20Sopenharmony_ci	phy_exit(phy);
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("DP off done\n");
18368c2ecf20Sopenharmony_ci	return ret;
18378c2ecf20Sopenharmony_ci}
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_civoid dp_ctrl_isr(struct dp_ctrl *dp_ctrl)
18408c2ecf20Sopenharmony_ci{
18418c2ecf20Sopenharmony_ci	struct dp_ctrl_private *ctrl;
18428c2ecf20Sopenharmony_ci	u32 isr;
18438c2ecf20Sopenharmony_ci
18448c2ecf20Sopenharmony_ci	if (!dp_ctrl)
18458c2ecf20Sopenharmony_ci		return;
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_ci	isr = dp_catalog_ctrl_get_interrupt(ctrl->catalog);
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci	if (isr & DP_CTRL_INTR_READY_FOR_VIDEO) {
18528c2ecf20Sopenharmony_ci		DRM_DEBUG_DP("dp_video_ready\n");
18538c2ecf20Sopenharmony_ci		complete(&ctrl->video_comp);
18548c2ecf20Sopenharmony_ci	}
18558c2ecf20Sopenharmony_ci
18568c2ecf20Sopenharmony_ci	if (isr & DP_CTRL_INTR_IDLE_PATTERN_SENT) {
18578c2ecf20Sopenharmony_ci		DRM_DEBUG_DP("idle_patterns_sent\n");
18588c2ecf20Sopenharmony_ci		complete(&ctrl->idle_comp);
18598c2ecf20Sopenharmony_ci	}
18608c2ecf20Sopenharmony_ci}
18618c2ecf20Sopenharmony_ci
18628c2ecf20Sopenharmony_cistruct dp_ctrl *dp_ctrl_get(struct device *dev, struct dp_link *link,
18638c2ecf20Sopenharmony_ci			struct dp_panel *panel,	struct drm_dp_aux *aux,
18648c2ecf20Sopenharmony_ci			struct dp_power *power, struct dp_catalog *catalog,
18658c2ecf20Sopenharmony_ci			struct dp_parser *parser)
18668c2ecf20Sopenharmony_ci{
18678c2ecf20Sopenharmony_ci	struct dp_ctrl_private *ctrl;
18688c2ecf20Sopenharmony_ci
18698c2ecf20Sopenharmony_ci	if (!dev || !panel || !aux ||
18708c2ecf20Sopenharmony_ci	    !link || !catalog) {
18718c2ecf20Sopenharmony_ci		DRM_ERROR("invalid input\n");
18728c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
18738c2ecf20Sopenharmony_ci	}
18748c2ecf20Sopenharmony_ci
18758c2ecf20Sopenharmony_ci	ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
18768c2ecf20Sopenharmony_ci	if (!ctrl) {
18778c2ecf20Sopenharmony_ci		DRM_ERROR("Mem allocation failure\n");
18788c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
18798c2ecf20Sopenharmony_ci	}
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_ci	init_completion(&ctrl->idle_comp);
18828c2ecf20Sopenharmony_ci	init_completion(&ctrl->video_comp);
18838c2ecf20Sopenharmony_ci
18848c2ecf20Sopenharmony_ci	/* in parameters */
18858c2ecf20Sopenharmony_ci	ctrl->parser   = parser;
18868c2ecf20Sopenharmony_ci	ctrl->panel    = panel;
18878c2ecf20Sopenharmony_ci	ctrl->power    = power;
18888c2ecf20Sopenharmony_ci	ctrl->aux      = aux;
18898c2ecf20Sopenharmony_ci	ctrl->link     = link;
18908c2ecf20Sopenharmony_ci	ctrl->catalog  = catalog;
18918c2ecf20Sopenharmony_ci	ctrl->dev      = dev;
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_ci	return &ctrl->dp_ctrl;
18948c2ecf20Sopenharmony_ci}
18958c2ecf20Sopenharmony_ci
18968c2ecf20Sopenharmony_civoid dp_ctrl_put(struct dp_ctrl *dp_ctrl)
18978c2ecf20Sopenharmony_ci{
18988c2ecf20Sopenharmony_ci}
1899