xref: /rk3399_rockchip-uboot/drivers/video/drm/analogix_dp_reg.c (revision fc2750785b7f24959c90ae972527f1ce47886d52)
16f920c07SWyon Bi /*
26f920c07SWyon Bi  * Analogix DP (Display port) core register interface driver.
36f920c07SWyon Bi  *
46f920c07SWyon Bi  * Copyright (C) 2008-2017 Fuzhou Rockchip Electronics Co., Ltd
56f920c07SWyon Bi  * Copyright (C) 2012 Samsung Electronics Co., Ltd.
66f920c07SWyon Bi  * Author: Jingoo Han <jg1.han@samsung.com>
76f920c07SWyon Bi  *
86f920c07SWyon Bi  * This program is free software; you can redistribute it and/or modify it
96f920c07SWyon Bi  * under the terms of the GNU General Public License as published by the
106f920c07SWyon Bi  * Free Software Foundation; either version 2 of the License, or (at your
116f920c07SWyon Bi  * option) any later version.
126f920c07SWyon Bi  */
136f920c07SWyon Bi 
146f920c07SWyon Bi #include <config.h>
156f920c07SWyon Bi #include <common.h>
166f920c07SWyon Bi #include <errno.h>
176f920c07SWyon Bi #include <malloc.h>
186f920c07SWyon Bi #include <asm/unaligned.h>
196f920c07SWyon Bi #include <linux/list.h>
206f920c07SWyon Bi #include <dm/device.h>
216f920c07SWyon Bi #include <syscon.h>
226f920c07SWyon Bi #include <asm/io.h>
236f920c07SWyon Bi #include <asm/gpio.h>
24a6285d17SWyon Bi #include <linux/iopoll.h>
256f920c07SWyon Bi 
266f920c07SWyon Bi #include "rockchip_display.h"
276f920c07SWyon Bi #include "rockchip_crtc.h"
286f920c07SWyon Bi #include "rockchip_connector.h"
296f920c07SWyon Bi #include "analogix_dp.h"
306f920c07SWyon Bi 
316f920c07SWyon Bi #define COMMON_INT_MASK_1	0
326f920c07SWyon Bi #define COMMON_INT_MASK_2	0
336f920c07SWyon Bi #define COMMON_INT_MASK_3	0
346f920c07SWyon Bi #define COMMON_INT_MASK_4	(HOTPLUG_CHG | HPD_LOST | PLUG)
356f920c07SWyon Bi #define INT_STA_MASK		INT_HPD
366f920c07SWyon Bi 
analogix_dp_write(struct analogix_dp_device * dp,u32 reg,u32 val)3752db8715SWyon Bi static void analogix_dp_write(struct analogix_dp_device *dp, u32 reg, u32 val)
3852db8715SWyon Bi {
3952db8715SWyon Bi 	readl(dp->reg_base);
4052db8715SWyon Bi 	writel(val, dp->reg_base + reg);
4152db8715SWyon Bi 	writel(val, dp->reg_base + reg);
4252db8715SWyon Bi }
4352db8715SWyon Bi 
analogix_dp_read(struct analogix_dp_device * dp,u32 reg)4452db8715SWyon Bi static u32 analogix_dp_read(struct analogix_dp_device *dp, u32 reg)
4552db8715SWyon Bi {
4652db8715SWyon Bi 	readl(dp->reg_base + reg);
4752db8715SWyon Bi 
4852db8715SWyon Bi 	return readl(dp->reg_base + reg);
4952db8715SWyon Bi }
5052db8715SWyon Bi 
analogix_dp_enable_video_mute(struct analogix_dp_device * dp,bool enable)516f920c07SWyon Bi void analogix_dp_enable_video_mute(struct analogix_dp_device *dp, bool enable)
526f920c07SWyon Bi {
536f920c07SWyon Bi 	u32 reg;
546f920c07SWyon Bi 
556f920c07SWyon Bi 	if (enable) {
5652db8715SWyon Bi 		reg = analogix_dp_read(dp, ANALOGIX_DP_VIDEO_CTL_1);
576f920c07SWyon Bi 		reg |= HDCP_VIDEO_MUTE;
5852db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_VIDEO_CTL_1, reg);
596f920c07SWyon Bi 	} else {
6052db8715SWyon Bi 		reg = analogix_dp_read(dp, ANALOGIX_DP_VIDEO_CTL_1);
616f920c07SWyon Bi 		reg &= ~HDCP_VIDEO_MUTE;
6252db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_VIDEO_CTL_1, reg);
636f920c07SWyon Bi 	}
646f920c07SWyon Bi }
656f920c07SWyon Bi 
analogix_dp_stop_video(struct analogix_dp_device * dp)666f920c07SWyon Bi void analogix_dp_stop_video(struct analogix_dp_device *dp)
676f920c07SWyon Bi {
686f920c07SWyon Bi 	u32 reg;
696f920c07SWyon Bi 
7052db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_VIDEO_CTL_1);
716f920c07SWyon Bi 	reg &= ~VIDEO_EN;
7252db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_VIDEO_CTL_1, reg);
736f920c07SWyon Bi }
746f920c07SWyon Bi 
analogix_dp_set_lane_map(struct analogix_dp_device * dp)751f59ac36SWyon Bi static void analogix_dp_set_lane_map(struct analogix_dp_device *dp)
766f920c07SWyon Bi {
771f59ac36SWyon Bi 	u32 i, reg = 0;
786f920c07SWyon Bi 
791f59ac36SWyon Bi 	for (i = 0; i < dp->video_info.max_lane_count; i++)
801f59ac36SWyon Bi 		reg |= dp->lane_map[i] << (2 * i);
816f920c07SWyon Bi 
8252db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_LANE_MAP, reg);
836f920c07SWyon Bi }
846f920c07SWyon Bi 
analogix_dp_init_analog_param(struct analogix_dp_device * dp)856f920c07SWyon Bi void analogix_dp_init_analog_param(struct analogix_dp_device *dp)
866f920c07SWyon Bi {
876f920c07SWyon Bi 	u32 reg;
886f920c07SWyon Bi 
896f920c07SWyon Bi 	reg = TX_TERMINAL_CTRL_50_OHM;
9052db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_ANALOG_CTL_1, reg);
916f920c07SWyon Bi 
926f920c07SWyon Bi 	reg = SEL_24M | TX_DVDD_BIT_1_0625V;
9352db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_ANALOG_CTL_2, reg);
946f920c07SWyon Bi 
956f920c07SWyon Bi 	if (dp->plat_data.dev_type == ROCKCHIP_DP) {
966f920c07SWyon Bi 		reg = REF_CLK_24M;
976f920c07SWyon Bi 		if (dp->plat_data.subdev_type == RK3288_DP ||
986f920c07SWyon Bi 		    dp->plat_data.subdev_type == RK3368_EDP)
996f920c07SWyon Bi 			reg ^= REF_CLK_MASK;
1006f920c07SWyon Bi 
10152db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_PLL_REG_1, reg);
1029f415b59SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_PLL_REG_2, 0x99);
10352db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_PLL_REG_3, 0x40);
10452db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_PLL_REG_4, 0x58);
10552db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_PLL_REG_5, 0x22);
1069f415b59SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_BIAS, 0x44);
1076f920c07SWyon Bi 	}
1086f920c07SWyon Bi 
1096f920c07SWyon Bi 	reg = DRIVE_DVDD_BIT_1_0625V | VCO_BIT_600_MICRO;
11052db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_ANALOG_CTL_3, reg);
1116f920c07SWyon Bi 
1126f920c07SWyon Bi 	reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM |
1136f920c07SWyon Bi 		TX_CUR1_2X | TX_CUR_16_MA;
11452db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_PLL_FILTER_CTL_1, reg);
1156f920c07SWyon Bi 
1166f920c07SWyon Bi 	reg = CH3_AMP_400_MV | CH2_AMP_400_MV |
1176f920c07SWyon Bi 		CH1_AMP_400_MV | CH0_AMP_400_MV;
11852db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_TX_AMP_TUNING_CTL, reg);
1196f920c07SWyon Bi }
1206f920c07SWyon Bi 
analogix_dp_init_interrupt(struct analogix_dp_device * dp)1216f920c07SWyon Bi void analogix_dp_init_interrupt(struct analogix_dp_device *dp)
1226f920c07SWyon Bi {
1236f920c07SWyon Bi 	/* Set interrupt pin assertion polarity as high */
12452db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_INT_CTL, INT_POL1 | INT_POL0);
1256f920c07SWyon Bi 
1266f920c07SWyon Bi 	/* Clear pending regisers */
12752db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_STA_1, 0xff);
12852db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_STA_2, 0x4f);
12952db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_STA_3, 0xe0);
13052db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_STA_4, 0xe7);
13152db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_INT_STA, 0x63);
1326f920c07SWyon Bi 
1336f920c07SWyon Bi 	/* 0:mask,1: unmask */
13452db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_1, 0x00);
13552db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_2, 0x00);
13652db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_3, 0x00);
13752db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_4, 0x00);
13852db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_INT_STA_MASK, 0x00);
1396f920c07SWyon Bi }
1406f920c07SWyon Bi 
analogix_dp_reset(struct analogix_dp_device * dp)1416f920c07SWyon Bi void analogix_dp_reset(struct analogix_dp_device *dp)
1426f920c07SWyon Bi {
1436f920c07SWyon Bi 	u32 reg;
1446f920c07SWyon Bi 
1456f920c07SWyon Bi 	analogix_dp_stop_video(dp);
1466f920c07SWyon Bi 	analogix_dp_enable_video_mute(dp, 0);
1476f920c07SWyon Bi 
1486f920c07SWyon Bi 	reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N |
1496f920c07SWyon Bi 		AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N |
1506f920c07SWyon Bi 		HDCP_FUNC_EN_N | SW_FUNC_EN_N;
15152db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_FUNC_EN_1, reg);
1526f920c07SWyon Bi 
1536f920c07SWyon Bi 	reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N |
1546f920c07SWyon Bi 		SERDES_FIFO_FUNC_EN_N |
1556f920c07SWyon Bi 		LS_CLK_DOMAIN_FUNC_EN_N;
15652db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_FUNC_EN_2, reg);
1576f920c07SWyon Bi 
1586f920c07SWyon Bi 	udelay(30);
1596f920c07SWyon Bi 
1601f59ac36SWyon Bi 	analogix_dp_set_lane_map(dp);
1616f920c07SWyon Bi 
16252db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_1, 0x0);
16352db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_2, 0x40);
16452db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_3, 0x0);
16552db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_4, 0x0);
1666f920c07SWyon Bi 
16752db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_PKT_SEND_CTL, 0x0);
16852db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_HDCP_CTL, 0x0);
1696f920c07SWyon Bi 
17052db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_HPD_DEGLITCH_L, 0x5e);
17152db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_HPD_DEGLITCH_H, 0x1a);
1726f920c07SWyon Bi 
17352db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_LINK_DEBUG_CTL, 0x10);
1746f920c07SWyon Bi 
17552db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_PHY_TEST, 0x0);
1766f920c07SWyon Bi 
17752db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_VIDEO_FIFO_THRD, 0x0);
17852db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_AUDIO_MARGIN, 0x20);
1796f920c07SWyon Bi 
18052db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_M_VID_GEN_FILTER_TH, 0x4);
18152db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_M_AUD_GEN_FILTER_TH, 0x2);
1826f920c07SWyon Bi 
18352db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_SOC_GENERAL_CTL, 0x00000101);
1846f920c07SWyon Bi }
1856f920c07SWyon Bi 
analogix_dp_swreset(struct analogix_dp_device * dp)1866f920c07SWyon Bi void analogix_dp_swreset(struct analogix_dp_device *dp)
1876f920c07SWyon Bi {
18852db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_TX_SW_RESET, RESET_DP_TX);
1896f920c07SWyon Bi }
1906f920c07SWyon Bi 
analogix_dp_config_interrupt(struct analogix_dp_device * dp)1916f920c07SWyon Bi void analogix_dp_config_interrupt(struct analogix_dp_device *dp)
1926f920c07SWyon Bi {
1936f920c07SWyon Bi 	u32 reg;
1946f920c07SWyon Bi 
1956f920c07SWyon Bi 	/* 0: mask, 1: unmask */
1966f920c07SWyon Bi 	reg = COMMON_INT_MASK_1;
19752db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_1, reg);
1986f920c07SWyon Bi 
1996f920c07SWyon Bi 	reg = COMMON_INT_MASK_2;
20052db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_2, reg);
2016f920c07SWyon Bi 
2026f920c07SWyon Bi 	reg = COMMON_INT_MASK_3;
20352db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_3, reg);
2046f920c07SWyon Bi 
2056f920c07SWyon Bi 	reg = COMMON_INT_MASK_4;
20652db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_4, reg);
2076f920c07SWyon Bi 
2086f920c07SWyon Bi 	reg = INT_STA_MASK;
20952db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_INT_STA_MASK, reg);
2106f920c07SWyon Bi }
2116f920c07SWyon Bi 
analogix_dp_mute_hpd_interrupt(struct analogix_dp_device * dp)2126f920c07SWyon Bi void analogix_dp_mute_hpd_interrupt(struct analogix_dp_device *dp)
2136f920c07SWyon Bi {
2146f920c07SWyon Bi 	u32 reg;
2156f920c07SWyon Bi 
2166f920c07SWyon Bi 	/* 0: mask, 1: unmask */
21752db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_COMMON_INT_MASK_4);
2186f920c07SWyon Bi 	reg &= ~COMMON_INT_MASK_4;
21952db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_4, reg);
2206f920c07SWyon Bi 
22152db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_INT_STA_MASK);
2226f920c07SWyon Bi 	reg &= ~INT_STA_MASK;
22352db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_INT_STA_MASK, reg);
2246f920c07SWyon Bi }
2256f920c07SWyon Bi 
analogix_dp_unmute_hpd_interrupt(struct analogix_dp_device * dp)2266f920c07SWyon Bi void analogix_dp_unmute_hpd_interrupt(struct analogix_dp_device *dp)
2276f920c07SWyon Bi {
2286f920c07SWyon Bi 	u32 reg;
2296f920c07SWyon Bi 
2306f920c07SWyon Bi 	/* 0: mask, 1: unmask */
2316f920c07SWyon Bi 	reg = COMMON_INT_MASK_4;
23252db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_4, reg);
2336f920c07SWyon Bi 
2346f920c07SWyon Bi 	reg = INT_STA_MASK;
23552db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_INT_STA_MASK, reg);
2366f920c07SWyon Bi }
2376f920c07SWyon Bi 
analogix_dp_get_pll_lock_status(struct analogix_dp_device * dp)2386f920c07SWyon Bi enum pll_status analogix_dp_get_pll_lock_status(struct analogix_dp_device *dp)
2396f920c07SWyon Bi {
2406f920c07SWyon Bi 	u32 reg;
2416f920c07SWyon Bi 
24252db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_DEBUG_CTL);
2436f920c07SWyon Bi 	if (reg & PLL_LOCK)
2446f920c07SWyon Bi 		return PLL_LOCKED;
2456f920c07SWyon Bi 	else
2466f920c07SWyon Bi 		return PLL_UNLOCKED;
2476f920c07SWyon Bi }
2486f920c07SWyon Bi 
analogix_dp_set_pll_power_down(struct analogix_dp_device * dp,bool enable)2496f920c07SWyon Bi void analogix_dp_set_pll_power_down(struct analogix_dp_device *dp, bool enable)
2506f920c07SWyon Bi {
2516f920c07SWyon Bi 	u32 reg;
2526f920c07SWyon Bi 
2536f920c07SWyon Bi 	if (enable) {
25452db8715SWyon Bi 		reg = analogix_dp_read(dp, ANALOGIX_DP_PLL_CTL);
2556f920c07SWyon Bi 		reg |= DP_PLL_PD;
25652db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_PLL_CTL, reg);
2576f920c07SWyon Bi 	} else {
25852db8715SWyon Bi 		reg = analogix_dp_read(dp, ANALOGIX_DP_PLL_CTL);
2596f920c07SWyon Bi 		reg &= ~DP_PLL_PD;
26052db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_PLL_CTL, reg);
2616f920c07SWyon Bi 	}
2626f920c07SWyon Bi }
2636f920c07SWyon Bi 
analogix_dp_set_analog_power_down(struct analogix_dp_device * dp,enum analog_power_block block,bool enable)2646f920c07SWyon Bi void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp,
2656f920c07SWyon Bi 				       enum analog_power_block block,
2666f920c07SWyon Bi 				       bool enable)
2676f920c07SWyon Bi {
2686f920c07SWyon Bi 	u32 reg;
2696f920c07SWyon Bi 	u32 phy_pd_addr = ANALOGIX_DP_PHY_PD;
2706f920c07SWyon Bi 
2716f920c07SWyon Bi 	if (dp->plat_data.dev_type == ROCKCHIP_DP)
2726f920c07SWyon Bi 		phy_pd_addr = ANALOGIX_DP_PD;
2736f920c07SWyon Bi 
2746f920c07SWyon Bi 	switch (block) {
2756f920c07SWyon Bi 	case AUX_BLOCK:
2766f920c07SWyon Bi 		if (enable) {
27752db8715SWyon Bi 			reg = analogix_dp_read(dp, phy_pd_addr);
2786f920c07SWyon Bi 			reg |= AUX_PD;
27952db8715SWyon Bi 			analogix_dp_write(dp, phy_pd_addr, reg);
2806f920c07SWyon Bi 		} else {
28152db8715SWyon Bi 			reg = analogix_dp_read(dp, phy_pd_addr);
2826f920c07SWyon Bi 			reg &= ~AUX_PD;
28352db8715SWyon Bi 			analogix_dp_write(dp, phy_pd_addr, reg);
2846f920c07SWyon Bi 		}
2856f920c07SWyon Bi 		break;
2866f920c07SWyon Bi 	case CH0_BLOCK:
2876f920c07SWyon Bi 		if (enable) {
28852db8715SWyon Bi 			reg = analogix_dp_read(dp, phy_pd_addr);
2896f920c07SWyon Bi 			reg |= CH0_PD;
29052db8715SWyon Bi 			analogix_dp_write(dp, phy_pd_addr, reg);
2916f920c07SWyon Bi 		} else {
29252db8715SWyon Bi 			reg = analogix_dp_read(dp, phy_pd_addr);
2936f920c07SWyon Bi 			reg &= ~CH0_PD;
29452db8715SWyon Bi 			analogix_dp_write(dp, phy_pd_addr, reg);
2956f920c07SWyon Bi 		}
2966f920c07SWyon Bi 		break;
2976f920c07SWyon Bi 	case CH1_BLOCK:
2986f920c07SWyon Bi 		if (enable) {
29952db8715SWyon Bi 			reg = analogix_dp_read(dp, phy_pd_addr);
3006f920c07SWyon Bi 			reg |= CH1_PD;
30152db8715SWyon Bi 			analogix_dp_write(dp, phy_pd_addr, reg);
3026f920c07SWyon Bi 		} else {
30352db8715SWyon Bi 			reg = analogix_dp_read(dp, phy_pd_addr);
3046f920c07SWyon Bi 			reg &= ~CH1_PD;
30552db8715SWyon Bi 			analogix_dp_write(dp, phy_pd_addr, reg);
3066f920c07SWyon Bi 		}
3076f920c07SWyon Bi 		break;
3086f920c07SWyon Bi 	case CH2_BLOCK:
3096f920c07SWyon Bi 		if (enable) {
31052db8715SWyon Bi 			reg = analogix_dp_read(dp, phy_pd_addr);
3116f920c07SWyon Bi 			reg |= CH2_PD;
31252db8715SWyon Bi 			analogix_dp_write(dp, phy_pd_addr, reg);
3136f920c07SWyon Bi 		} else {
31452db8715SWyon Bi 			reg = analogix_dp_read(dp, phy_pd_addr);
3156f920c07SWyon Bi 			reg &= ~CH2_PD;
31652db8715SWyon Bi 			analogix_dp_write(dp, phy_pd_addr, reg);
3176f920c07SWyon Bi 		}
3186f920c07SWyon Bi 		break;
3196f920c07SWyon Bi 	case CH3_BLOCK:
3206f920c07SWyon Bi 		if (enable) {
32152db8715SWyon Bi 			reg = analogix_dp_read(dp, phy_pd_addr);
3226f920c07SWyon Bi 			reg |= CH3_PD;
32352db8715SWyon Bi 			analogix_dp_write(dp, phy_pd_addr, reg);
3246f920c07SWyon Bi 		} else {
32552db8715SWyon Bi 			reg = analogix_dp_read(dp, phy_pd_addr);
3266f920c07SWyon Bi 			reg &= ~CH3_PD;
32752db8715SWyon Bi 			analogix_dp_write(dp, phy_pd_addr, reg);
3286f920c07SWyon Bi 		}
3296f920c07SWyon Bi 		break;
3306f920c07SWyon Bi 	case ANALOG_TOTAL:
3316f920c07SWyon Bi 		if (enable) {
33252db8715SWyon Bi 			reg = analogix_dp_read(dp, phy_pd_addr);
3336f920c07SWyon Bi 			reg |= DP_PHY_PD;
33452db8715SWyon Bi 			analogix_dp_write(dp, phy_pd_addr, reg);
3356f920c07SWyon Bi 		} else {
33652db8715SWyon Bi 			reg = analogix_dp_read(dp, phy_pd_addr);
3376f920c07SWyon Bi 			reg &= ~DP_PHY_PD;
33852db8715SWyon Bi 			analogix_dp_write(dp, phy_pd_addr, reg);
3396f920c07SWyon Bi 		}
3406f920c07SWyon Bi 		break;
3416f920c07SWyon Bi 	case POWER_ALL:
3426f920c07SWyon Bi 		if (enable) {
3436f920c07SWyon Bi 			reg = DP_PHY_PD | AUX_PD | CH3_PD | CH2_PD |
3446f920c07SWyon Bi 				CH1_PD | CH0_PD;
34552db8715SWyon Bi 			analogix_dp_write(dp, phy_pd_addr, reg);
3466f920c07SWyon Bi 		} else {
34752db8715SWyon Bi 			analogix_dp_write(dp, phy_pd_addr, 0x00);
3486f920c07SWyon Bi 		}
3496f920c07SWyon Bi 		break;
3506f920c07SWyon Bi 	default:
3516f920c07SWyon Bi 		break;
3526f920c07SWyon Bi 	}
3536f920c07SWyon Bi }
3546f920c07SWyon Bi 
analogix_dp_init_analog_func(struct analogix_dp_device * dp)3556f920c07SWyon Bi void analogix_dp_init_analog_func(struct analogix_dp_device *dp)
3566f920c07SWyon Bi {
3576f920c07SWyon Bi 	u32 reg;
3586f920c07SWyon Bi 
3596f920c07SWyon Bi 	analogix_dp_set_analog_power_down(dp, POWER_ALL, 0);
3606f920c07SWyon Bi 
3616f920c07SWyon Bi 	reg = PLL_LOCK_CHG;
36252db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_STA_1, reg);
3636f920c07SWyon Bi 
36452db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_DEBUG_CTL);
3656f920c07SWyon Bi 	reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL);
36652db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_DEBUG_CTL, reg);
3676f920c07SWyon Bi 
3686f920c07SWyon Bi 	/* Power up PLL */
3696f920c07SWyon Bi 	analogix_dp_set_pll_power_down(dp, 0);
3706f920c07SWyon Bi 
3716f920c07SWyon Bi 	/* Enable Serdes FIFO function and Link symbol clock domain module */
37252db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_FUNC_EN_2);
3736f920c07SWyon Bi 	reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N
3746f920c07SWyon Bi 		| AUX_FUNC_EN_N);
37552db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_FUNC_EN_2, reg);
3766f920c07SWyon Bi }
3776f920c07SWyon Bi 
analogix_dp_clear_hotplug_interrupts(struct analogix_dp_device * dp)3786f920c07SWyon Bi void analogix_dp_clear_hotplug_interrupts(struct analogix_dp_device *dp)
3796f920c07SWyon Bi {
3806f920c07SWyon Bi 	u32 reg;
3816f920c07SWyon Bi 
3826f920c07SWyon Bi 	if (dm_gpio_is_valid(&dp->hpd_gpio))
3836f920c07SWyon Bi 		return;
3846f920c07SWyon Bi 
3856f920c07SWyon Bi 	reg = HOTPLUG_CHG | HPD_LOST | PLUG;
38652db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_STA_4, reg);
3876f920c07SWyon Bi 
3886f920c07SWyon Bi 	reg = INT_HPD;
38952db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_INT_STA, reg);
3906f920c07SWyon Bi }
3916f920c07SWyon Bi 
analogix_dp_init_hpd(struct analogix_dp_device * dp)3926f920c07SWyon Bi void analogix_dp_init_hpd(struct analogix_dp_device *dp)
3936f920c07SWyon Bi {
3946f920c07SWyon Bi 	u32 reg;
3956f920c07SWyon Bi 
3966f920c07SWyon Bi 	if (dm_gpio_is_valid(&dp->hpd_gpio))
3976f920c07SWyon Bi 		return;
3986f920c07SWyon Bi 
3996f920c07SWyon Bi 	analogix_dp_clear_hotplug_interrupts(dp);
4006f920c07SWyon Bi 
40152db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_3);
4026f920c07SWyon Bi 	reg &= ~(F_HPD | HPD_CTRL);
40352db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_3, reg);
4046f920c07SWyon Bi }
4056f920c07SWyon Bi 
analogix_dp_force_hpd(struct analogix_dp_device * dp)4066f920c07SWyon Bi void analogix_dp_force_hpd(struct analogix_dp_device *dp)
4076f920c07SWyon Bi {
4086f920c07SWyon Bi 	u32 reg;
4096f920c07SWyon Bi 
41052db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_3);
41152db8715SWyon Bi 	reg |= (F_HPD | HPD_CTRL);
41252db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_3, reg);
4136f920c07SWyon Bi }
4146f920c07SWyon Bi 
analogix_dp_get_irq_type(struct analogix_dp_device * dp)4156f920c07SWyon Bi enum dp_irq_type analogix_dp_get_irq_type(struct analogix_dp_device *dp)
4166f920c07SWyon Bi {
4176f920c07SWyon Bi 	u32 reg;
4186f920c07SWyon Bi 
4196f920c07SWyon Bi 	if (dm_gpio_is_valid(&dp->hpd_gpio)) {
4206f920c07SWyon Bi 		reg = dm_gpio_get_value(&dp->hpd_gpio);
4216f920c07SWyon Bi 		if (reg)
4226f920c07SWyon Bi 			return DP_IRQ_TYPE_HP_CABLE_IN;
4236f920c07SWyon Bi 		else
4246f920c07SWyon Bi 			return DP_IRQ_TYPE_HP_CABLE_OUT;
4256f920c07SWyon Bi 	} else {
4266f920c07SWyon Bi 		/* Parse hotplug interrupt status register */
42752db8715SWyon Bi 		reg = analogix_dp_read(dp, ANALOGIX_DP_COMMON_INT_STA_4);
4286f920c07SWyon Bi 
4296f920c07SWyon Bi 		if (reg & PLUG)
4306f920c07SWyon Bi 			return DP_IRQ_TYPE_HP_CABLE_IN;
4316f920c07SWyon Bi 
4326f920c07SWyon Bi 		if (reg & HPD_LOST)
4336f920c07SWyon Bi 			return DP_IRQ_TYPE_HP_CABLE_OUT;
4346f920c07SWyon Bi 
4356f920c07SWyon Bi 		if (reg & HOTPLUG_CHG)
4366f920c07SWyon Bi 			return DP_IRQ_TYPE_HP_CHANGE;
4376f920c07SWyon Bi 
4386f920c07SWyon Bi 		return DP_IRQ_TYPE_UNKNOWN;
4396f920c07SWyon Bi 	}
4406f920c07SWyon Bi }
4416f920c07SWyon Bi 
analogix_dp_reset_aux(struct analogix_dp_device * dp)4426f920c07SWyon Bi void analogix_dp_reset_aux(struct analogix_dp_device *dp)
4436f920c07SWyon Bi {
4446f920c07SWyon Bi 	u32 reg;
4456f920c07SWyon Bi 
4466f920c07SWyon Bi 	/* Disable AUX channel module */
44752db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_FUNC_EN_2);
4486f920c07SWyon Bi 	reg |= AUX_FUNC_EN_N;
44952db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_FUNC_EN_2, reg);
4506f920c07SWyon Bi }
4516f920c07SWyon Bi 
analogix_dp_init_aux(struct analogix_dp_device * dp)4526f920c07SWyon Bi void analogix_dp_init_aux(struct analogix_dp_device *dp)
4536f920c07SWyon Bi {
4546f920c07SWyon Bi 	u32 reg;
4556f920c07SWyon Bi 
4566f920c07SWyon Bi 	/* Clear inerrupts related to AUX channel */
4576f920c07SWyon Bi 	reg = RPLY_RECEIV | AUX_ERR;
45852db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_INT_STA, reg);
4596f920c07SWyon Bi 
4606f920c07SWyon Bi 	analogix_dp_reset_aux(dp);
4616f920c07SWyon Bi 
4626f920c07SWyon Bi 	/* Disable AUX transaction H/W retry */
4636f920c07SWyon Bi 	if (dp->plat_data.dev_type == ROCKCHIP_DP)
4646f920c07SWyon Bi 		reg = AUX_BIT_PERIOD_EXPECTED_DELAY(0) |
4656f920c07SWyon Bi 		      AUX_HW_RETRY_COUNT_SEL(3) |
4666f920c07SWyon Bi 		      AUX_HW_RETRY_INTERVAL_600_MICROSECONDS;
4676f920c07SWyon Bi 	else
4686f920c07SWyon Bi 		reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) |
4696f920c07SWyon Bi 		      AUX_HW_RETRY_COUNT_SEL(0) |
4706f920c07SWyon Bi 		      AUX_HW_RETRY_INTERVAL_600_MICROSECONDS;
47152db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_AUX_HW_RETRY_CTL, reg);
4726f920c07SWyon Bi 
4736f920c07SWyon Bi 	/* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */
4746f920c07SWyon Bi 	reg = DEFER_CTRL_EN | DEFER_COUNT(1);
47552db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_AUX_CH_DEFER_CTL, reg);
4766f920c07SWyon Bi 
4776f920c07SWyon Bi 	/* Enable AUX channel module */
47852db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_FUNC_EN_2);
4796f920c07SWyon Bi 	reg &= ~AUX_FUNC_EN_N;
48052db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_FUNC_EN_2, reg);
4816f920c07SWyon Bi }
4826f920c07SWyon Bi 
analogix_dp_detect(struct analogix_dp_device * dp)483d90a0d9fSWyon Bi int analogix_dp_detect(struct analogix_dp_device *dp)
4846f920c07SWyon Bi {
4856f920c07SWyon Bi 	u32 reg;
4866f920c07SWyon Bi 
487d90a0d9fSWyon Bi 	if (dm_gpio_is_valid(&dp->hpd_gpio))
488d90a0d9fSWyon Bi 		return dm_gpio_get_value(&dp->hpd_gpio);
489d90a0d9fSWyon Bi 
490d90a0d9fSWyon Bi 	if (dp->force_hpd)
491d90a0d9fSWyon Bi 		analogix_dp_force_hpd(dp);
492d90a0d9fSWyon Bi 
49352db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_3);
4946f920c07SWyon Bi 	if (reg & HPD_STATUS)
495d90a0d9fSWyon Bi 		return 1;
4966f920c07SWyon Bi 
497d90a0d9fSWyon Bi 	return 0;
4986f920c07SWyon Bi }
4996f920c07SWyon Bi 
analogix_dp_enable_sw_function(struct analogix_dp_device * dp)5006f920c07SWyon Bi void analogix_dp_enable_sw_function(struct analogix_dp_device *dp)
5016f920c07SWyon Bi {
5026f920c07SWyon Bi 	u32 reg;
5036f920c07SWyon Bi 
50452db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_FUNC_EN_1);
5056f920c07SWyon Bi 	reg &= ~SW_FUNC_EN_N;
50652db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_FUNC_EN_1, reg);
5076f920c07SWyon Bi }
5086f920c07SWyon Bi 
analogix_dp_get_plug_in_status(struct analogix_dp_device * dp)509d3e70420SWyon Bi int analogix_dp_get_plug_in_status(struct analogix_dp_device *dp)
510d3e70420SWyon Bi {
511d3e70420SWyon Bi 	u32 reg;
512d3e70420SWyon Bi 
513d3e70420SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_3);
514d3e70420SWyon Bi 	if (reg & HPD_STATUS)
515d3e70420SWyon Bi 		return 0;
516d3e70420SWyon Bi 
517d3e70420SWyon Bi 	return -EINVAL;
518d3e70420SWyon Bi }
519d3e70420SWyon Bi 
analogix_dp_start_aux_transaction(struct analogix_dp_device * dp)5206f920c07SWyon Bi int analogix_dp_start_aux_transaction(struct analogix_dp_device *dp)
5216f920c07SWyon Bi {
5226f920c07SWyon Bi 	int reg;
5236f920c07SWyon Bi 	int retval = 0;
5246f920c07SWyon Bi 	int timeout_loop = 0;
5256f920c07SWyon Bi 
5266f920c07SWyon Bi 	/* Enable AUX CH operation */
52752db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_AUX_CH_CTL_2);
5286f920c07SWyon Bi 	reg |= AUX_EN;
52952db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_AUX_CH_CTL_2, reg);
5306f920c07SWyon Bi 
5316f920c07SWyon Bi 	/* Is AUX CH command reply received? */
53252db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_INT_STA);
5336f920c07SWyon Bi 	while (!(reg & RPLY_RECEIV)) {
5346f920c07SWyon Bi 		timeout_loop++;
5356f920c07SWyon Bi 		if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
5366f920c07SWyon Bi 			dev_err(dp->dev, "AUX CH command reply failed!\n");
5376f920c07SWyon Bi 			return -ETIMEDOUT;
5386f920c07SWyon Bi 		}
5396f920c07SWyon Bi 
54052db8715SWyon Bi 		reg = analogix_dp_read(dp, ANALOGIX_DP_INT_STA);
5416f920c07SWyon Bi 		udelay(11);
5426f920c07SWyon Bi 	}
5436f920c07SWyon Bi 
5446f920c07SWyon Bi 	/* Clear interrupt source for AUX CH command reply */
54552db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_INT_STA, reg);
5466f920c07SWyon Bi 
5476f920c07SWyon Bi 	/* Clear interrupt source for AUX CH access error */
54852db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_INT_STA);
5496f920c07SWyon Bi 	if (reg & AUX_ERR) {
55052db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_INT_STA, AUX_ERR);
5516f920c07SWyon Bi 		return -EREMOTEIO;
5526f920c07SWyon Bi 	}
5536f920c07SWyon Bi 
5546f920c07SWyon Bi 	/* Check AUX CH error access status */
55552db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_AUX_CH_STA);
5566f920c07SWyon Bi 	if ((reg & AUX_STATUS_MASK) != 0) {
5576f920c07SWyon Bi 		dev_err(dp->dev,
5586f920c07SWyon Bi 			"AUX CH error happens: %d\n", reg & AUX_STATUS_MASK);
5596f920c07SWyon Bi 		return -EREMOTEIO;
5606f920c07SWyon Bi 	}
5616f920c07SWyon Bi 
5626f920c07SWyon Bi 	return retval;
5636f920c07SWyon Bi }
5646f920c07SWyon Bi 
analogix_dp_select_i2c_device(struct analogix_dp_device * dp,unsigned int device_addr,unsigned int reg_addr)5656f920c07SWyon Bi int analogix_dp_select_i2c_device(struct analogix_dp_device *dp,
5666f920c07SWyon Bi 				  unsigned int device_addr,
5676f920c07SWyon Bi 				  unsigned int reg_addr)
5686f920c07SWyon Bi {
5696f920c07SWyon Bi 	u32 reg;
5706f920c07SWyon Bi 	int retval;
5716f920c07SWyon Bi 
5726f920c07SWyon Bi 	/* Set EDID device address */
5736f920c07SWyon Bi 	reg = device_addr;
57452db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_AUX_ADDR_7_0, reg);
57552db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_AUX_ADDR_15_8, 0x0);
57652db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_AUX_ADDR_19_16, 0x0);
5776f920c07SWyon Bi 
5786f920c07SWyon Bi 	/* Set offset from base address of EDID device */
57952db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_BUF_DATA_0, reg_addr);
5806f920c07SWyon Bi 
5816f920c07SWyon Bi 	/*
5826f920c07SWyon Bi 	 * Set I2C transaction and write address
5836f920c07SWyon Bi 	 * If bit 3 is 1, DisplayPort transaction.
5846f920c07SWyon Bi 	 * If Bit 3 is 0, I2C transaction.
5856f920c07SWyon Bi 	 */
5866f920c07SWyon Bi 	reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT |
5876f920c07SWyon Bi 		AUX_TX_COMM_WRITE;
58852db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_AUX_CH_CTL_1, reg);
5896f920c07SWyon Bi 
5906f920c07SWyon Bi 	/* Start AUX transaction */
5916f920c07SWyon Bi 	retval = analogix_dp_start_aux_transaction(dp);
5926f920c07SWyon Bi 	if (retval < 0)
5936f920c07SWyon Bi 		return retval;
5946f920c07SWyon Bi 
5956f920c07SWyon Bi 	return 0;
5966f920c07SWyon Bi }
5976f920c07SWyon Bi 
analogix_dp_read_byte_from_i2c(struct analogix_dp_device * dp,unsigned int device_addr,unsigned int reg_addr,unsigned int * data)5986f920c07SWyon Bi int analogix_dp_read_byte_from_i2c(struct analogix_dp_device *dp,
5996f920c07SWyon Bi 				   unsigned int device_addr,
6006f920c07SWyon Bi 				   unsigned int reg_addr,
6016f920c07SWyon Bi 				   unsigned int *data)
6026f920c07SWyon Bi {
6036f920c07SWyon Bi 	u32 reg;
6046f920c07SWyon Bi 	int i;
6056f920c07SWyon Bi 	int retval;
6066f920c07SWyon Bi 
6076f920c07SWyon Bi 	for (i = 0; i < 3; i++) {
6086f920c07SWyon Bi 		/* Clear AUX CH data buffer */
6096f920c07SWyon Bi 		reg = BUF_CLR;
61052db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_BUFFER_DATA_CTL, reg);
6116f920c07SWyon Bi 
6126f920c07SWyon Bi 		/* Select EDID device */
6136f920c07SWyon Bi 		retval = analogix_dp_select_i2c_device(dp, device_addr,
6146f920c07SWyon Bi 						       reg_addr);
6156f920c07SWyon Bi 		if (retval != 0)
6166f920c07SWyon Bi 			continue;
6176f920c07SWyon Bi 
6186f920c07SWyon Bi 		/*
6196f920c07SWyon Bi 		 * Set I2C transaction and read data
6206f920c07SWyon Bi 		 * If bit 3 is 1, DisplayPort transaction.
6216f920c07SWyon Bi 		 * If Bit 3 is 0, I2C transaction.
6226f920c07SWyon Bi 		 */
6236f920c07SWyon Bi 		reg = AUX_TX_COMM_I2C_TRANSACTION |
6246f920c07SWyon Bi 			AUX_TX_COMM_READ;
62552db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_AUX_CH_CTL_1, reg);
6266f920c07SWyon Bi 
6276f920c07SWyon Bi 		/* Start AUX transaction */
6286f920c07SWyon Bi 		retval = analogix_dp_start_aux_transaction(dp);
6296f920c07SWyon Bi 		if (retval == 0)
6306f920c07SWyon Bi 			break;
6316f920c07SWyon Bi 	}
6326f920c07SWyon Bi 
6336f920c07SWyon Bi 	/* Read data */
6346f920c07SWyon Bi 	if (retval == 0)
63552db8715SWyon Bi 		*data = analogix_dp_read(dp, ANALOGIX_DP_BUF_DATA_0);
6366f920c07SWyon Bi 
6376f920c07SWyon Bi 	return retval;
6386f920c07SWyon Bi }
6396f920c07SWyon Bi 
analogix_dp_read_bytes_from_i2c(struct analogix_dp_device * dp,unsigned int device_addr,unsigned int reg_addr,unsigned int count,unsigned char edid[])6406f920c07SWyon Bi int analogix_dp_read_bytes_from_i2c(struct analogix_dp_device *dp,
6416f920c07SWyon Bi 				    unsigned int device_addr,
6426f920c07SWyon Bi 				    unsigned int reg_addr,
6436f920c07SWyon Bi 				    unsigned int count,
6446f920c07SWyon Bi 				    unsigned char edid[])
6456f920c07SWyon Bi {
6466f920c07SWyon Bi 	u32 reg;
6476f920c07SWyon Bi 	unsigned int i, j;
6486f920c07SWyon Bi 	unsigned int cur_data_idx;
6496f920c07SWyon Bi 	unsigned int defer = 0;
6506f920c07SWyon Bi 	int retval = 0;
6516f920c07SWyon Bi 
6526f920c07SWyon Bi 	for (i = 0; i < count; i += 16) {
6536f920c07SWyon Bi 		for (j = 0; j < 3; j++) {
6546f920c07SWyon Bi 			/* Clear AUX CH data buffer */
6556f920c07SWyon Bi 			reg = BUF_CLR;
65652db8715SWyon Bi 			analogix_dp_write(dp, ANALOGIX_DP_BUFFER_DATA_CTL, reg);
6576f920c07SWyon Bi 
6586f920c07SWyon Bi 			/* Set normal AUX CH command */
65952db8715SWyon Bi 			reg = analogix_dp_read(dp, ANALOGIX_DP_AUX_CH_CTL_2);
6606f920c07SWyon Bi 			reg &= ~ADDR_ONLY;
66152db8715SWyon Bi 			analogix_dp_write(dp, ANALOGIX_DP_AUX_CH_CTL_2, reg);
6626f920c07SWyon Bi 
6636f920c07SWyon Bi 			/*
6646f920c07SWyon Bi 			 * If Rx sends defer, Tx sends only reads
6656f920c07SWyon Bi 			 * request without sending address
6666f920c07SWyon Bi 			 */
6676f920c07SWyon Bi 			if (!defer)
6686f920c07SWyon Bi 				retval = analogix_dp_select_i2c_device(dp,
6696f920c07SWyon Bi 						device_addr, reg_addr + i);
6706f920c07SWyon Bi 			else
6716f920c07SWyon Bi 				defer = 0;
6726f920c07SWyon Bi 
6736f920c07SWyon Bi 			if (retval == 0) {
6746f920c07SWyon Bi 				/*
6756f920c07SWyon Bi 				 * Set I2C transaction and write data
6766f920c07SWyon Bi 				 * If bit 3 is 1, DisplayPort transaction.
6776f920c07SWyon Bi 				 * If Bit 3 is 0, I2C transaction.
6786f920c07SWyon Bi 				 */
6796f920c07SWyon Bi 				reg = AUX_LENGTH(16) |
6806f920c07SWyon Bi 					AUX_TX_COMM_I2C_TRANSACTION |
6816f920c07SWyon Bi 					AUX_TX_COMM_READ;
68252db8715SWyon Bi 				analogix_dp_write(dp, ANALOGIX_DP_AUX_CH_CTL_1,
68352db8715SWyon Bi 						  reg);
6846f920c07SWyon Bi 
6856f920c07SWyon Bi 				/* Start AUX transaction */
6866f920c07SWyon Bi 				retval = analogix_dp_start_aux_transaction(dp);
6876f920c07SWyon Bi 				if (retval == 0)
6886f920c07SWyon Bi 					break;
6896f920c07SWyon Bi 			}
6906f920c07SWyon Bi 			/* Check if Rx sends defer */
69152db8715SWyon Bi 			reg = analogix_dp_read(dp, ANALOGIX_DP_AUX_RX_COMM);
6926f920c07SWyon Bi 			if (reg == AUX_RX_COMM_AUX_DEFER ||
6936f920c07SWyon Bi 			    reg == AUX_RX_COMM_I2C_DEFER) {
6946f920c07SWyon Bi 				dev_dbg(dp->dev, "Defer: %d\n\n", reg);
6956f920c07SWyon Bi 				defer = 1;
6966f920c07SWyon Bi 			}
6976f920c07SWyon Bi 		}
6986f920c07SWyon Bi 
6996f920c07SWyon Bi 		for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) {
70052db8715SWyon Bi 			reg = analogix_dp_read(dp, ANALOGIX_DP_BUF_DATA_0
7016f920c07SWyon Bi 						 + 4 * cur_data_idx);
7026f920c07SWyon Bi 			edid[i + cur_data_idx] = (unsigned char)reg;
7036f920c07SWyon Bi 		}
7046f920c07SWyon Bi 	}
7056f920c07SWyon Bi 
7066f920c07SWyon Bi 	return retval;
7076f920c07SWyon Bi }
7086f920c07SWyon Bi 
analogix_dp_ssc_supported(struct analogix_dp_device * dp)709699c29a5SWyon Bi bool analogix_dp_ssc_supported(struct analogix_dp_device *dp)
710699c29a5SWyon Bi {
711699c29a5SWyon Bi 	/* Check if SSC is supported by both sides */
712699c29a5SWyon Bi 	return dp->plat_data.ssc && dp->link_train.ssc;
713699c29a5SWyon Bi }
714699c29a5SWyon Bi 
analogix_dp_set_link_bandwidth(struct analogix_dp_device * dp,u32 bwtype)7156f920c07SWyon Bi void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype)
7166f920c07SWyon Bi {
717699c29a5SWyon Bi 	union phy_configure_opts phy_cfg;
7187adc0066SWyon Bi 	u32 status;
719a6285d17SWyon Bi 	int ret;
7206f920c07SWyon Bi 
7217adc0066SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_LINK_BW_SET, bwtype);
722a6285d17SWyon Bi 
723699c29a5SWyon Bi 	phy_cfg.dp.lanes = dp->link_train.lane_count;
724699c29a5SWyon Bi 	phy_cfg.dp.link_rate =
725699c29a5SWyon Bi 		drm_dp_bw_code_to_link_rate(dp->link_train.link_rate) / 100;
726699c29a5SWyon Bi 	phy_cfg.dp.ssc = analogix_dp_ssc_supported(dp);
727699c29a5SWyon Bi 	phy_cfg.dp.set_lanes = false;
728699c29a5SWyon Bi 	phy_cfg.dp.set_rate = true;
729699c29a5SWyon Bi 	phy_cfg.dp.set_voltages = false;
730699c29a5SWyon Bi 	ret = generic_phy_configure(&dp->phy, &phy_cfg);
731699c29a5SWyon Bi 	if (ret) {
732699c29a5SWyon Bi 		dev_err(dp->dev, "%s: phy_configure() failed: %d\n",
733699c29a5SWyon Bi 			__func__, ret);
734699c29a5SWyon Bi 		return;
735699c29a5SWyon Bi 	}
736699c29a5SWyon Bi 
737a6285d17SWyon Bi 	ret = readx_poll_timeout(analogix_dp_get_pll_lock_status, dp, status,
738a6285d17SWyon Bi 				 status != PLL_UNLOCKED,
739a6285d17SWyon Bi 				 120 * DP_TIMEOUT_LOOP_COUNT);
740a6285d17SWyon Bi 	if (ret) {
741a6285d17SWyon Bi 		dev_err(dp->dev, "Wait for pll lock failed %d\n", ret);
742a6285d17SWyon Bi 		return;
743a6285d17SWyon Bi 	}
7446f920c07SWyon Bi }
7456f920c07SWyon Bi 
analogix_dp_get_link_bandwidth(struct analogix_dp_device * dp,u32 * bwtype)7466f920c07SWyon Bi void analogix_dp_get_link_bandwidth(struct analogix_dp_device *dp, u32 *bwtype)
7476f920c07SWyon Bi {
7486f920c07SWyon Bi 	u32 reg;
7496f920c07SWyon Bi 
75052db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_LINK_BW_SET);
7516f920c07SWyon Bi 	*bwtype = reg;
7526f920c07SWyon Bi }
7536f920c07SWyon Bi 
analogix_dp_set_lane_count(struct analogix_dp_device * dp,u32 count)7546f920c07SWyon Bi void analogix_dp_set_lane_count(struct analogix_dp_device *dp, u32 count)
7556f920c07SWyon Bi {
756699c29a5SWyon Bi 	union phy_configure_opts phy_cfg;
7576f920c07SWyon Bi 	u32 reg;
758699c29a5SWyon Bi 	int ret;
7596f920c07SWyon Bi 
7606f920c07SWyon Bi 	reg = count;
76152db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_LANE_COUNT_SET, reg);
762699c29a5SWyon Bi 
763699c29a5SWyon Bi 	phy_cfg.dp.lanes = dp->link_train.lane_count;
764699c29a5SWyon Bi 	phy_cfg.dp.set_lanes = true;
765699c29a5SWyon Bi 	phy_cfg.dp.set_rate = false;
766699c29a5SWyon Bi 	phy_cfg.dp.set_voltages = false;
767699c29a5SWyon Bi 	ret = generic_phy_configure(&dp->phy, &phy_cfg);
768699c29a5SWyon Bi 	if (ret) {
769699c29a5SWyon Bi 		dev_err(dp->dev, "%s: phy_configure() failed: %d\n",
770699c29a5SWyon Bi 			__func__, ret);
771699c29a5SWyon Bi 		return;
772699c29a5SWyon Bi 	}
7736f920c07SWyon Bi }
7746f920c07SWyon Bi 
analogix_dp_get_lane_count(struct analogix_dp_device * dp,u32 * count)7756f920c07SWyon Bi void analogix_dp_get_lane_count(struct analogix_dp_device *dp, u32 *count)
7766f920c07SWyon Bi {
7776f920c07SWyon Bi 	u32 reg;
7786f920c07SWyon Bi 
77952db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_LANE_COUNT_SET);
7806f920c07SWyon Bi 	*count = reg;
7816f920c07SWyon Bi }
7826f920c07SWyon Bi 
analogix_dp_set_lane_link_training(struct analogix_dp_device * dp)783253c2dc8SWyon Bi void analogix_dp_set_lane_link_training(struct analogix_dp_device *dp)
784253c2dc8SWyon Bi {
785699c29a5SWyon Bi 	union phy_configure_opts phy_cfg;
786253c2dc8SWyon Bi 	u8 lane;
787699c29a5SWyon Bi 	int ret;
788253c2dc8SWyon Bi 
789699c29a5SWyon Bi 	for (lane = 0; lane < dp->link_train.lane_count; lane++) {
790699c29a5SWyon Bi 		u8 training_lane = dp->link_train.training_lane[lane];
791699c29a5SWyon Bi 		u8 vs, pe;
792699c29a5SWyon Bi 
793253c2dc8SWyon Bi 		analogix_dp_write(dp,
794253c2dc8SWyon Bi 				  ANALOGIX_DP_LN0_LINK_TRAINING_CTL + 4 * lane,
795253c2dc8SWyon Bi 				  dp->link_train.training_lane[lane]);
796699c29a5SWyon Bi 
797d63e2d24SWyon Bi 		vs = (training_lane & DP_TRAIN_VOLTAGE_SWING_MASK) >>
798d63e2d24SWyon Bi 		     DP_TRAIN_VOLTAGE_SWING_SHIFT;
799d63e2d24SWyon Bi 		pe = (training_lane & DP_TRAIN_PRE_EMPHASIS_MASK) >>
800d63e2d24SWyon Bi 		     DP_TRAIN_PRE_EMPHASIS_SHIFT;
801699c29a5SWyon Bi 		phy_cfg.dp.voltage[lane] = vs;
802699c29a5SWyon Bi 		phy_cfg.dp.pre[lane] = pe;
803699c29a5SWyon Bi 	}
804699c29a5SWyon Bi 
805699c29a5SWyon Bi 	phy_cfg.dp.lanes = dp->link_train.lane_count;
8067adc0066SWyon Bi 	phy_cfg.dp.link_rate =
8077adc0066SWyon Bi 		drm_dp_bw_code_to_link_rate(dp->link_train.link_rate) / 100;
808699c29a5SWyon Bi 	phy_cfg.dp.set_lanes = false;
809699c29a5SWyon Bi 	phy_cfg.dp.set_rate = false;
810699c29a5SWyon Bi 	phy_cfg.dp.set_voltages = true;
811699c29a5SWyon Bi 	ret = generic_phy_configure(&dp->phy, &phy_cfg);
812699c29a5SWyon Bi 	if (ret) {
813699c29a5SWyon Bi 		dev_err(dp->dev, "%s: phy_configure() failed: %d\n",
814699c29a5SWyon Bi 			__func__, ret);
815699c29a5SWyon Bi 		return;
816699c29a5SWyon Bi 	}
817253c2dc8SWyon Bi }
818253c2dc8SWyon Bi 
analogix_dp_get_lane_link_training(struct analogix_dp_device * dp,u8 lane)819253c2dc8SWyon Bi u32 analogix_dp_get_lane_link_training(struct analogix_dp_device *dp, u8 lane)
820253c2dc8SWyon Bi {
821253c2dc8SWyon Bi 	return analogix_dp_read(dp,
822253c2dc8SWyon Bi 				ANALOGIX_DP_LN0_LINK_TRAINING_CTL + 4 * lane);
823253c2dc8SWyon Bi }
824253c2dc8SWyon Bi 
analogix_dp_enable_enhanced_mode(struct analogix_dp_device * dp,bool enable)8256f920c07SWyon Bi void analogix_dp_enable_enhanced_mode(struct analogix_dp_device *dp,
8266f920c07SWyon Bi 				      bool enable)
8276f920c07SWyon Bi {
8286f920c07SWyon Bi 	u32 reg;
8296f920c07SWyon Bi 
8306f920c07SWyon Bi 	if (enable) {
83152db8715SWyon Bi 		reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_4);
8326f920c07SWyon Bi 		reg |= ENHANCED;
83352db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_4, reg);
8346f920c07SWyon Bi 	} else {
83552db8715SWyon Bi 		reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_4);
8366f920c07SWyon Bi 		reg &= ~ENHANCED;
83752db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_4, reg);
8386f920c07SWyon Bi 	}
8396f920c07SWyon Bi }
8406f920c07SWyon Bi 
analogix_dp_set_training_pattern(struct analogix_dp_device * dp,enum pattern_set pattern)8416f920c07SWyon Bi void analogix_dp_set_training_pattern(struct analogix_dp_device *dp,
8426f920c07SWyon Bi 				      enum pattern_set pattern)
8436f920c07SWyon Bi {
8446f920c07SWyon Bi 	u32 reg;
8456f920c07SWyon Bi 
8466f920c07SWyon Bi 	switch (pattern) {
8476f920c07SWyon Bi 	case PRBS7:
8486f920c07SWyon Bi 		reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7;
84952db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_TRAINING_PTN_SET, reg);
8506f920c07SWyon Bi 		break;
8516f920c07SWyon Bi 	case D10_2:
8526f920c07SWyon Bi 		reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2;
85352db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_TRAINING_PTN_SET, reg);
8546f920c07SWyon Bi 		break;
8556f920c07SWyon Bi 	case TRAINING_PTN1:
8566f920c07SWyon Bi 		reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1;
85752db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_TRAINING_PTN_SET, reg);
8586f920c07SWyon Bi 		break;
8596f920c07SWyon Bi 	case TRAINING_PTN2:
8606f920c07SWyon Bi 		reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2;
86152db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_TRAINING_PTN_SET, reg);
8626f920c07SWyon Bi 		break;
8637adc0066SWyon Bi 	case TRAINING_PTN3:
8647adc0066SWyon Bi 		reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN3;
8657adc0066SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_TRAINING_PTN_SET, reg);
8667adc0066SWyon Bi 		break;
8676f920c07SWyon Bi 	case DP_NONE:
8686f920c07SWyon Bi 		reg = SCRAMBLING_ENABLE |
8696f920c07SWyon Bi 			LINK_QUAL_PATTERN_SET_DISABLE |
8706f920c07SWyon Bi 			SW_TRAINING_PATTERN_SET_NORMAL;
87152db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_TRAINING_PTN_SET, reg);
8726f920c07SWyon Bi 		break;
8736f920c07SWyon Bi 	default:
8746f920c07SWyon Bi 		break;
8756f920c07SWyon Bi 	}
8766f920c07SWyon Bi }
8776f920c07SWyon Bi 
analogix_dp_reset_macro(struct analogix_dp_device * dp)8786f920c07SWyon Bi void analogix_dp_reset_macro(struct analogix_dp_device *dp)
8796f920c07SWyon Bi {
8806f920c07SWyon Bi 	u32 reg;
8816f920c07SWyon Bi 
88252db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_PHY_TEST);
8836f920c07SWyon Bi 	reg |= MACRO_RST;
88452db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_PHY_TEST, reg);
8856f920c07SWyon Bi 
8866f920c07SWyon Bi 	/* 10 us is the minimum reset time. */
8876f920c07SWyon Bi 	udelay(20);
8886f920c07SWyon Bi 
8896f920c07SWyon Bi 	reg &= ~MACRO_RST;
89052db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_PHY_TEST, reg);
8916f920c07SWyon Bi }
8926f920c07SWyon Bi 
analogix_dp_init_video(struct analogix_dp_device * dp)8936f920c07SWyon Bi void analogix_dp_init_video(struct analogix_dp_device *dp)
8946f920c07SWyon Bi {
8956f920c07SWyon Bi 	u32 reg;
8966f920c07SWyon Bi 
8976f920c07SWyon Bi 	reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG;
89852db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_STA_1, reg);
8996f920c07SWyon Bi 
9006f920c07SWyon Bi 	reg = 0x0;
90152db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_1, reg);
9026f920c07SWyon Bi 
9036f920c07SWyon Bi 	reg = CHA_CRI(4) | CHA_CTRL;
90452db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_2, reg);
9056f920c07SWyon Bi 
906ae5256b5SWyon Bi 	if (dp->video_info.force_stream_valid) {
907e9cac7f1SWyon Bi 		reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_3);
908e9cac7f1SWyon Bi 		reg |= VALID_CTRL | F_VALID;
90952db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_3, reg);
910ae5256b5SWyon Bi 	}
9116f920c07SWyon Bi 
9126f920c07SWyon Bi 	reg = VID_HRES_TH(2) | VID_VRES_TH(0);
91352db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_VIDEO_CTL_8, reg);
9146f920c07SWyon Bi }
9156f920c07SWyon Bi 
analogix_dp_set_video_color_format(struct analogix_dp_device * dp)9166f920c07SWyon Bi void analogix_dp_set_video_color_format(struct analogix_dp_device *dp)
9176f920c07SWyon Bi {
9186f920c07SWyon Bi 	u32 reg;
9196f920c07SWyon Bi 
9206f920c07SWyon Bi 	/* Configure the input color depth, color space, dynamic range */
9216f920c07SWyon Bi 	reg = (dp->video_info.dynamic_range << IN_D_RANGE_SHIFT) |
9226f920c07SWyon Bi 		(dp->video_info.color_depth << IN_BPC_SHIFT) |
9236f920c07SWyon Bi 		(dp->video_info.color_space << IN_COLOR_F_SHIFT);
92452db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_VIDEO_CTL_2, reg);
9256f920c07SWyon Bi 
9266f920c07SWyon Bi 	/* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */
92752db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_VIDEO_CTL_3);
9286f920c07SWyon Bi 	reg &= ~IN_YC_COEFFI_MASK;
9296f920c07SWyon Bi 	if (dp->video_info.ycbcr_coeff)
9306f920c07SWyon Bi 		reg |= IN_YC_COEFFI_ITU709;
9316f920c07SWyon Bi 	else
9326f920c07SWyon Bi 		reg |= IN_YC_COEFFI_ITU601;
93352db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_VIDEO_CTL_3, reg);
9346f920c07SWyon Bi }
9356f920c07SWyon Bi 
analogix_dp_is_slave_video_stream_clock_on(struct analogix_dp_device * dp)9366f920c07SWyon Bi int analogix_dp_is_slave_video_stream_clock_on(struct analogix_dp_device *dp)
9376f920c07SWyon Bi {
9386f920c07SWyon Bi 	u32 reg;
9396f920c07SWyon Bi 
94052db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_1);
94152db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_1, reg);
9426f920c07SWyon Bi 
94352db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_1);
9446f920c07SWyon Bi 
9456f920c07SWyon Bi 	if (!(reg & DET_STA))
9466f920c07SWyon Bi 		return -EINVAL;
9476f920c07SWyon Bi 
94852db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_2);
94952db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_2, reg);
9506f920c07SWyon Bi 
95152db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_2);
9526f920c07SWyon Bi 
9536f920c07SWyon Bi 	if (reg & CHA_STA)
9546f920c07SWyon Bi 		return -EINVAL;
9556f920c07SWyon Bi 
9566f920c07SWyon Bi 	return 0;
9576f920c07SWyon Bi }
9586f920c07SWyon Bi 
analogix_dp_set_video_cr_mn(struct analogix_dp_device * dp,enum clock_recovery_m_value_type type,u32 m_value,u32 n_value)9596f920c07SWyon Bi void analogix_dp_set_video_cr_mn(struct analogix_dp_device *dp,
9606f920c07SWyon Bi 				 enum clock_recovery_m_value_type type,
9616f920c07SWyon Bi 				 u32 m_value, u32 n_value)
9626f920c07SWyon Bi {
9636f920c07SWyon Bi 	u32 reg;
9646f920c07SWyon Bi 
9656f920c07SWyon Bi 	if (type == REGISTER_M) {
96652db8715SWyon Bi 		reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_4);
9676f920c07SWyon Bi 		reg |= FIX_M_VID;
96852db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_4, reg);
9696f920c07SWyon Bi 		reg = m_value & 0xff;
97052db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_M_VID_0, reg);
9716f920c07SWyon Bi 		reg = (m_value >> 8) & 0xff;
97252db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_M_VID_1, reg);
9736f920c07SWyon Bi 		reg = (m_value >> 16) & 0xff;
97452db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_M_VID_2, reg);
9756f920c07SWyon Bi 
9766f920c07SWyon Bi 		reg = n_value & 0xff;
97752db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_N_VID_0, reg);
9786f920c07SWyon Bi 		reg = (n_value >> 8) & 0xff;
97952db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_N_VID_1, reg);
9806f920c07SWyon Bi 		reg = (n_value >> 16) & 0xff;
98152db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_N_VID_2, reg);
9826f920c07SWyon Bi 	} else  {
98352db8715SWyon Bi 		reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_4);
9846f920c07SWyon Bi 		reg &= ~FIX_M_VID;
98552db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_4, reg);
9866f920c07SWyon Bi 
98752db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_N_VID_0, 0x00);
98852db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_N_VID_1, 0x80);
98952db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_N_VID_2, 0x00);
9906f920c07SWyon Bi 	}
9916f920c07SWyon Bi }
9926f920c07SWyon Bi 
analogix_dp_set_video_timing_mode(struct analogix_dp_device * dp,u32 type)9936f920c07SWyon Bi void analogix_dp_set_video_timing_mode(struct analogix_dp_device *dp, u32 type)
9946f920c07SWyon Bi {
9956f920c07SWyon Bi 	u32 reg;
9966f920c07SWyon Bi 
9976f920c07SWyon Bi 	if (type == VIDEO_TIMING_FROM_CAPTURE) {
99852db8715SWyon Bi 		reg = analogix_dp_read(dp, ANALOGIX_DP_VIDEO_CTL_10);
9996f920c07SWyon Bi 		reg &= ~FORMAT_SEL;
100052db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_VIDEO_CTL_10, reg);
10016f920c07SWyon Bi 	} else {
100252db8715SWyon Bi 		reg = analogix_dp_read(dp, ANALOGIX_DP_VIDEO_CTL_10);
10036f920c07SWyon Bi 		reg |= FORMAT_SEL;
100452db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_VIDEO_CTL_10, reg);
10056f920c07SWyon Bi 	}
10066f920c07SWyon Bi }
10076f920c07SWyon Bi 
analogix_dp_enable_video_master(struct analogix_dp_device * dp,bool enable)10086f920c07SWyon Bi void analogix_dp_enable_video_master(struct analogix_dp_device *dp, bool enable)
10096f920c07SWyon Bi {
10106f920c07SWyon Bi 	u32 reg;
10116f920c07SWyon Bi 
10126f920c07SWyon Bi 	if (enable) {
101352db8715SWyon Bi 		reg = analogix_dp_read(dp, ANALOGIX_DP_SOC_GENERAL_CTL);
10146f920c07SWyon Bi 		reg &= ~VIDEO_MODE_MASK;
10156f920c07SWyon Bi 		reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE;
101652db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_SOC_GENERAL_CTL, reg);
10176f920c07SWyon Bi 	} else {
101852db8715SWyon Bi 		reg = analogix_dp_read(dp, ANALOGIX_DP_SOC_GENERAL_CTL);
10196f920c07SWyon Bi 		reg &= ~VIDEO_MODE_MASK;
10206f920c07SWyon Bi 		reg |= VIDEO_MODE_SLAVE_MODE;
102152db8715SWyon Bi 		analogix_dp_write(dp, ANALOGIX_DP_SOC_GENERAL_CTL, reg);
10226f920c07SWyon Bi 	}
10236f920c07SWyon Bi }
10246f920c07SWyon Bi 
analogix_dp_start_video(struct analogix_dp_device * dp)10256f920c07SWyon Bi void analogix_dp_start_video(struct analogix_dp_device *dp)
10266f920c07SWyon Bi {
10276f920c07SWyon Bi 	u32 reg;
10286f920c07SWyon Bi 
102952db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_VIDEO_CTL_1);
10306f920c07SWyon Bi 	reg |= VIDEO_EN;
103152db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_VIDEO_CTL_1, reg);
10326f920c07SWyon Bi }
10336f920c07SWyon Bi 
analogix_dp_is_video_stream_on(struct analogix_dp_device * dp)10346f920c07SWyon Bi int analogix_dp_is_video_stream_on(struct analogix_dp_device *dp)
10356f920c07SWyon Bi {
10366f920c07SWyon Bi 	u32 reg;
10376f920c07SWyon Bi 
103852db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_3);
103952db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_3, reg);
10406f920c07SWyon Bi 
104152db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_3);
10426f920c07SWyon Bi 	if (!(reg & STRM_VALID))
10436f920c07SWyon Bi 		return -EINVAL;
10446f920c07SWyon Bi 
10456f920c07SWyon Bi 	return 0;
10466f920c07SWyon Bi }
10476f920c07SWyon Bi 
analogix_dp_config_video_slave_mode(struct analogix_dp_device * dp)10486f920c07SWyon Bi void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp)
10496f920c07SWyon Bi {
10506f920c07SWyon Bi 	u32 reg;
10516f920c07SWyon Bi 
105252db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_FUNC_EN_1);
10536f920c07SWyon Bi 	reg &= ~(MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N);
10546f920c07SWyon Bi 	reg |= MASTER_VID_FUNC_EN_N;
105552db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_FUNC_EN_1, reg);
10566f920c07SWyon Bi 
105752db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_VIDEO_CTL_10);
10586f920c07SWyon Bi 	reg &= ~INTERACE_SCAN_CFG;
10596f920c07SWyon Bi 	reg |= (dp->video_info.interlaced << 2);
106052db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_VIDEO_CTL_10, reg);
10616f920c07SWyon Bi 
106252db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_VIDEO_CTL_10);
10636f920c07SWyon Bi 	reg &= ~VSYNC_POLARITY_CFG;
10646f920c07SWyon Bi 	reg |= (dp->video_info.v_sync_polarity << 1);
106552db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_VIDEO_CTL_10, reg);
10666f920c07SWyon Bi 
106752db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_VIDEO_CTL_10);
10686f920c07SWyon Bi 	reg &= ~HSYNC_POLARITY_CFG;
10696f920c07SWyon Bi 	reg |= (dp->video_info.h_sync_polarity << 0);
107052db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_VIDEO_CTL_10, reg);
10716f920c07SWyon Bi 
10726f920c07SWyon Bi 	reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE;
107352db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_SOC_GENERAL_CTL, reg);
10746f920c07SWyon Bi }
10756f920c07SWyon Bi 
analogix_dp_enable_scrambling(struct analogix_dp_device * dp)10766f920c07SWyon Bi void analogix_dp_enable_scrambling(struct analogix_dp_device *dp)
10776f920c07SWyon Bi {
10786f920c07SWyon Bi 	u32 reg;
10796f920c07SWyon Bi 
108052db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_TRAINING_PTN_SET);
10816f920c07SWyon Bi 	reg &= ~SCRAMBLING_DISABLE;
108252db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_TRAINING_PTN_SET, reg);
10836f920c07SWyon Bi }
10846f920c07SWyon Bi 
analogix_dp_disable_scrambling(struct analogix_dp_device * dp)10856f920c07SWyon Bi void analogix_dp_disable_scrambling(struct analogix_dp_device *dp)
10866f920c07SWyon Bi {
10876f920c07SWyon Bi 	u32 reg;
10886f920c07SWyon Bi 
108952db8715SWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_TRAINING_PTN_SET);
10906f920c07SWyon Bi 	reg |= SCRAMBLING_DISABLE;
109152db8715SWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_TRAINING_PTN_SET, reg);
10926f920c07SWyon Bi }
10930b8cf90dSWyon Bi 
analogix_dp_set_video_format(struct analogix_dp_device * dp,const struct drm_display_mode * mode)10940b8cf90dSWyon Bi void analogix_dp_set_video_format(struct analogix_dp_device *dp,
10950b8cf90dSWyon Bi 				  const struct drm_display_mode *mode)
10960b8cf90dSWyon Bi {
10970b8cf90dSWyon Bi 	unsigned int hsw, hfp, hbp, vsw, vfp, vbp;
10980b8cf90dSWyon Bi 
1099e9cac7f1SWyon Bi 	dp->video_info.interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
1100c7dcfb21SWyon Bi 
1101c7dcfb21SWyon Bi 	if (dp->plat_data.subdev_type == RK3588_EDP) {
1102c7dcfb21SWyon Bi 		dp->video_info.v_sync_polarity = true;
1103c7dcfb21SWyon Bi 		dp->video_info.h_sync_polarity = true;
1104c7dcfb21SWyon Bi 	} else {
1105e9cac7f1SWyon Bi 		dp->video_info.v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
1106e9cac7f1SWyon Bi 		dp->video_info.h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
1107c7dcfb21SWyon Bi 	}
1108e9cac7f1SWyon Bi 
11090b8cf90dSWyon Bi 	hsw = mode->hsync_end - mode->hsync_start;
11100b8cf90dSWyon Bi 	hfp = mode->hsync_start - mode->hdisplay;
11110b8cf90dSWyon Bi 	hbp = mode->htotal - mode->hsync_end;
11120b8cf90dSWyon Bi 	vsw = mode->vsync_end - mode->vsync_start;
11130b8cf90dSWyon Bi 	vfp = mode->vsync_start - mode->vdisplay;
11140b8cf90dSWyon Bi 	vbp = mode->vtotal - mode->vsync_end;
11150b8cf90dSWyon Bi 
11160b8cf90dSWyon Bi 	/* Set Video Format Parameters */
11170b8cf90dSWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_TOTAL_LINE_CFG_L,
11180b8cf90dSWyon Bi 			  TOTAL_LINE_CFG_L(mode->vtotal));
11190b8cf90dSWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_TOTAL_LINE_CFG_H,
11200b8cf90dSWyon Bi 			  TOTAL_LINE_CFG_H(mode->vtotal >> 8));
11210b8cf90dSWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_ACTIVE_LINE_CFG_L,
11220b8cf90dSWyon Bi 			  ACTIVE_LINE_CFG_L(mode->vdisplay));
11230b8cf90dSWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_ACTIVE_LINE_CFG_H,
11240b8cf90dSWyon Bi 			  ACTIVE_LINE_CFG_H(mode->vdisplay >> 8));
11250b8cf90dSWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_V_F_PORCH_CFG,
11260b8cf90dSWyon Bi 			  V_F_PORCH_CFG(vfp));
11270b8cf90dSWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_V_SYNC_WIDTH_CFG,
11280b8cf90dSWyon Bi 			  V_SYNC_WIDTH_CFG(vsw));
11290b8cf90dSWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_V_B_PORCH_CFG,
11300b8cf90dSWyon Bi 			  V_B_PORCH_CFG(vbp));
11310b8cf90dSWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_TOTAL_PIXEL_CFG_L,
11320b8cf90dSWyon Bi 			  TOTAL_PIXEL_CFG_L(mode->htotal));
11330b8cf90dSWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_TOTAL_PIXEL_CFG_H,
11340b8cf90dSWyon Bi 			  TOTAL_PIXEL_CFG_H(mode->htotal >> 8));
11350b8cf90dSWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_ACTIVE_PIXEL_CFG_L,
11360b8cf90dSWyon Bi 			  ACTIVE_PIXEL_CFG_L(mode->hdisplay));
11370b8cf90dSWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_ACTIVE_PIXEL_CFG_H,
11380b8cf90dSWyon Bi 			  ACTIVE_PIXEL_CFG_H(mode->hdisplay >> 8));
11390b8cf90dSWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_H_F_PORCH_CFG_L,
11400b8cf90dSWyon Bi 			  H_F_PORCH_CFG_L(hfp));
11410b8cf90dSWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_H_F_PORCH_CFG_H,
11420b8cf90dSWyon Bi 			  H_F_PORCH_CFG_H(hfp >> 8));
11430b8cf90dSWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_H_SYNC_CFG_L,
11440b8cf90dSWyon Bi 			  H_SYNC_CFG_L(hsw));
11450b8cf90dSWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_H_SYNC_CFG_H,
11460b8cf90dSWyon Bi 			  H_SYNC_CFG_H(hsw >> 8));
11470b8cf90dSWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_H_B_PORCH_CFG_L,
11480b8cf90dSWyon Bi 			  H_B_PORCH_CFG_L(hbp));
11490b8cf90dSWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_H_B_PORCH_CFG_H,
11500b8cf90dSWyon Bi 			  H_B_PORCH_CFG_H(hbp >> 8));
11510b8cf90dSWyon Bi }
11520b8cf90dSWyon Bi 
analogix_dp_video_bist_enable(struct analogix_dp_device * dp)11530b8cf90dSWyon Bi void analogix_dp_video_bist_enable(struct analogix_dp_device *dp)
11540b8cf90dSWyon Bi {
11550b8cf90dSWyon Bi 	u32 reg;
11560b8cf90dSWyon Bi 
11570b8cf90dSWyon Bi 	/* Enable Video BIST */
11580b8cf90dSWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_VIDEO_CTL_4, BIST_EN);
11590b8cf90dSWyon Bi 
11600b8cf90dSWyon Bi 	/*
11610b8cf90dSWyon Bi 	 * Note that if BIST_EN is set to 1, F_SEL must be cleared to 0
11620b8cf90dSWyon Bi 	 * although video format information comes from registers set by user.
11630b8cf90dSWyon Bi 	 */
11640b8cf90dSWyon Bi 	reg = analogix_dp_read(dp, ANALOGIX_DP_VIDEO_CTL_10);
11650b8cf90dSWyon Bi 	reg &= ~FORMAT_SEL;
11660b8cf90dSWyon Bi 	analogix_dp_write(dp, ANALOGIX_DP_VIDEO_CTL_10, reg);
11670b8cf90dSWyon Bi }
116858df3976SDamon Ding 
116958df3976SDamon Ding enum {
117058df3976SDamon Ding 	AUX_STATUS_OK,
117158df3976SDamon Ding 	AUX_STATUS_NACK_ERROR,
117258df3976SDamon Ding 	AUX_STATUS_TIMEOUT_ERROR,
117358df3976SDamon Ding 	AUX_STATUS_UNKNOWN_ERROR,
117458df3976SDamon Ding 	AUX_STATUS_MUCH_DEFER_ERROR,
117558df3976SDamon Ding 	AUX_STATUS_TX_SHORT_ERROR,
117658df3976SDamon Ding 	AUX_STATUS_RX_SHORT_ERROR,
117758df3976SDamon Ding 	AUX_STATUS_NACK_WITHOUT_M_ERROR,
117858df3976SDamon Ding 	AUX_STATUS_I2C_NACK_ERROR
117958df3976SDamon Ding };
118058df3976SDamon Ding 
analogix_dp_aux_transfer(struct drm_dp_aux * aux,struct drm_dp_aux_msg * msg)118158df3976SDamon Ding ssize_t analogix_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
118258df3976SDamon Ding {
118358df3976SDamon Ding 	struct analogix_dp_device *dp = dev_get_priv(aux->dev);
118458df3976SDamon Ding 	u32 reg;
118558df3976SDamon Ding 	u8 *buffer = msg->buffer;
118658df3976SDamon Ding 	unsigned int i;
118758df3976SDamon Ding 	int num_transferred = 0;
118858df3976SDamon Ding 	int ret;
118958df3976SDamon Ding 
119058df3976SDamon Ding 	/* Buffer size of AUX CH is 16 bytes */
119158df3976SDamon Ding 	if (WARN_ON(msg->size > 16))
119258df3976SDamon Ding 		return -E2BIG;
119358df3976SDamon Ding 
119458df3976SDamon Ding 	/* Clear AUX CH data buffer */
119558df3976SDamon Ding 	reg = BUF_CLR;
119658df3976SDamon Ding 	analogix_dp_write(dp, ANALOGIX_DP_BUFFER_DATA_CTL, reg);
119758df3976SDamon Ding 
119858df3976SDamon Ding 	switch (msg->request & ~DP_AUX_I2C_MOT) {
119958df3976SDamon Ding 	case DP_AUX_I2C_WRITE:
120058df3976SDamon Ding 		reg = AUX_TX_COMM_WRITE | AUX_TX_COMM_I2C_TRANSACTION;
120158df3976SDamon Ding 		if (msg->request & DP_AUX_I2C_MOT)
120258df3976SDamon Ding 			reg |= AUX_TX_COMM_MOT;
120358df3976SDamon Ding 		break;
120458df3976SDamon Ding 
120558df3976SDamon Ding 	case DP_AUX_I2C_READ:
120658df3976SDamon Ding 		reg = AUX_TX_COMM_READ | AUX_TX_COMM_I2C_TRANSACTION;
120758df3976SDamon Ding 		if (msg->request & DP_AUX_I2C_MOT)
120858df3976SDamon Ding 			reg |= AUX_TX_COMM_MOT;
120958df3976SDamon Ding 		break;
121058df3976SDamon Ding 
121158df3976SDamon Ding 	case DP_AUX_NATIVE_WRITE:
121258df3976SDamon Ding 		reg = AUX_TX_COMM_WRITE | AUX_TX_COMM_DP_TRANSACTION;
121358df3976SDamon Ding 		break;
121458df3976SDamon Ding 
121558df3976SDamon Ding 	case DP_AUX_NATIVE_READ:
121658df3976SDamon Ding 		reg = AUX_TX_COMM_READ | AUX_TX_COMM_DP_TRANSACTION;
121758df3976SDamon Ding 		break;
121858df3976SDamon Ding 
121958df3976SDamon Ding 	default:
122058df3976SDamon Ding 		return -EINVAL;
122158df3976SDamon Ding 	}
122258df3976SDamon Ding 
122358df3976SDamon Ding 	reg |= AUX_LENGTH(msg->size);
122458df3976SDamon Ding 	analogix_dp_write(dp, ANALOGIX_DP_AUX_CH_CTL_1, reg);
122558df3976SDamon Ding 
122658df3976SDamon Ding 	/* Select DPCD device address */
122758df3976SDamon Ding 	reg = AUX_ADDR_7_0(msg->address);
122858df3976SDamon Ding 	analogix_dp_write(dp, ANALOGIX_DP_AUX_ADDR_7_0, reg);
122958df3976SDamon Ding 	reg = AUX_ADDR_15_8(msg->address);
123058df3976SDamon Ding 	analogix_dp_write(dp, ANALOGIX_DP_AUX_ADDR_15_8, reg);
123158df3976SDamon Ding 	reg = AUX_ADDR_19_16(msg->address);
123258df3976SDamon Ding 	analogix_dp_write(dp, ANALOGIX_DP_AUX_ADDR_19_16, reg);
123358df3976SDamon Ding 
123458df3976SDamon Ding 	if (!(msg->request & DP_AUX_I2C_READ)) {
123558df3976SDamon Ding 		for (i = 0; i < msg->size; i++) {
123658df3976SDamon Ding 			reg = buffer[i];
123758df3976SDamon Ding 			analogix_dp_write(dp, ANALOGIX_DP_BUF_DATA_0 + 4 * i,
123858df3976SDamon Ding 					  reg);
123958df3976SDamon Ding 			num_transferred++;
124058df3976SDamon Ding 		}
124158df3976SDamon Ding 	}
124258df3976SDamon Ding 
124358df3976SDamon Ding 	/* Enable AUX CH operation */
124458df3976SDamon Ding 	reg = AUX_EN;
124558df3976SDamon Ding 
124658df3976SDamon Ding 	/* Zero-sized messages specify address-only transactions. */
124758df3976SDamon Ding 	if (msg->size < 1)
124858df3976SDamon Ding 		reg |= ADDR_ONLY;
124958df3976SDamon Ding 
125058df3976SDamon Ding 	analogix_dp_write(dp, ANALOGIX_DP_AUX_CH_CTL_2, reg);
125158df3976SDamon Ding 
125258df3976SDamon Ding 	ret = readx_poll_timeout(readl, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2,
125358df3976SDamon Ding 				 reg, !(reg & AUX_EN), 500 * 1000);
125458df3976SDamon Ding 	if (ret) {
125558df3976SDamon Ding 		dev_err(dp->dev, "AUX CH enable timeout!\n");
125658df3976SDamon Ding 		goto aux_error;
125758df3976SDamon Ding 	}
125858df3976SDamon Ding 
125958df3976SDamon Ding 	/* TODO: Wait for an interrupt instead of looping? */
126058df3976SDamon Ding 	/* Is AUX CH command reply received? */
126158df3976SDamon Ding 	ret = readx_poll_timeout(readl, dp->reg_base + ANALOGIX_DP_INT_STA,
126258df3976SDamon Ding 				 reg, reg & RPLY_RECEIV, 20 * 1000);
126358df3976SDamon Ding 	if (ret) {
126458df3976SDamon Ding 		dev_err(dp->dev, "AUX CH cmd reply timeout!\n");
126558df3976SDamon Ding 		goto aux_error;
126658df3976SDamon Ding 	}
126758df3976SDamon Ding 
126858df3976SDamon Ding 	/* Clear interrupt source for AUX CH command reply */
126958df3976SDamon Ding 	analogix_dp_write(dp, ANALOGIX_DP_INT_STA, RPLY_RECEIV);
127058df3976SDamon Ding 
127158df3976SDamon Ding 	reg = analogix_dp_read(dp, ANALOGIX_DP_AUX_CH_STA);
127258df3976SDamon Ding 	if ((reg & AUX_STATUS_MASK) == AUX_STATUS_TIMEOUT_ERROR)
127358df3976SDamon Ding 		return -ETIMEDOUT;
127458df3976SDamon Ding 
127558df3976SDamon Ding 	if (msg->request & DP_AUX_I2C_READ) {
127658df3976SDamon Ding 		size_t buf_data_count;
127758df3976SDamon Ding 
127858df3976SDamon Ding 		reg = analogix_dp_read(dp, ANALOGIX_DP_BUFFER_DATA_CTL);
127958df3976SDamon Ding 		buf_data_count = BUF_DATA_COUNT(reg);
128058df3976SDamon Ding 
128158df3976SDamon Ding 		if (buf_data_count != msg->size)
128258df3976SDamon Ding 			return -EBUSY;
128358df3976SDamon Ding 
128458df3976SDamon Ding 		for (i = 0; i < msg->size; i++) {
128558df3976SDamon Ding 			reg = analogix_dp_read(dp, ANALOGIX_DP_BUF_DATA_0 +
128658df3976SDamon Ding 					       4 * i);
128758df3976SDamon Ding 			buffer[i] = (unsigned char)reg;
128858df3976SDamon Ding 			num_transferred++;
128958df3976SDamon Ding 		}
129058df3976SDamon Ding 	}
129158df3976SDamon Ding 
129258df3976SDamon Ding 	/* Check if Rx sends defer */
129358df3976SDamon Ding 	reg = analogix_dp_read(dp, ANALOGIX_DP_AUX_RX_COMM);
129458df3976SDamon Ding 	if (reg == AUX_RX_COMM_AUX_DEFER)
129558df3976SDamon Ding 		msg->reply = DP_AUX_NATIVE_REPLY_DEFER;
129658df3976SDamon Ding 	else if (reg == AUX_RX_COMM_I2C_DEFER)
129758df3976SDamon Ding 		msg->reply = DP_AUX_I2C_REPLY_DEFER;
129858df3976SDamon Ding 	else if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_WRITE ||
129958df3976SDamon Ding 		 (msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_READ)
130058df3976SDamon Ding 		msg->reply = DP_AUX_I2C_REPLY_ACK;
130158df3976SDamon Ding 	else if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_WRITE ||
130258df3976SDamon Ding 		 (msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_READ)
130358df3976SDamon Ding 		msg->reply = DP_AUX_NATIVE_REPLY_ACK;
130458df3976SDamon Ding 
130558df3976SDamon Ding 	return (num_transferred == msg->size) ? num_transferred : -EBUSY;
130658df3976SDamon Ding 
130758df3976SDamon Ding aux_error:
130858df3976SDamon Ding 	/* if aux err happen, reset aux */
130958df3976SDamon Ding 	analogix_dp_init_aux(dp);
131058df3976SDamon Ding 
131158df3976SDamon Ding 	return -EREMOTEIO;
131258df3976SDamon Ding }
1313*fc275078SDamon Ding 
analogix_dp_enable_assr_mode(struct analogix_dp_device * dp,bool enable)1314*fc275078SDamon Ding void analogix_dp_enable_assr_mode(struct analogix_dp_device *dp, bool enable)
1315*fc275078SDamon Ding {
1316*fc275078SDamon Ding 	u32 reg;
1317*fc275078SDamon Ding 
1318*fc275078SDamon Ding 	if (enable) {
1319*fc275078SDamon Ding 		reg = analogix_dp_read(dp, ANALOGIX_DP_LINK_POLICY);
1320*fc275078SDamon Ding 		reg |= ALTERNATE_SR_ENABLE;
1321*fc275078SDamon Ding 		analogix_dp_write(dp, ANALOGIX_DP_LINK_POLICY, reg);
1322*fc275078SDamon Ding 	} else {
1323*fc275078SDamon Ding 		reg = analogix_dp_read(dp, ANALOGIX_DP_LINK_POLICY);
1324*fc275078SDamon Ding 		reg &= ~ALTERNATE_SR_ENABLE;
1325*fc275078SDamon Ding 		analogix_dp_write(dp, ANALOGIX_DP_LINK_POLICY, reg);
1326*fc275078SDamon Ding 	}
1327*fc275078SDamon Ding }
1328*fc275078SDamon Ding 
analogix_dp_get_assr_mode(struct analogix_dp_device * dp)1329*fc275078SDamon Ding bool analogix_dp_get_assr_mode(struct analogix_dp_device *dp)
1330*fc275078SDamon Ding {
1331*fc275078SDamon Ding 	u32 reg;
1332*fc275078SDamon Ding 
1333*fc275078SDamon Ding 	reg = analogix_dp_read(dp, ANALOGIX_DP_LINK_POLICY);
1334*fc275078SDamon Ding 
1335*fc275078SDamon Ding 	return !!(reg & ALTERNATE_SR_ENABLE);
1336*fc275078SDamon Ding }
1337