13424e3a4SYakir Yang /*
23424e3a4SYakir Yang  * Analogix DP (Display port) core register interface driver.
33424e3a4SYakir Yang  *
43424e3a4SYakir Yang  * Copyright (C) 2012 Samsung Electronics Co., Ltd.
53424e3a4SYakir Yang  * Author: Jingoo Han <jg1.han@samsung.com>
63424e3a4SYakir Yang  *
73424e3a4SYakir Yang  * This program is free software; you can redistribute it and/or modify it
83424e3a4SYakir Yang  * under the terms of the GNU General Public License as published by the
93424e3a4SYakir Yang  * Free Software Foundation; either version 2 of the License, or (at your
103424e3a4SYakir Yang  * option) any later version.
113424e3a4SYakir Yang  */
123424e3a4SYakir Yang 
133424e3a4SYakir Yang #include <linux/device.h>
143424e3a4SYakir Yang #include <linux/io.h>
153424e3a4SYakir Yang #include <linux/delay.h>
163424e3a4SYakir Yang #include <linux/gpio.h>
173424e3a4SYakir Yang 
183424e3a4SYakir Yang #include "analogix_dp_core.h"
193424e3a4SYakir Yang #include "analogix_dp_reg.h"
203424e3a4SYakir Yang 
213424e3a4SYakir Yang #define COMMON_INT_MASK_1	0
223424e3a4SYakir Yang #define COMMON_INT_MASK_2	0
233424e3a4SYakir Yang #define COMMON_INT_MASK_3	0
243424e3a4SYakir Yang #define COMMON_INT_MASK_4	(HOTPLUG_CHG | HPD_LOST | PLUG)
253424e3a4SYakir Yang #define INT_STA_MASK		INT_HPD
263424e3a4SYakir Yang 
273424e3a4SYakir Yang void analogix_dp_enable_video_mute(struct analogix_dp_device *dp, bool enable)
283424e3a4SYakir Yang {
293424e3a4SYakir Yang 	u32 reg;
303424e3a4SYakir Yang 
313424e3a4SYakir Yang 	if (enable) {
32092f8994SHeiko Stuebner 		reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1);
333424e3a4SYakir Yang 		reg |= HDCP_VIDEO_MUTE;
34092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1);
353424e3a4SYakir Yang 	} else {
36092f8994SHeiko Stuebner 		reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1);
373424e3a4SYakir Yang 		reg &= ~HDCP_VIDEO_MUTE;
38092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1);
393424e3a4SYakir Yang 	}
403424e3a4SYakir Yang }
413424e3a4SYakir Yang 
423424e3a4SYakir Yang void analogix_dp_stop_video(struct analogix_dp_device *dp)
433424e3a4SYakir Yang {
443424e3a4SYakir Yang 	u32 reg;
453424e3a4SYakir Yang 
46092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1);
473424e3a4SYakir Yang 	reg &= ~VIDEO_EN;
48092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1);
493424e3a4SYakir Yang }
503424e3a4SYakir Yang 
513424e3a4SYakir Yang void analogix_dp_lane_swap(struct analogix_dp_device *dp, bool enable)
523424e3a4SYakir Yang {
533424e3a4SYakir Yang 	u32 reg;
543424e3a4SYakir Yang 
553424e3a4SYakir Yang 	if (enable)
563424e3a4SYakir Yang 		reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 |
573424e3a4SYakir Yang 		      LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3;
583424e3a4SYakir Yang 	else
593424e3a4SYakir Yang 		reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 |
603424e3a4SYakir Yang 		      LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0;
613424e3a4SYakir Yang 
62092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_LANE_MAP);
633424e3a4SYakir Yang }
643424e3a4SYakir Yang 
653424e3a4SYakir Yang void analogix_dp_init_analog_param(struct analogix_dp_device *dp)
663424e3a4SYakir Yang {
673424e3a4SYakir Yang 	u32 reg;
683424e3a4SYakir Yang 
693424e3a4SYakir Yang 	reg = TX_TERMINAL_CTRL_50_OHM;
70092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_ANALOG_CTL_1);
713424e3a4SYakir Yang 
723424e3a4SYakir Yang 	reg = SEL_24M | TX_DVDD_BIT_1_0625V;
73092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_ANALOG_CTL_2);
743424e3a4SYakir Yang 
753424e3a4SYakir Yang 	reg = DRIVE_DVDD_BIT_1_0625V | VCO_BIT_600_MICRO;
76092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_ANALOG_CTL_3);
773424e3a4SYakir Yang 
783424e3a4SYakir Yang 	reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM |
793424e3a4SYakir Yang 		TX_CUR1_2X | TX_CUR_16_MA;
80092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_PLL_FILTER_CTL_1);
813424e3a4SYakir Yang 
823424e3a4SYakir Yang 	reg = CH3_AMP_400_MV | CH2_AMP_400_MV |
833424e3a4SYakir Yang 		CH1_AMP_400_MV | CH0_AMP_400_MV;
84092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_TX_AMP_TUNING_CTL);
853424e3a4SYakir Yang }
863424e3a4SYakir Yang 
873424e3a4SYakir Yang void analogix_dp_init_interrupt(struct analogix_dp_device *dp)
883424e3a4SYakir Yang {
893424e3a4SYakir Yang 	/* Set interrupt pin assertion polarity as high */
90092f8994SHeiko Stuebner 	writel(INT_POL1 | INT_POL0, dp->reg_base + ANALOGIX_DP_INT_CTL);
913424e3a4SYakir Yang 
923424e3a4SYakir Yang 	/* Clear pending regisers */
93092f8994SHeiko Stuebner 	writel(0xff, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_1);
94092f8994SHeiko Stuebner 	writel(0x4f, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_2);
95092f8994SHeiko Stuebner 	writel(0xe0, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_3);
96092f8994SHeiko Stuebner 	writel(0xe7, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_4);
97092f8994SHeiko Stuebner 	writel(0x63, dp->reg_base + ANALOGIX_DP_INT_STA);
983424e3a4SYakir Yang 
993424e3a4SYakir Yang 	/* 0:mask,1: unmask */
100092f8994SHeiko Stuebner 	writel(0x00, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_1);
101092f8994SHeiko Stuebner 	writel(0x00, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_2);
102092f8994SHeiko Stuebner 	writel(0x00, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_3);
103092f8994SHeiko Stuebner 	writel(0x00, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4);
104092f8994SHeiko Stuebner 	writel(0x00, dp->reg_base + ANALOGIX_DP_INT_STA_MASK);
1053424e3a4SYakir Yang }
1063424e3a4SYakir Yang 
1073424e3a4SYakir Yang void analogix_dp_reset(struct analogix_dp_device *dp)
1083424e3a4SYakir Yang {
1093424e3a4SYakir Yang 	u32 reg;
1103424e3a4SYakir Yang 
1113424e3a4SYakir Yang 	analogix_dp_stop_video(dp);
1123424e3a4SYakir Yang 	analogix_dp_enable_video_mute(dp, 0);
1133424e3a4SYakir Yang 
1143424e3a4SYakir Yang 	reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N |
1153424e3a4SYakir Yang 		AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N |
1163424e3a4SYakir Yang 		HDCP_FUNC_EN_N | SW_FUNC_EN_N;
117092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_1);
1183424e3a4SYakir Yang 
1193424e3a4SYakir Yang 	reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N |
1203424e3a4SYakir Yang 		SERDES_FIFO_FUNC_EN_N |
1213424e3a4SYakir Yang 		LS_CLK_DOMAIN_FUNC_EN_N;
122092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_2);
1233424e3a4SYakir Yang 
1243424e3a4SYakir Yang 	usleep_range(20, 30);
1253424e3a4SYakir Yang 
1263424e3a4SYakir Yang 	analogix_dp_lane_swap(dp, 0);
1273424e3a4SYakir Yang 
128092f8994SHeiko Stuebner 	writel(0x0, dp->reg_base + ANALOGIX_DP_SYS_CTL_1);
129092f8994SHeiko Stuebner 	writel(0x40, dp->reg_base + ANALOGIX_DP_SYS_CTL_2);
130092f8994SHeiko Stuebner 	writel(0x0, dp->reg_base + ANALOGIX_DP_SYS_CTL_3);
131092f8994SHeiko Stuebner 	writel(0x0, dp->reg_base + ANALOGIX_DP_SYS_CTL_4);
1323424e3a4SYakir Yang 
133092f8994SHeiko Stuebner 	writel(0x0, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
134092f8994SHeiko Stuebner 	writel(0x0, dp->reg_base + ANALOGIX_DP_HDCP_CTL);
1353424e3a4SYakir Yang 
136092f8994SHeiko Stuebner 	writel(0x5e, dp->reg_base + ANALOGIX_DP_HPD_DEGLITCH_L);
137092f8994SHeiko Stuebner 	writel(0x1a, dp->reg_base + ANALOGIX_DP_HPD_DEGLITCH_H);
1383424e3a4SYakir Yang 
139092f8994SHeiko Stuebner 	writel(0x10, dp->reg_base + ANALOGIX_DP_LINK_DEBUG_CTL);
1403424e3a4SYakir Yang 
141092f8994SHeiko Stuebner 	writel(0x0, dp->reg_base + ANALOGIX_DP_PHY_TEST);
1423424e3a4SYakir Yang 
143092f8994SHeiko Stuebner 	writel(0x0, dp->reg_base + ANALOGIX_DP_VIDEO_FIFO_THRD);
144092f8994SHeiko Stuebner 	writel(0x20, dp->reg_base + ANALOGIX_DP_AUDIO_MARGIN);
1453424e3a4SYakir Yang 
146092f8994SHeiko Stuebner 	writel(0x4, dp->reg_base + ANALOGIX_DP_M_VID_GEN_FILTER_TH);
147092f8994SHeiko Stuebner 	writel(0x2, dp->reg_base + ANALOGIX_DP_M_AUD_GEN_FILTER_TH);
1483424e3a4SYakir Yang 
149092f8994SHeiko Stuebner 	writel(0x00000101, dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL);
1503424e3a4SYakir Yang }
1513424e3a4SYakir Yang 
1523424e3a4SYakir Yang void analogix_dp_swreset(struct analogix_dp_device *dp)
1533424e3a4SYakir Yang {
154092f8994SHeiko Stuebner 	writel(RESET_DP_TX, dp->reg_base + ANALOGIX_DP_TX_SW_RESET);
1553424e3a4SYakir Yang }
1563424e3a4SYakir Yang 
1573424e3a4SYakir Yang void analogix_dp_config_interrupt(struct analogix_dp_device *dp)
1583424e3a4SYakir Yang {
1593424e3a4SYakir Yang 	u32 reg;
1603424e3a4SYakir Yang 
1613424e3a4SYakir Yang 	/* 0: mask, 1: unmask */
1623424e3a4SYakir Yang 	reg = COMMON_INT_MASK_1;
163092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_1);
1643424e3a4SYakir Yang 
1653424e3a4SYakir Yang 	reg = COMMON_INT_MASK_2;
166092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_2);
1673424e3a4SYakir Yang 
1683424e3a4SYakir Yang 	reg = COMMON_INT_MASK_3;
169092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_3);
1703424e3a4SYakir Yang 
1713424e3a4SYakir Yang 	reg = COMMON_INT_MASK_4;
172092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4);
1733424e3a4SYakir Yang 
1743424e3a4SYakir Yang 	reg = INT_STA_MASK;
175092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA_MASK);
1763424e3a4SYakir Yang }
1773424e3a4SYakir Yang 
1783424e3a4SYakir Yang enum pll_status analogix_dp_get_pll_lock_status(struct analogix_dp_device *dp)
1793424e3a4SYakir Yang {
1803424e3a4SYakir Yang 	u32 reg;
1813424e3a4SYakir Yang 
182092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_DEBUG_CTL);
1833424e3a4SYakir Yang 	if (reg & PLL_LOCK)
1843424e3a4SYakir Yang 		return PLL_LOCKED;
1853424e3a4SYakir Yang 	else
1863424e3a4SYakir Yang 		return PLL_UNLOCKED;
1873424e3a4SYakir Yang }
1883424e3a4SYakir Yang 
1893424e3a4SYakir Yang void analogix_dp_set_pll_power_down(struct analogix_dp_device *dp, bool enable)
1903424e3a4SYakir Yang {
1913424e3a4SYakir Yang 	u32 reg;
1923424e3a4SYakir Yang 
1933424e3a4SYakir Yang 	if (enable) {
194092f8994SHeiko Stuebner 		reg = readl(dp->reg_base + ANALOGIX_DP_PLL_CTL);
1953424e3a4SYakir Yang 		reg |= DP_PLL_PD;
196092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_PLL_CTL);
1973424e3a4SYakir Yang 	} else {
198092f8994SHeiko Stuebner 		reg = readl(dp->reg_base + ANALOGIX_DP_PLL_CTL);
1993424e3a4SYakir Yang 		reg &= ~DP_PLL_PD;
200092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_PLL_CTL);
2013424e3a4SYakir Yang 	}
2023424e3a4SYakir Yang }
2033424e3a4SYakir Yang 
2043424e3a4SYakir Yang void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp,
2053424e3a4SYakir Yang 				       enum analog_power_block block,
2063424e3a4SYakir Yang 				       bool enable)
2073424e3a4SYakir Yang {
2083424e3a4SYakir Yang 	u32 reg;
2093424e3a4SYakir Yang 
2103424e3a4SYakir Yang 	switch (block) {
2113424e3a4SYakir Yang 	case AUX_BLOCK:
2123424e3a4SYakir Yang 		if (enable) {
213092f8994SHeiko Stuebner 			reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD);
2143424e3a4SYakir Yang 			reg |= AUX_PD;
215092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD);
2163424e3a4SYakir Yang 		} else {
217092f8994SHeiko Stuebner 			reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD);
2183424e3a4SYakir Yang 			reg &= ~AUX_PD;
219092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD);
2203424e3a4SYakir Yang 		}
2213424e3a4SYakir Yang 		break;
2223424e3a4SYakir Yang 	case CH0_BLOCK:
2233424e3a4SYakir Yang 		if (enable) {
224092f8994SHeiko Stuebner 			reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD);
2253424e3a4SYakir Yang 			reg |= CH0_PD;
226092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD);
2273424e3a4SYakir Yang 		} else {
228092f8994SHeiko Stuebner 			reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD);
2293424e3a4SYakir Yang 			reg &= ~CH0_PD;
230092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD);
2313424e3a4SYakir Yang 		}
2323424e3a4SYakir Yang 		break;
2333424e3a4SYakir Yang 	case CH1_BLOCK:
2343424e3a4SYakir Yang 		if (enable) {
235092f8994SHeiko Stuebner 			reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD);
2363424e3a4SYakir Yang 			reg |= CH1_PD;
237092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD);
2383424e3a4SYakir Yang 		} else {
239092f8994SHeiko Stuebner 			reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD);
2403424e3a4SYakir Yang 			reg &= ~CH1_PD;
241092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD);
2423424e3a4SYakir Yang 		}
2433424e3a4SYakir Yang 		break;
2443424e3a4SYakir Yang 	case CH2_BLOCK:
2453424e3a4SYakir Yang 		if (enable) {
246092f8994SHeiko Stuebner 			reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD);
2473424e3a4SYakir Yang 			reg |= CH2_PD;
248092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD);
2493424e3a4SYakir Yang 		} else {
250092f8994SHeiko Stuebner 			reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD);
2513424e3a4SYakir Yang 			reg &= ~CH2_PD;
252092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD);
2533424e3a4SYakir Yang 		}
2543424e3a4SYakir Yang 		break;
2553424e3a4SYakir Yang 	case CH3_BLOCK:
2563424e3a4SYakir Yang 		if (enable) {
257092f8994SHeiko Stuebner 			reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD);
2583424e3a4SYakir Yang 			reg |= CH3_PD;
259092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD);
2603424e3a4SYakir Yang 		} else {
261092f8994SHeiko Stuebner 			reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD);
2623424e3a4SYakir Yang 			reg &= ~CH3_PD;
263092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD);
2643424e3a4SYakir Yang 		}
2653424e3a4SYakir Yang 		break;
2663424e3a4SYakir Yang 	case ANALOG_TOTAL:
2673424e3a4SYakir Yang 		if (enable) {
268092f8994SHeiko Stuebner 			reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD);
2693424e3a4SYakir Yang 			reg |= DP_PHY_PD;
270092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD);
2713424e3a4SYakir Yang 		} else {
272092f8994SHeiko Stuebner 			reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD);
2733424e3a4SYakir Yang 			reg &= ~DP_PHY_PD;
274092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD);
2753424e3a4SYakir Yang 		}
2763424e3a4SYakir Yang 		break;
2773424e3a4SYakir Yang 	case POWER_ALL:
2783424e3a4SYakir Yang 		if (enable) {
2793424e3a4SYakir Yang 			reg = DP_PHY_PD | AUX_PD | CH3_PD | CH2_PD |
2803424e3a4SYakir Yang 				CH1_PD | CH0_PD;
281092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD);
2823424e3a4SYakir Yang 		} else {
283092f8994SHeiko Stuebner 			writel(0x00, dp->reg_base + ANALOGIX_DP_PHY_PD);
2843424e3a4SYakir Yang 		}
2853424e3a4SYakir Yang 		break;
2863424e3a4SYakir Yang 	default:
2873424e3a4SYakir Yang 		break;
2883424e3a4SYakir Yang 	}
2893424e3a4SYakir Yang }
2903424e3a4SYakir Yang 
2913424e3a4SYakir Yang void analogix_dp_init_analog_func(struct analogix_dp_device *dp)
2923424e3a4SYakir Yang {
2933424e3a4SYakir Yang 	u32 reg;
2943424e3a4SYakir Yang 	int timeout_loop = 0;
2953424e3a4SYakir Yang 
2963424e3a4SYakir Yang 	analogix_dp_set_analog_power_down(dp, POWER_ALL, 0);
2973424e3a4SYakir Yang 
2983424e3a4SYakir Yang 	reg = PLL_LOCK_CHG;
299092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_1);
3003424e3a4SYakir Yang 
301092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_DEBUG_CTL);
3023424e3a4SYakir Yang 	reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL);
303092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_DEBUG_CTL);
3043424e3a4SYakir Yang 
3053424e3a4SYakir Yang 	/* Power up PLL */
3063424e3a4SYakir Yang 	if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
3073424e3a4SYakir Yang 		analogix_dp_set_pll_power_down(dp, 0);
3083424e3a4SYakir Yang 
3093424e3a4SYakir Yang 		while (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
3103424e3a4SYakir Yang 			timeout_loop++;
3113424e3a4SYakir Yang 			if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
3123424e3a4SYakir Yang 				dev_err(dp->dev, "failed to get pll lock status\n");
3133424e3a4SYakir Yang 				return;
3143424e3a4SYakir Yang 			}
3153424e3a4SYakir Yang 			usleep_range(10, 20);
3163424e3a4SYakir Yang 		}
3173424e3a4SYakir Yang 	}
3183424e3a4SYakir Yang 
3193424e3a4SYakir Yang 	/* Enable Serdes FIFO function and Link symbol clock domain module */
320092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_2);
3213424e3a4SYakir Yang 	reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N
3223424e3a4SYakir Yang 		| AUX_FUNC_EN_N);
323092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_2);
3243424e3a4SYakir Yang }
3253424e3a4SYakir Yang 
3263424e3a4SYakir Yang void analogix_dp_clear_hotplug_interrupts(struct analogix_dp_device *dp)
3273424e3a4SYakir Yang {
3283424e3a4SYakir Yang 	u32 reg;
3293424e3a4SYakir Yang 
3303424e3a4SYakir Yang 	if (gpio_is_valid(dp->hpd_gpio))
3313424e3a4SYakir Yang 		return;
3323424e3a4SYakir Yang 
3333424e3a4SYakir Yang 	reg = HOTPLUG_CHG | HPD_LOST | PLUG;
334092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_4);
3353424e3a4SYakir Yang 
3363424e3a4SYakir Yang 	reg = INT_HPD;
337092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA);
3383424e3a4SYakir Yang }
3393424e3a4SYakir Yang 
3403424e3a4SYakir Yang void analogix_dp_init_hpd(struct analogix_dp_device *dp)
3413424e3a4SYakir Yang {
3423424e3a4SYakir Yang 	u32 reg;
3433424e3a4SYakir Yang 
3443424e3a4SYakir Yang 	if (gpio_is_valid(dp->hpd_gpio))
3453424e3a4SYakir Yang 		return;
3463424e3a4SYakir Yang 
3473424e3a4SYakir Yang 	analogix_dp_clear_hotplug_interrupts(dp);
3483424e3a4SYakir Yang 
349092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_3);
3503424e3a4SYakir Yang 	reg &= ~(F_HPD | HPD_CTRL);
351092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_3);
3523424e3a4SYakir Yang }
3533424e3a4SYakir Yang 
3543424e3a4SYakir Yang enum dp_irq_type analogix_dp_get_irq_type(struct analogix_dp_device *dp)
3553424e3a4SYakir Yang {
3563424e3a4SYakir Yang 	u32 reg;
3573424e3a4SYakir Yang 
3583424e3a4SYakir Yang 	if (gpio_is_valid(dp->hpd_gpio)) {
3593424e3a4SYakir Yang 		reg = gpio_get_value(dp->hpd_gpio);
3603424e3a4SYakir Yang 		if (reg)
3613424e3a4SYakir Yang 			return DP_IRQ_TYPE_HP_CABLE_IN;
3623424e3a4SYakir Yang 		else
3633424e3a4SYakir Yang 			return DP_IRQ_TYPE_HP_CABLE_OUT;
3643424e3a4SYakir Yang 	} else {
3653424e3a4SYakir Yang 		/* Parse hotplug interrupt status register */
366092f8994SHeiko Stuebner 		reg = readl(dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_4);
3673424e3a4SYakir Yang 
3683424e3a4SYakir Yang 		if (reg & PLUG)
3693424e3a4SYakir Yang 			return DP_IRQ_TYPE_HP_CABLE_IN;
3703424e3a4SYakir Yang 
3713424e3a4SYakir Yang 		if (reg & HPD_LOST)
3723424e3a4SYakir Yang 			return DP_IRQ_TYPE_HP_CABLE_OUT;
3733424e3a4SYakir Yang 
3743424e3a4SYakir Yang 		if (reg & HOTPLUG_CHG)
3753424e3a4SYakir Yang 			return DP_IRQ_TYPE_HP_CHANGE;
3763424e3a4SYakir Yang 
3773424e3a4SYakir Yang 		return DP_IRQ_TYPE_UNKNOWN;
3783424e3a4SYakir Yang 	}
3793424e3a4SYakir Yang }
3803424e3a4SYakir Yang 
3813424e3a4SYakir Yang void analogix_dp_reset_aux(struct analogix_dp_device *dp)
3823424e3a4SYakir Yang {
3833424e3a4SYakir Yang 	u32 reg;
3843424e3a4SYakir Yang 
3853424e3a4SYakir Yang 	/* Disable AUX channel module */
386092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_2);
3873424e3a4SYakir Yang 	reg |= AUX_FUNC_EN_N;
388092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_2);
3893424e3a4SYakir Yang }
3903424e3a4SYakir Yang 
3913424e3a4SYakir Yang void analogix_dp_init_aux(struct analogix_dp_device *dp)
3923424e3a4SYakir Yang {
3933424e3a4SYakir Yang 	u32 reg;
3943424e3a4SYakir Yang 
3953424e3a4SYakir Yang 	/* Clear inerrupts related to AUX channel */
3963424e3a4SYakir Yang 	reg = RPLY_RECEIV | AUX_ERR;
397092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA);
3983424e3a4SYakir Yang 
3993424e3a4SYakir Yang 	analogix_dp_reset_aux(dp);
4003424e3a4SYakir Yang 
4013424e3a4SYakir Yang 	/* Disable AUX transaction H/W retry */
4023424e3a4SYakir Yang 	reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(0) |
4033424e3a4SYakir Yang 	      AUX_HW_RETRY_INTERVAL_600_MICROSECONDS;
404092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_AUX_HW_RETRY_CTL);
4053424e3a4SYakir Yang 
4063424e3a4SYakir Yang 	/* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */
4073424e3a4SYakir Yang 	reg = DEFER_CTRL_EN | DEFER_COUNT(1);
408092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_DEFER_CTL);
4093424e3a4SYakir Yang 
4103424e3a4SYakir Yang 	/* Enable AUX channel module */
411092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_2);
4123424e3a4SYakir Yang 	reg &= ~AUX_FUNC_EN_N;
413092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_2);
4143424e3a4SYakir Yang }
4153424e3a4SYakir Yang 
4163424e3a4SYakir Yang int analogix_dp_get_plug_in_status(struct analogix_dp_device *dp)
4173424e3a4SYakir Yang {
4183424e3a4SYakir Yang 	u32 reg;
4193424e3a4SYakir Yang 
4203424e3a4SYakir Yang 	if (gpio_is_valid(dp->hpd_gpio)) {
4213424e3a4SYakir Yang 		if (gpio_get_value(dp->hpd_gpio))
4223424e3a4SYakir Yang 			return 0;
4233424e3a4SYakir Yang 	} else {
424092f8994SHeiko Stuebner 		reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_3);
4253424e3a4SYakir Yang 		if (reg & HPD_STATUS)
4263424e3a4SYakir Yang 			return 0;
4273424e3a4SYakir Yang 	}
4283424e3a4SYakir Yang 
4293424e3a4SYakir Yang 	return -EINVAL;
4303424e3a4SYakir Yang }
4313424e3a4SYakir Yang 
4323424e3a4SYakir Yang void analogix_dp_enable_sw_function(struct analogix_dp_device *dp)
4333424e3a4SYakir Yang {
4343424e3a4SYakir Yang 	u32 reg;
4353424e3a4SYakir Yang 
436092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_1);
4373424e3a4SYakir Yang 	reg &= ~SW_FUNC_EN_N;
438092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_1);
4393424e3a4SYakir Yang }
4403424e3a4SYakir Yang 
4413424e3a4SYakir Yang int analogix_dp_start_aux_transaction(struct analogix_dp_device *dp)
4423424e3a4SYakir Yang {
4433424e3a4SYakir Yang 	int reg;
4443424e3a4SYakir Yang 	int retval = 0;
4453424e3a4SYakir Yang 	int timeout_loop = 0;
4463424e3a4SYakir Yang 
4473424e3a4SYakir Yang 	/* Enable AUX CH operation */
448092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2);
4493424e3a4SYakir Yang 	reg |= AUX_EN;
450092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2);
4513424e3a4SYakir Yang 
4523424e3a4SYakir Yang 	/* Is AUX CH command reply received? */
453092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);
4543424e3a4SYakir Yang 	while (!(reg & RPLY_RECEIV)) {
4553424e3a4SYakir Yang 		timeout_loop++;
4563424e3a4SYakir Yang 		if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
4573424e3a4SYakir Yang 			dev_err(dp->dev, "AUX CH command reply failed!\n");
4583424e3a4SYakir Yang 			return -ETIMEDOUT;
4593424e3a4SYakir Yang 		}
460092f8994SHeiko Stuebner 		reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);
4613424e3a4SYakir Yang 		usleep_range(10, 11);
4623424e3a4SYakir Yang 	}
4633424e3a4SYakir Yang 
4643424e3a4SYakir Yang 	/* Clear interrupt source for AUX CH command reply */
465092f8994SHeiko Stuebner 	writel(RPLY_RECEIV, dp->reg_base + ANALOGIX_DP_INT_STA);
4663424e3a4SYakir Yang 
4673424e3a4SYakir Yang 	/* Clear interrupt source for AUX CH access error */
468092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);
4693424e3a4SYakir Yang 	if (reg & AUX_ERR) {
470092f8994SHeiko Stuebner 		writel(AUX_ERR, dp->reg_base + ANALOGIX_DP_INT_STA);
4713424e3a4SYakir Yang 		return -EREMOTEIO;
4723424e3a4SYakir Yang 	}
4733424e3a4SYakir Yang 
4743424e3a4SYakir Yang 	/* Check AUX CH error access status */
475092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_STA);
4763424e3a4SYakir Yang 	if ((reg & AUX_STATUS_MASK) != 0) {
4773424e3a4SYakir Yang 		dev_err(dp->dev, "AUX CH error happens: %d\n\n",
4783424e3a4SYakir Yang 			reg & AUX_STATUS_MASK);
4793424e3a4SYakir Yang 		return -EREMOTEIO;
4803424e3a4SYakir Yang 	}
4813424e3a4SYakir Yang 
4823424e3a4SYakir Yang 	return retval;
4833424e3a4SYakir Yang }
4843424e3a4SYakir Yang 
4853424e3a4SYakir Yang int analogix_dp_write_byte_to_dpcd(struct analogix_dp_device *dp,
4863424e3a4SYakir Yang 				   unsigned int reg_addr,
4873424e3a4SYakir Yang 				   unsigned char data)
4883424e3a4SYakir Yang {
4893424e3a4SYakir Yang 	u32 reg;
4903424e3a4SYakir Yang 	int i;
4913424e3a4SYakir Yang 	int retval;
4923424e3a4SYakir Yang 
4933424e3a4SYakir Yang 	for (i = 0; i < 3; i++) {
4943424e3a4SYakir Yang 		/* Clear AUX CH data buffer */
4953424e3a4SYakir Yang 		reg = BUF_CLR;
496092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL);
4973424e3a4SYakir Yang 
4983424e3a4SYakir Yang 		/* Select DPCD device address */
4993424e3a4SYakir Yang 		reg = AUX_ADDR_7_0(reg_addr);
500092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0);
5013424e3a4SYakir Yang 		reg = AUX_ADDR_15_8(reg_addr);
502092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8);
5033424e3a4SYakir Yang 		reg = AUX_ADDR_19_16(reg_addr);
504092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16);
5053424e3a4SYakir Yang 
5063424e3a4SYakir Yang 		/* Write data buffer */
5073424e3a4SYakir Yang 		reg = (unsigned int)data;
508092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_BUF_DATA_0);
5093424e3a4SYakir Yang 
5103424e3a4SYakir Yang 		/*
5113424e3a4SYakir Yang 		 * Set DisplayPort transaction and write 1 byte
5123424e3a4SYakir Yang 		 * If bit 3 is 1, DisplayPort transaction.
5133424e3a4SYakir Yang 		 * If Bit 3 is 0, I2C transaction.
5143424e3a4SYakir Yang 		 */
5153424e3a4SYakir Yang 		reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
516092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1);
5173424e3a4SYakir Yang 
5183424e3a4SYakir Yang 		/* Start AUX transaction */
5193424e3a4SYakir Yang 		retval = analogix_dp_start_aux_transaction(dp);
5203424e3a4SYakir Yang 		if (retval == 0)
5213424e3a4SYakir Yang 			break;
522bcbb7033SYakir Yang 
523bcbb7033SYakir Yang 		dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__);
5243424e3a4SYakir Yang 	}
5253424e3a4SYakir Yang 
5263424e3a4SYakir Yang 	return retval;
5273424e3a4SYakir Yang }
5283424e3a4SYakir Yang 
5293424e3a4SYakir Yang int analogix_dp_read_byte_from_dpcd(struct analogix_dp_device *dp,
5303424e3a4SYakir Yang 				    unsigned int reg_addr,
5313424e3a4SYakir Yang 				    unsigned char *data)
5323424e3a4SYakir Yang {
5333424e3a4SYakir Yang 	u32 reg;
5343424e3a4SYakir Yang 	int i;
5353424e3a4SYakir Yang 	int retval;
5363424e3a4SYakir Yang 
5373424e3a4SYakir Yang 	for (i = 0; i < 3; i++) {
5383424e3a4SYakir Yang 		/* Clear AUX CH data buffer */
5393424e3a4SYakir Yang 		reg = BUF_CLR;
540092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL);
5413424e3a4SYakir Yang 
5423424e3a4SYakir Yang 		/* Select DPCD device address */
5433424e3a4SYakir Yang 		reg = AUX_ADDR_7_0(reg_addr);
544092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0);
5453424e3a4SYakir Yang 		reg = AUX_ADDR_15_8(reg_addr);
546092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8);
5473424e3a4SYakir Yang 		reg = AUX_ADDR_19_16(reg_addr);
548092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16);
5493424e3a4SYakir Yang 
5503424e3a4SYakir Yang 		/*
5513424e3a4SYakir Yang 		 * Set DisplayPort transaction and read 1 byte
5523424e3a4SYakir Yang 		 * If bit 3 is 1, DisplayPort transaction.
5533424e3a4SYakir Yang 		 * If Bit 3 is 0, I2C transaction.
5543424e3a4SYakir Yang 		 */
5553424e3a4SYakir Yang 		reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
556092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1);
5573424e3a4SYakir Yang 
5583424e3a4SYakir Yang 		/* Start AUX transaction */
5593424e3a4SYakir Yang 		retval = analogix_dp_start_aux_transaction(dp);
5603424e3a4SYakir Yang 		if (retval == 0)
5613424e3a4SYakir Yang 			break;
562bcbb7033SYakir Yang 
563bcbb7033SYakir Yang 		dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__);
5643424e3a4SYakir Yang 	}
5653424e3a4SYakir Yang 
5663424e3a4SYakir Yang 	/* Read data buffer */
567092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0);
5683424e3a4SYakir Yang 	*data = (unsigned char)(reg & 0xff);
5693424e3a4SYakir Yang 
5703424e3a4SYakir Yang 	return retval;
5713424e3a4SYakir Yang }
5723424e3a4SYakir Yang 
5733424e3a4SYakir Yang int analogix_dp_write_bytes_to_dpcd(struct analogix_dp_device *dp,
5743424e3a4SYakir Yang 				    unsigned int reg_addr,
5753424e3a4SYakir Yang 				    unsigned int count,
5763424e3a4SYakir Yang 				    unsigned char data[])
5773424e3a4SYakir Yang {
5783424e3a4SYakir Yang 	u32 reg;
5793424e3a4SYakir Yang 	unsigned int start_offset;
5803424e3a4SYakir Yang 	unsigned int cur_data_count;
5813424e3a4SYakir Yang 	unsigned int cur_data_idx;
5823424e3a4SYakir Yang 	int i;
5833424e3a4SYakir Yang 	int retval = 0;
5843424e3a4SYakir Yang 
5853424e3a4SYakir Yang 	/* Clear AUX CH data buffer */
5863424e3a4SYakir Yang 	reg = BUF_CLR;
587092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL);
5883424e3a4SYakir Yang 
5893424e3a4SYakir Yang 	start_offset = 0;
5903424e3a4SYakir Yang 	while (start_offset < count) {
5913424e3a4SYakir Yang 		/* Buffer size of AUX CH is 16 * 4bytes */
5923424e3a4SYakir Yang 		if ((count - start_offset) > 16)
5933424e3a4SYakir Yang 			cur_data_count = 16;
5943424e3a4SYakir Yang 		else
5953424e3a4SYakir Yang 			cur_data_count = count - start_offset;
5963424e3a4SYakir Yang 
5973424e3a4SYakir Yang 		for (i = 0; i < 3; i++) {
5983424e3a4SYakir Yang 			/* Select DPCD device address */
5993424e3a4SYakir Yang 			reg = AUX_ADDR_7_0(reg_addr + start_offset);
600092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0);
6013424e3a4SYakir Yang 			reg = AUX_ADDR_15_8(reg_addr + start_offset);
602092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8);
6033424e3a4SYakir Yang 			reg = AUX_ADDR_19_16(reg_addr + start_offset);
604092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16);
6053424e3a4SYakir Yang 
6063424e3a4SYakir Yang 			for (cur_data_idx = 0; cur_data_idx < cur_data_count;
6073424e3a4SYakir Yang 			     cur_data_idx++) {
6083424e3a4SYakir Yang 				reg = data[start_offset + cur_data_idx];
609bcbb7033SYakir Yang 				writel(reg, dp->reg_base +
610bcbb7033SYakir Yang 				       ANALOGIX_DP_BUF_DATA_0 +
611bcbb7033SYakir Yang 				       4 * cur_data_idx);
6123424e3a4SYakir Yang 			}
6133424e3a4SYakir Yang 
6143424e3a4SYakir Yang 			/*
6153424e3a4SYakir Yang 			 * Set DisplayPort transaction and write
6163424e3a4SYakir Yang 			 * If bit 3 is 1, DisplayPort transaction.
6173424e3a4SYakir Yang 			 * If Bit 3 is 0, I2C transaction.
6183424e3a4SYakir Yang 			 */
6193424e3a4SYakir Yang 			reg = AUX_LENGTH(cur_data_count) |
6203424e3a4SYakir Yang 				AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
621092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1);
6223424e3a4SYakir Yang 
6233424e3a4SYakir Yang 			/* Start AUX transaction */
6243424e3a4SYakir Yang 			retval = analogix_dp_start_aux_transaction(dp);
6253424e3a4SYakir Yang 			if (retval == 0)
6263424e3a4SYakir Yang 				break;
627bcbb7033SYakir Yang 
6283424e3a4SYakir Yang 			dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
6293424e3a4SYakir Yang 				__func__);
6303424e3a4SYakir Yang 		}
6313424e3a4SYakir Yang 
6323424e3a4SYakir Yang 		start_offset += cur_data_count;
6333424e3a4SYakir Yang 	}
6343424e3a4SYakir Yang 
6353424e3a4SYakir Yang 	return retval;
6363424e3a4SYakir Yang }
6373424e3a4SYakir Yang 
6383424e3a4SYakir Yang int analogix_dp_read_bytes_from_dpcd(struct analogix_dp_device *dp,
6393424e3a4SYakir Yang 				     unsigned int reg_addr,
6403424e3a4SYakir Yang 				     unsigned int count,
6413424e3a4SYakir Yang 				     unsigned char data[])
6423424e3a4SYakir Yang {
6433424e3a4SYakir Yang 	u32 reg;
6443424e3a4SYakir Yang 	unsigned int start_offset;
6453424e3a4SYakir Yang 	unsigned int cur_data_count;
6463424e3a4SYakir Yang 	unsigned int cur_data_idx;
6473424e3a4SYakir Yang 	int i;
6483424e3a4SYakir Yang 	int retval = 0;
6493424e3a4SYakir Yang 
6503424e3a4SYakir Yang 	/* Clear AUX CH data buffer */
6513424e3a4SYakir Yang 	reg = BUF_CLR;
652092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL);
6533424e3a4SYakir Yang 
6543424e3a4SYakir Yang 	start_offset = 0;
6553424e3a4SYakir Yang 	while (start_offset < count) {
6563424e3a4SYakir Yang 		/* Buffer size of AUX CH is 16 * 4bytes */
6573424e3a4SYakir Yang 		if ((count - start_offset) > 16)
6583424e3a4SYakir Yang 			cur_data_count = 16;
6593424e3a4SYakir Yang 		else
6603424e3a4SYakir Yang 			cur_data_count = count - start_offset;
6613424e3a4SYakir Yang 
6623424e3a4SYakir Yang 		/* AUX CH Request Transaction process */
6633424e3a4SYakir Yang 		for (i = 0; i < 3; i++) {
6643424e3a4SYakir Yang 			/* Select DPCD device address */
6653424e3a4SYakir Yang 			reg = AUX_ADDR_7_0(reg_addr + start_offset);
666092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0);
6673424e3a4SYakir Yang 			reg = AUX_ADDR_15_8(reg_addr + start_offset);
668092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8);
6693424e3a4SYakir Yang 			reg = AUX_ADDR_19_16(reg_addr + start_offset);
670092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16);
6713424e3a4SYakir Yang 
6723424e3a4SYakir Yang 			/*
6733424e3a4SYakir Yang 			 * Set DisplayPort transaction and read
6743424e3a4SYakir Yang 			 * If bit 3 is 1, DisplayPort transaction.
6753424e3a4SYakir Yang 			 * If Bit 3 is 0, I2C transaction.
6763424e3a4SYakir Yang 			 */
6773424e3a4SYakir Yang 			reg = AUX_LENGTH(cur_data_count) |
6783424e3a4SYakir Yang 				AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
679092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1);
6803424e3a4SYakir Yang 
6813424e3a4SYakir Yang 			/* Start AUX transaction */
6823424e3a4SYakir Yang 			retval = analogix_dp_start_aux_transaction(dp);
6833424e3a4SYakir Yang 			if (retval == 0)
6843424e3a4SYakir Yang 				break;
685bcbb7033SYakir Yang 
6863424e3a4SYakir Yang 			dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
6873424e3a4SYakir Yang 				__func__);
6883424e3a4SYakir Yang 		}
6893424e3a4SYakir Yang 
6903424e3a4SYakir Yang 		for (cur_data_idx = 0; cur_data_idx < cur_data_count;
6913424e3a4SYakir Yang 		    cur_data_idx++) {
692092f8994SHeiko Stuebner 			reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0
6933424e3a4SYakir Yang 						 + 4 * cur_data_idx);
6943424e3a4SYakir Yang 			data[start_offset + cur_data_idx] =
6953424e3a4SYakir Yang 				(unsigned char)reg;
6963424e3a4SYakir Yang 		}
6973424e3a4SYakir Yang 
6983424e3a4SYakir Yang 		start_offset += cur_data_count;
6993424e3a4SYakir Yang 	}
7003424e3a4SYakir Yang 
7013424e3a4SYakir Yang 	return retval;
7023424e3a4SYakir Yang }
7033424e3a4SYakir Yang 
7043424e3a4SYakir Yang int analogix_dp_select_i2c_device(struct analogix_dp_device *dp,
7053424e3a4SYakir Yang 				  unsigned int device_addr,
7063424e3a4SYakir Yang 				  unsigned int reg_addr)
7073424e3a4SYakir Yang {
7083424e3a4SYakir Yang 	u32 reg;
7093424e3a4SYakir Yang 	int retval;
7103424e3a4SYakir Yang 
7113424e3a4SYakir Yang 	/* Set EDID device address */
7123424e3a4SYakir Yang 	reg = device_addr;
713092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0);
714092f8994SHeiko Stuebner 	writel(0x0, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8);
715092f8994SHeiko Stuebner 	writel(0x0, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16);
7163424e3a4SYakir Yang 
7173424e3a4SYakir Yang 	/* Set offset from base address of EDID device */
718092f8994SHeiko Stuebner 	writel(reg_addr, dp->reg_base + ANALOGIX_DP_BUF_DATA_0);
7193424e3a4SYakir Yang 
7203424e3a4SYakir Yang 	/*
7213424e3a4SYakir Yang 	 * Set I2C transaction and write address
7223424e3a4SYakir Yang 	 * If bit 3 is 1, DisplayPort transaction.
7233424e3a4SYakir Yang 	 * If Bit 3 is 0, I2C transaction.
7243424e3a4SYakir Yang 	 */
7253424e3a4SYakir Yang 	reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT |
7263424e3a4SYakir Yang 		AUX_TX_COMM_WRITE;
727092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1);
7283424e3a4SYakir Yang 
7293424e3a4SYakir Yang 	/* Start AUX transaction */
7303424e3a4SYakir Yang 	retval = analogix_dp_start_aux_transaction(dp);
7313424e3a4SYakir Yang 	if (retval != 0)
7323424e3a4SYakir Yang 		dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__);
7333424e3a4SYakir Yang 
7343424e3a4SYakir Yang 	return retval;
7353424e3a4SYakir Yang }
7363424e3a4SYakir Yang 
7373424e3a4SYakir Yang int analogix_dp_read_byte_from_i2c(struct analogix_dp_device *dp,
7383424e3a4SYakir Yang 				   unsigned int device_addr,
7393424e3a4SYakir Yang 				   unsigned int reg_addr,
7403424e3a4SYakir Yang 				   unsigned int *data)
7413424e3a4SYakir Yang {
7423424e3a4SYakir Yang 	u32 reg;
7433424e3a4SYakir Yang 	int i;
7443424e3a4SYakir Yang 	int retval;
7453424e3a4SYakir Yang 
7463424e3a4SYakir Yang 	for (i = 0; i < 3; i++) {
7473424e3a4SYakir Yang 		/* Clear AUX CH data buffer */
7483424e3a4SYakir Yang 		reg = BUF_CLR;
749092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL);
7503424e3a4SYakir Yang 
7513424e3a4SYakir Yang 		/* Select EDID device */
752bcbb7033SYakir Yang 		retval = analogix_dp_select_i2c_device(dp, device_addr,
753bcbb7033SYakir Yang 						       reg_addr);
7543424e3a4SYakir Yang 		if (retval != 0)
7553424e3a4SYakir Yang 			continue;
7563424e3a4SYakir Yang 
7573424e3a4SYakir Yang 		/*
7583424e3a4SYakir Yang 		 * Set I2C transaction and read data
7593424e3a4SYakir Yang 		 * If bit 3 is 1, DisplayPort transaction.
7603424e3a4SYakir Yang 		 * If Bit 3 is 0, I2C transaction.
7613424e3a4SYakir Yang 		 */
7623424e3a4SYakir Yang 		reg = AUX_TX_COMM_I2C_TRANSACTION |
7633424e3a4SYakir Yang 			AUX_TX_COMM_READ;
764092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1);
7653424e3a4SYakir Yang 
7663424e3a4SYakir Yang 		/* Start AUX transaction */
7673424e3a4SYakir Yang 		retval = analogix_dp_start_aux_transaction(dp);
7683424e3a4SYakir Yang 		if (retval == 0)
7693424e3a4SYakir Yang 			break;
770bcbb7033SYakir Yang 
771bcbb7033SYakir Yang 		dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__);
7723424e3a4SYakir Yang 	}
7733424e3a4SYakir Yang 
7743424e3a4SYakir Yang 	/* Read data */
7753424e3a4SYakir Yang 	if (retval == 0)
776092f8994SHeiko Stuebner 		*data = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0);
7773424e3a4SYakir Yang 
7783424e3a4SYakir Yang 	return retval;
7793424e3a4SYakir Yang }
7803424e3a4SYakir Yang 
7813424e3a4SYakir Yang int analogix_dp_read_bytes_from_i2c(struct analogix_dp_device *dp,
7823424e3a4SYakir Yang 				    unsigned int device_addr,
7833424e3a4SYakir Yang 				    unsigned int reg_addr,
7843424e3a4SYakir Yang 				    unsigned int count,
7853424e3a4SYakir Yang 				    unsigned char edid[])
7863424e3a4SYakir Yang {
7873424e3a4SYakir Yang 	u32 reg;
7883424e3a4SYakir Yang 	unsigned int i, j;
7893424e3a4SYakir Yang 	unsigned int cur_data_idx;
7903424e3a4SYakir Yang 	unsigned int defer = 0;
7913424e3a4SYakir Yang 	int retval = 0;
7923424e3a4SYakir Yang 
7933424e3a4SYakir Yang 	for (i = 0; i < count; i += 16) {
7943424e3a4SYakir Yang 		for (j = 0; j < 3; j++) {
7953424e3a4SYakir Yang 			/* Clear AUX CH data buffer */
7963424e3a4SYakir Yang 			reg = BUF_CLR;
797092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL);
7983424e3a4SYakir Yang 
7993424e3a4SYakir Yang 			/* Set normal AUX CH command */
800092f8994SHeiko Stuebner 			reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2);
8013424e3a4SYakir Yang 			reg &= ~ADDR_ONLY;
802092f8994SHeiko Stuebner 			writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2);
8033424e3a4SYakir Yang 
8043424e3a4SYakir Yang 			/*
8053424e3a4SYakir Yang 			 * If Rx sends defer, Tx sends only reads
8063424e3a4SYakir Yang 			 * request without sending address
8073424e3a4SYakir Yang 			 */
8083424e3a4SYakir Yang 			if (!defer)
8093424e3a4SYakir Yang 				retval = analogix_dp_select_i2c_device(dp,
8103424e3a4SYakir Yang 						device_addr, reg_addr + i);
8113424e3a4SYakir Yang 			else
8123424e3a4SYakir Yang 				defer = 0;
8133424e3a4SYakir Yang 
8143424e3a4SYakir Yang 			if (retval == 0) {
8153424e3a4SYakir Yang 				/*
8163424e3a4SYakir Yang 				 * Set I2C transaction and write data
8173424e3a4SYakir Yang 				 * If bit 3 is 1, DisplayPort transaction.
8183424e3a4SYakir Yang 				 * If Bit 3 is 0, I2C transaction.
8193424e3a4SYakir Yang 				 */
8203424e3a4SYakir Yang 				reg = AUX_LENGTH(16) |
8213424e3a4SYakir Yang 					AUX_TX_COMM_I2C_TRANSACTION |
8223424e3a4SYakir Yang 					AUX_TX_COMM_READ;
8233424e3a4SYakir Yang 				writel(reg, dp->reg_base +
824092f8994SHeiko Stuebner 					ANALOGIX_DP_AUX_CH_CTL_1);
8253424e3a4SYakir Yang 
8263424e3a4SYakir Yang 				/* Start AUX transaction */
8273424e3a4SYakir Yang 				retval = analogix_dp_start_aux_transaction(dp);
8283424e3a4SYakir Yang 				if (retval == 0)
8293424e3a4SYakir Yang 					break;
830bcbb7033SYakir Yang 
831bcbb7033SYakir Yang 				dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
8323424e3a4SYakir Yang 					__func__);
8333424e3a4SYakir Yang 			}
8343424e3a4SYakir Yang 			/* Check if Rx sends defer */
835092f8994SHeiko Stuebner 			reg = readl(dp->reg_base + ANALOGIX_DP_AUX_RX_COMM);
8363424e3a4SYakir Yang 			if (reg == AUX_RX_COMM_AUX_DEFER ||
8373424e3a4SYakir Yang 			    reg == AUX_RX_COMM_I2C_DEFER) {
8383424e3a4SYakir Yang 				dev_err(dp->dev, "Defer: %d\n\n", reg);
8393424e3a4SYakir Yang 				defer = 1;
8403424e3a4SYakir Yang 			}
8413424e3a4SYakir Yang 		}
8423424e3a4SYakir Yang 
8433424e3a4SYakir Yang 		for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) {
844092f8994SHeiko Stuebner 			reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0
8453424e3a4SYakir Yang 						 + 4 * cur_data_idx);
8463424e3a4SYakir Yang 			edid[i + cur_data_idx] = (unsigned char)reg;
8473424e3a4SYakir Yang 		}
8483424e3a4SYakir Yang 	}
8493424e3a4SYakir Yang 
8503424e3a4SYakir Yang 	return retval;
8513424e3a4SYakir Yang }
8523424e3a4SYakir Yang 
8533424e3a4SYakir Yang void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype)
8543424e3a4SYakir Yang {
8553424e3a4SYakir Yang 	u32 reg;
8563424e3a4SYakir Yang 
8573424e3a4SYakir Yang 	reg = bwtype;
8583424e3a4SYakir Yang 	if ((bwtype == LINK_RATE_2_70GBPS) || (bwtype == LINK_RATE_1_62GBPS))
859092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_LINK_BW_SET);
8603424e3a4SYakir Yang }
8613424e3a4SYakir Yang 
8623424e3a4SYakir Yang void analogix_dp_get_link_bandwidth(struct analogix_dp_device *dp, u32 *bwtype)
8633424e3a4SYakir Yang {
8643424e3a4SYakir Yang 	u32 reg;
8653424e3a4SYakir Yang 
866092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_LINK_BW_SET);
8673424e3a4SYakir Yang 	*bwtype = reg;
8683424e3a4SYakir Yang }
8693424e3a4SYakir Yang 
8703424e3a4SYakir Yang void analogix_dp_set_lane_count(struct analogix_dp_device *dp, u32 count)
8713424e3a4SYakir Yang {
8723424e3a4SYakir Yang 	u32 reg;
8733424e3a4SYakir Yang 
8743424e3a4SYakir Yang 	reg = count;
875092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_LANE_COUNT_SET);
8763424e3a4SYakir Yang }
8773424e3a4SYakir Yang 
8783424e3a4SYakir Yang void analogix_dp_get_lane_count(struct analogix_dp_device *dp, u32 *count)
8793424e3a4SYakir Yang {
8803424e3a4SYakir Yang 	u32 reg;
8813424e3a4SYakir Yang 
882092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_LANE_COUNT_SET);
8833424e3a4SYakir Yang 	*count = reg;
8843424e3a4SYakir Yang }
8853424e3a4SYakir Yang 
886bcbb7033SYakir Yang void analogix_dp_enable_enhanced_mode(struct analogix_dp_device *dp,
887bcbb7033SYakir Yang 				      bool enable)
8883424e3a4SYakir Yang {
8893424e3a4SYakir Yang 	u32 reg;
8903424e3a4SYakir Yang 
8913424e3a4SYakir Yang 	if (enable) {
892092f8994SHeiko Stuebner 		reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_4);
8933424e3a4SYakir Yang 		reg |= ENHANCED;
894092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_4);
8953424e3a4SYakir Yang 	} else {
896092f8994SHeiko Stuebner 		reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_4);
8973424e3a4SYakir Yang 		reg &= ~ENHANCED;
898092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_4);
8993424e3a4SYakir Yang 	}
9003424e3a4SYakir Yang }
9013424e3a4SYakir Yang 
9023424e3a4SYakir Yang void analogix_dp_set_training_pattern(struct analogix_dp_device *dp,
9033424e3a4SYakir Yang 				      enum pattern_set pattern)
9043424e3a4SYakir Yang {
9053424e3a4SYakir Yang 	u32 reg;
9063424e3a4SYakir Yang 
9073424e3a4SYakir Yang 	switch (pattern) {
9083424e3a4SYakir Yang 	case PRBS7:
9093424e3a4SYakir Yang 		reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7;
910092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET);
9113424e3a4SYakir Yang 		break;
9123424e3a4SYakir Yang 	case D10_2:
9133424e3a4SYakir Yang 		reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2;
914092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET);
9153424e3a4SYakir Yang 		break;
9163424e3a4SYakir Yang 	case TRAINING_PTN1:
9173424e3a4SYakir Yang 		reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1;
918092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET);
9193424e3a4SYakir Yang 		break;
9203424e3a4SYakir Yang 	case TRAINING_PTN2:
9213424e3a4SYakir Yang 		reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2;
922092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET);
9233424e3a4SYakir Yang 		break;
9243424e3a4SYakir Yang 	case DP_NONE:
9253424e3a4SYakir Yang 		reg = SCRAMBLING_ENABLE |
9263424e3a4SYakir Yang 			LINK_QUAL_PATTERN_SET_DISABLE |
9273424e3a4SYakir Yang 			SW_TRAINING_PATTERN_SET_NORMAL;
928092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET);
9293424e3a4SYakir Yang 		break;
9303424e3a4SYakir Yang 	default:
9313424e3a4SYakir Yang 		break;
9323424e3a4SYakir Yang 	}
9333424e3a4SYakir Yang }
9343424e3a4SYakir Yang 
935bcbb7033SYakir Yang void analogix_dp_set_lane0_pre_emphasis(struct analogix_dp_device *dp,
936bcbb7033SYakir Yang 					u32 level)
9373424e3a4SYakir Yang {
9383424e3a4SYakir Yang 	u32 reg;
9393424e3a4SYakir Yang 
940092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL);
9413424e3a4SYakir Yang 	reg &= ~PRE_EMPHASIS_SET_MASK;
9423424e3a4SYakir Yang 	reg |= level << PRE_EMPHASIS_SET_SHIFT;
943092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL);
9443424e3a4SYakir Yang }
9453424e3a4SYakir Yang 
946bcbb7033SYakir Yang void analogix_dp_set_lane1_pre_emphasis(struct analogix_dp_device *dp,
947bcbb7033SYakir Yang 					u32 level)
9483424e3a4SYakir Yang {
9493424e3a4SYakir Yang 	u32 reg;
9503424e3a4SYakir Yang 
951092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL);
9523424e3a4SYakir Yang 	reg &= ~PRE_EMPHASIS_SET_MASK;
9533424e3a4SYakir Yang 	reg |= level << PRE_EMPHASIS_SET_SHIFT;
954092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL);
9553424e3a4SYakir Yang }
9563424e3a4SYakir Yang 
957bcbb7033SYakir Yang void analogix_dp_set_lane2_pre_emphasis(struct analogix_dp_device *dp,
958bcbb7033SYakir Yang 					u32 level)
9593424e3a4SYakir Yang {
9603424e3a4SYakir Yang 	u32 reg;
9613424e3a4SYakir Yang 
962092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL);
9633424e3a4SYakir Yang 	reg &= ~PRE_EMPHASIS_SET_MASK;
9643424e3a4SYakir Yang 	reg |= level << PRE_EMPHASIS_SET_SHIFT;
965092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL);
9663424e3a4SYakir Yang }
9673424e3a4SYakir Yang 
968bcbb7033SYakir Yang void analogix_dp_set_lane3_pre_emphasis(struct analogix_dp_device *dp,
969bcbb7033SYakir Yang 					u32 level)
9703424e3a4SYakir Yang {
9713424e3a4SYakir Yang 	u32 reg;
9723424e3a4SYakir Yang 
973092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL);
9743424e3a4SYakir Yang 	reg &= ~PRE_EMPHASIS_SET_MASK;
9753424e3a4SYakir Yang 	reg |= level << PRE_EMPHASIS_SET_SHIFT;
976092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL);
9773424e3a4SYakir Yang }
9783424e3a4SYakir Yang 
9793424e3a4SYakir Yang void analogix_dp_set_lane0_link_training(struct analogix_dp_device *dp,
9803424e3a4SYakir Yang 					 u32 training_lane)
9813424e3a4SYakir Yang {
9823424e3a4SYakir Yang 	u32 reg;
9833424e3a4SYakir Yang 
9843424e3a4SYakir Yang 	reg = training_lane;
985092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL);
9863424e3a4SYakir Yang }
9873424e3a4SYakir Yang 
9883424e3a4SYakir Yang void analogix_dp_set_lane1_link_training(struct analogix_dp_device *dp,
9893424e3a4SYakir Yang 					 u32 training_lane)
9903424e3a4SYakir Yang {
9913424e3a4SYakir Yang 	u32 reg;
9923424e3a4SYakir Yang 
9933424e3a4SYakir Yang 	reg = training_lane;
994092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL);
9953424e3a4SYakir Yang }
9963424e3a4SYakir Yang 
9973424e3a4SYakir Yang void analogix_dp_set_lane2_link_training(struct analogix_dp_device *dp,
9983424e3a4SYakir Yang 					 u32 training_lane)
9993424e3a4SYakir Yang {
10003424e3a4SYakir Yang 	u32 reg;
10013424e3a4SYakir Yang 
10023424e3a4SYakir Yang 	reg = training_lane;
1003092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL);
10043424e3a4SYakir Yang }
10053424e3a4SYakir Yang 
10063424e3a4SYakir Yang void analogix_dp_set_lane3_link_training(struct analogix_dp_device *dp,
10073424e3a4SYakir Yang 					 u32 training_lane)
10083424e3a4SYakir Yang {
10093424e3a4SYakir Yang 	u32 reg;
10103424e3a4SYakir Yang 
10113424e3a4SYakir Yang 	reg = training_lane;
1012092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL);
10133424e3a4SYakir Yang }
10143424e3a4SYakir Yang 
10153424e3a4SYakir Yang u32 analogix_dp_get_lane0_link_training(struct analogix_dp_device *dp)
10163424e3a4SYakir Yang {
10173424e3a4SYakir Yang 	u32 reg;
10183424e3a4SYakir Yang 
1019092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL);
10203424e3a4SYakir Yang 	return reg;
10213424e3a4SYakir Yang }
10223424e3a4SYakir Yang 
10233424e3a4SYakir Yang u32 analogix_dp_get_lane1_link_training(struct analogix_dp_device *dp)
10243424e3a4SYakir Yang {
10253424e3a4SYakir Yang 	u32 reg;
10263424e3a4SYakir Yang 
1027092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL);
10283424e3a4SYakir Yang 	return reg;
10293424e3a4SYakir Yang }
10303424e3a4SYakir Yang 
10313424e3a4SYakir Yang u32 analogix_dp_get_lane2_link_training(struct analogix_dp_device *dp)
10323424e3a4SYakir Yang {
10333424e3a4SYakir Yang 	u32 reg;
10343424e3a4SYakir Yang 
1035092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL);
10363424e3a4SYakir Yang 	return reg;
10373424e3a4SYakir Yang }
10383424e3a4SYakir Yang 
10393424e3a4SYakir Yang u32 analogix_dp_get_lane3_link_training(struct analogix_dp_device *dp)
10403424e3a4SYakir Yang {
10413424e3a4SYakir Yang 	u32 reg;
10423424e3a4SYakir Yang 
1043092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL);
10443424e3a4SYakir Yang 	return reg;
10453424e3a4SYakir Yang }
10463424e3a4SYakir Yang 
10473424e3a4SYakir Yang void analogix_dp_reset_macro(struct analogix_dp_device *dp)
10483424e3a4SYakir Yang {
10493424e3a4SYakir Yang 	u32 reg;
10503424e3a4SYakir Yang 
1051092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_PHY_TEST);
10523424e3a4SYakir Yang 	reg |= MACRO_RST;
1053092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_PHY_TEST);
10543424e3a4SYakir Yang 
10553424e3a4SYakir Yang 	/* 10 us is the minimum reset time. */
10563424e3a4SYakir Yang 	usleep_range(10, 20);
10573424e3a4SYakir Yang 
10583424e3a4SYakir Yang 	reg &= ~MACRO_RST;
1059092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_PHY_TEST);
10603424e3a4SYakir Yang }
10613424e3a4SYakir Yang 
10623424e3a4SYakir Yang void analogix_dp_init_video(struct analogix_dp_device *dp)
10633424e3a4SYakir Yang {
10643424e3a4SYakir Yang 	u32 reg;
10653424e3a4SYakir Yang 
10663424e3a4SYakir Yang 	reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG;
1067092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_1);
10683424e3a4SYakir Yang 
10693424e3a4SYakir Yang 	reg = 0x0;
1070092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_1);
10713424e3a4SYakir Yang 
10723424e3a4SYakir Yang 	reg = CHA_CRI(4) | CHA_CTRL;
1073092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_2);
10743424e3a4SYakir Yang 
10753424e3a4SYakir Yang 	reg = 0x0;
1076092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_3);
10773424e3a4SYakir Yang 
10783424e3a4SYakir Yang 	reg = VID_HRES_TH(2) | VID_VRES_TH(0);
1079092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_8);
10803424e3a4SYakir Yang }
10813424e3a4SYakir Yang 
10823424e3a4SYakir Yang void analogix_dp_set_video_color_format(struct analogix_dp_device *dp)
10833424e3a4SYakir Yang {
10843424e3a4SYakir Yang 	u32 reg;
10853424e3a4SYakir Yang 
10863424e3a4SYakir Yang 	/* Configure the input color depth, color space, dynamic range */
10873424e3a4SYakir Yang 	reg = (dp->video_info->dynamic_range << IN_D_RANGE_SHIFT) |
10883424e3a4SYakir Yang 		(dp->video_info->color_depth << IN_BPC_SHIFT) |
10893424e3a4SYakir Yang 		(dp->video_info->color_space << IN_COLOR_F_SHIFT);
1090092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_2);
10913424e3a4SYakir Yang 
10923424e3a4SYakir Yang 	/* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */
1093092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_3);
10943424e3a4SYakir Yang 	reg &= ~IN_YC_COEFFI_MASK;
10953424e3a4SYakir Yang 	if (dp->video_info->ycbcr_coeff)
10963424e3a4SYakir Yang 		reg |= IN_YC_COEFFI_ITU709;
10973424e3a4SYakir Yang 	else
10983424e3a4SYakir Yang 		reg |= IN_YC_COEFFI_ITU601;
1099092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_3);
11003424e3a4SYakir Yang }
11013424e3a4SYakir Yang 
11023424e3a4SYakir Yang int analogix_dp_is_slave_video_stream_clock_on(struct analogix_dp_device *dp)
11033424e3a4SYakir Yang {
11043424e3a4SYakir Yang 	u32 reg;
11053424e3a4SYakir Yang 
1106092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_1);
1107092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_1);
11083424e3a4SYakir Yang 
1109092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_1);
11103424e3a4SYakir Yang 
11113424e3a4SYakir Yang 	if (!(reg & DET_STA)) {
11123424e3a4SYakir Yang 		dev_dbg(dp->dev, "Input stream clock not detected.\n");
11133424e3a4SYakir Yang 		return -EINVAL;
11143424e3a4SYakir Yang 	}
11153424e3a4SYakir Yang 
1116092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_2);
1117092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_2);
11183424e3a4SYakir Yang 
1119092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_2);
11203424e3a4SYakir Yang 	dev_dbg(dp->dev, "wait SYS_CTL_2.\n");
11213424e3a4SYakir Yang 
11223424e3a4SYakir Yang 	if (reg & CHA_STA) {
11233424e3a4SYakir Yang 		dev_dbg(dp->dev, "Input stream clk is changing\n");
11243424e3a4SYakir Yang 		return -EINVAL;
11253424e3a4SYakir Yang 	}
11263424e3a4SYakir Yang 
11273424e3a4SYakir Yang 	return 0;
11283424e3a4SYakir Yang }
11293424e3a4SYakir Yang 
11303424e3a4SYakir Yang void analogix_dp_set_video_cr_mn(struct analogix_dp_device *dp,
11313424e3a4SYakir Yang 				 enum clock_recovery_m_value_type type,
1132bcbb7033SYakir Yang 				 u32 m_value, u32 n_value)
11333424e3a4SYakir Yang {
11343424e3a4SYakir Yang 	u32 reg;
11353424e3a4SYakir Yang 
11363424e3a4SYakir Yang 	if (type == REGISTER_M) {
1137092f8994SHeiko Stuebner 		reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_4);
11383424e3a4SYakir Yang 		reg |= FIX_M_VID;
1139092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_4);
11403424e3a4SYakir Yang 		reg = m_value & 0xff;
1141092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_M_VID_0);
11423424e3a4SYakir Yang 		reg = (m_value >> 8) & 0xff;
1143092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_M_VID_1);
11443424e3a4SYakir Yang 		reg = (m_value >> 16) & 0xff;
1145092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_M_VID_2);
11463424e3a4SYakir Yang 
11473424e3a4SYakir Yang 		reg = n_value & 0xff;
1148092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_N_VID_0);
11493424e3a4SYakir Yang 		reg = (n_value >> 8) & 0xff;
1150092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_N_VID_1);
11513424e3a4SYakir Yang 		reg = (n_value >> 16) & 0xff;
1152092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_N_VID_2);
11533424e3a4SYakir Yang 	} else  {
1154092f8994SHeiko Stuebner 		reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_4);
11553424e3a4SYakir Yang 		reg &= ~FIX_M_VID;
1156092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_4);
11573424e3a4SYakir Yang 
1158092f8994SHeiko Stuebner 		writel(0x00, dp->reg_base + ANALOGIX_DP_N_VID_0);
1159092f8994SHeiko Stuebner 		writel(0x80, dp->reg_base + ANALOGIX_DP_N_VID_1);
1160092f8994SHeiko Stuebner 		writel(0x00, dp->reg_base + ANALOGIX_DP_N_VID_2);
11613424e3a4SYakir Yang 	}
11623424e3a4SYakir Yang }
11633424e3a4SYakir Yang 
11643424e3a4SYakir Yang void analogix_dp_set_video_timing_mode(struct analogix_dp_device *dp, u32 type)
11653424e3a4SYakir Yang {
11663424e3a4SYakir Yang 	u32 reg;
11673424e3a4SYakir Yang 
11683424e3a4SYakir Yang 	if (type == VIDEO_TIMING_FROM_CAPTURE) {
1169092f8994SHeiko Stuebner 		reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);
11703424e3a4SYakir Yang 		reg &= ~FORMAT_SEL;
1171092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);
11723424e3a4SYakir Yang 	} else {
1173092f8994SHeiko Stuebner 		reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);
11743424e3a4SYakir Yang 		reg |= FORMAT_SEL;
1175092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);
11763424e3a4SYakir Yang 	}
11773424e3a4SYakir Yang }
11783424e3a4SYakir Yang 
11793424e3a4SYakir Yang void analogix_dp_enable_video_master(struct analogix_dp_device *dp, bool enable)
11803424e3a4SYakir Yang {
11813424e3a4SYakir Yang 	u32 reg;
11823424e3a4SYakir Yang 
11833424e3a4SYakir Yang 	if (enable) {
1184092f8994SHeiko Stuebner 		reg = readl(dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL);
11853424e3a4SYakir Yang 		reg &= ~VIDEO_MODE_MASK;
11863424e3a4SYakir Yang 		reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE;
1187092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL);
11883424e3a4SYakir Yang 	} else {
1189092f8994SHeiko Stuebner 		reg = readl(dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL);
11903424e3a4SYakir Yang 		reg &= ~VIDEO_MODE_MASK;
11913424e3a4SYakir Yang 		reg |= VIDEO_MODE_SLAVE_MODE;
1192092f8994SHeiko Stuebner 		writel(reg, dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL);
11933424e3a4SYakir Yang 	}
11943424e3a4SYakir Yang }
11953424e3a4SYakir Yang 
11963424e3a4SYakir Yang void analogix_dp_start_video(struct analogix_dp_device *dp)
11973424e3a4SYakir Yang {
11983424e3a4SYakir Yang 	u32 reg;
11993424e3a4SYakir Yang 
1200092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1);
12013424e3a4SYakir Yang 	reg |= VIDEO_EN;
1202092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1);
12033424e3a4SYakir Yang }
12043424e3a4SYakir Yang 
12053424e3a4SYakir Yang int analogix_dp_is_video_stream_on(struct analogix_dp_device *dp)
12063424e3a4SYakir Yang {
12073424e3a4SYakir Yang 	u32 reg;
12083424e3a4SYakir Yang 
1209092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_3);
1210092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_3);
12113424e3a4SYakir Yang 
1212092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_3);
12133424e3a4SYakir Yang 	if (!(reg & STRM_VALID)) {
12143424e3a4SYakir Yang 		dev_dbg(dp->dev, "Input video stream is not detected.\n");
12153424e3a4SYakir Yang 		return -EINVAL;
12163424e3a4SYakir Yang 	}
12173424e3a4SYakir Yang 
12183424e3a4SYakir Yang 	return 0;
12193424e3a4SYakir Yang }
12203424e3a4SYakir Yang 
12213424e3a4SYakir Yang void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp)
12223424e3a4SYakir Yang {
12233424e3a4SYakir Yang 	u32 reg;
12243424e3a4SYakir Yang 
1225092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_1);
12263424e3a4SYakir Yang 	reg &= ~(MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N);
12273424e3a4SYakir Yang 	reg |= MASTER_VID_FUNC_EN_N;
1228092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_1);
12293424e3a4SYakir Yang 
1230092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);
12313424e3a4SYakir Yang 	reg &= ~INTERACE_SCAN_CFG;
12323424e3a4SYakir Yang 	reg |= (dp->video_info->interlaced << 2);
1233092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);
12343424e3a4SYakir Yang 
1235092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);
12363424e3a4SYakir Yang 	reg &= ~VSYNC_POLARITY_CFG;
12373424e3a4SYakir Yang 	reg |= (dp->video_info->v_sync_polarity << 1);
1238092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);
12393424e3a4SYakir Yang 
1240092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);
12413424e3a4SYakir Yang 	reg &= ~HSYNC_POLARITY_CFG;
12423424e3a4SYakir Yang 	reg |= (dp->video_info->h_sync_polarity << 0);
1243092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);
12443424e3a4SYakir Yang 
12453424e3a4SYakir Yang 	reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE;
1246092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL);
12473424e3a4SYakir Yang }
12483424e3a4SYakir Yang 
12493424e3a4SYakir Yang void analogix_dp_enable_scrambling(struct analogix_dp_device *dp)
12503424e3a4SYakir Yang {
12513424e3a4SYakir Yang 	u32 reg;
12523424e3a4SYakir Yang 
1253092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET);
12543424e3a4SYakir Yang 	reg &= ~SCRAMBLING_DISABLE;
1255092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET);
12563424e3a4SYakir Yang }
12573424e3a4SYakir Yang 
12583424e3a4SYakir Yang void analogix_dp_disable_scrambling(struct analogix_dp_device *dp)
12593424e3a4SYakir Yang {
12603424e3a4SYakir Yang 	u32 reg;
12613424e3a4SYakir Yang 
1262092f8994SHeiko Stuebner 	reg = readl(dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET);
12633424e3a4SYakir Yang 	reg |= SCRAMBLING_DISABLE;
1264092f8994SHeiko Stuebner 	writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET);
12653424e3a4SYakir Yang }
1266