xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include <linux/clk.h>
7*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
8*4882a593Smuzhiyun #include <linux/mfd/syscon.h>
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <linux/of_gpio.h>
11*4882a593Smuzhiyun #include <linux/platform_device.h>
12*4882a593Smuzhiyun #include <linux/phy/phy.h>
13*4882a593Smuzhiyun #include <linux/regmap.h>
14*4882a593Smuzhiyun #include <linux/pm_runtime.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include <drm/drm_of.h>
17*4882a593Smuzhiyun #include <drm/drm_crtc_helper.h>
18*4882a593Smuzhiyun #include <drm/drm_dsc.h>
19*4882a593Smuzhiyun #include <drm/drm_edid.h>
20*4882a593Smuzhiyun #include <drm/bridge/dw_hdmi.h>
21*4882a593Smuzhiyun #include <drm/drm_edid.h>
22*4882a593Smuzhiyun #include <drm/drm_of.h>
23*4882a593Smuzhiyun #include <drm/drm_probe_helper.h>
24*4882a593Smuzhiyun #include <drm/drm_simple_kms_helper.h>
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #include <uapi/linux/videodev2.h>
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #include "rockchip_drm_drv.h"
29*4882a593Smuzhiyun #include "rockchip_drm_vop.h"
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #define HIWORD_UPDATE(val, mask)	(val | (mask) << 16)
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #define RK3228_GRF_SOC_CON2		0x0408
34*4882a593Smuzhiyun #define RK3228_HDMI_SDAIN_MSK		BIT(14)
35*4882a593Smuzhiyun #define RK3228_HDMI_SCLIN_MSK		BIT(13)
36*4882a593Smuzhiyun #define RK3228_GRF_SOC_CON6		0x0418
37*4882a593Smuzhiyun #define RK3228_HDMI_HPD_VSEL		BIT(6)
38*4882a593Smuzhiyun #define RK3228_HDMI_SDA_VSEL		BIT(5)
39*4882a593Smuzhiyun #define RK3228_HDMI_SCL_VSEL		BIT(4)
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun #define RK3288_GRF_SOC_CON6		0x025C
42*4882a593Smuzhiyun #define RK3288_HDMI_LCDC_SEL		BIT(4)
43*4882a593Smuzhiyun #define RK3288_GRF_SOC_CON16		0x03a8
44*4882a593Smuzhiyun #define RK3288_HDMI_LCDC0_YUV420	BIT(2)
45*4882a593Smuzhiyun #define RK3288_HDMI_LCDC1_YUV420	BIT(3)
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun #define RK3328_GRF_SOC_CON2		0x0408
48*4882a593Smuzhiyun #define RK3328_HDMI_SDAIN_MSK		BIT(11)
49*4882a593Smuzhiyun #define RK3328_HDMI_SCLIN_MSK		BIT(10)
50*4882a593Smuzhiyun #define RK3328_HDMI_HPD_IOE		BIT(2)
51*4882a593Smuzhiyun #define RK3328_GRF_SOC_CON3		0x040c
52*4882a593Smuzhiyun /* need to be unset if hdmi or i2c should control voltage */
53*4882a593Smuzhiyun #define RK3328_HDMI_SDA5V_GRF		BIT(15)
54*4882a593Smuzhiyun #define RK3328_HDMI_SCL5V_GRF		BIT(14)
55*4882a593Smuzhiyun #define RK3328_HDMI_HPD5V_GRF		BIT(13)
56*4882a593Smuzhiyun #define RK3328_HDMI_CEC5V_GRF		BIT(12)
57*4882a593Smuzhiyun #define RK3328_GRF_SOC_CON4		0x0410
58*4882a593Smuzhiyun #define RK3328_HDMI_HPD_SARADC		BIT(13)
59*4882a593Smuzhiyun #define RK3328_HDMI_CEC_5V		BIT(11)
60*4882a593Smuzhiyun #define RK3328_HDMI_SDA_5V		BIT(10)
61*4882a593Smuzhiyun #define RK3328_HDMI_SCL_5V		BIT(9)
62*4882a593Smuzhiyun #define RK3328_HDMI_HPD_5V		BIT(8)
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun #define RK3399_GRF_SOC_CON20		0x6250
65*4882a593Smuzhiyun #define RK3399_HDMI_LCDC_SEL		BIT(6)
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun #define RK3528_VO_GRF_HDMI_MASK		0x60014
68*4882a593Smuzhiyun #define RK3528_HDMI_SNKDET_SEL		BIT(6)
69*4882a593Smuzhiyun #define RK3528_HDMI_SNKDET		BIT(5)
70*4882a593Smuzhiyun #define RK3528_HDMI_CECIN_MSK		BIT(2)
71*4882a593Smuzhiyun #define RK3528_HDMI_SDAIN_MSK		BIT(1)
72*4882a593Smuzhiyun #define RK3528_HDMI_SCLIN_MSK		BIT(0)
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun #define RK3528PMU_GRF_SOC_CON6		0x70018
75*4882a593Smuzhiyun #define RK3528_HDMI_SDA5V_GRF		BIT(6)
76*4882a593Smuzhiyun #define RK3528_HDMI_SCL5V_GRF		BIT(5)
77*4882a593Smuzhiyun #define RK3528_HDMI_CEC5V_GRF		BIT(4)
78*4882a593Smuzhiyun #define RK3528_HDMI_HPD5V_GRF		BIT(3)
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun #define RK3528_GPIO_SWPORT_DR_L		0x0000
81*4882a593Smuzhiyun #define RK3528_GPIO0_A2_DR		BIT(2)
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun #define RK3568_GRF_VO_CON1		0x0364
84*4882a593Smuzhiyun #define RK3568_HDMI_SDAIN_MSK		BIT(15)
85*4882a593Smuzhiyun #define RK3568_HDMI_SCLIN_MSK		BIT(14)
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun #define RK3588_GRF_SOC_CON2		0x0308
88*4882a593Smuzhiyun #define RK3588_HDMI1_HPD_INT_MSK	BIT(15)
89*4882a593Smuzhiyun #define RK3588_HDMI1_HPD_INT_CLR	BIT(14)
90*4882a593Smuzhiyun #define RK3588_HDMI0_HPD_INT_MSK	BIT(13)
91*4882a593Smuzhiyun #define RK3588_HDMI0_HPD_INT_CLR	BIT(12)
92*4882a593Smuzhiyun #define RK3588_GRF_SOC_CON7		0x031c
93*4882a593Smuzhiyun #define RK3588_SET_HPD_PATH_MASK	(0x3 << 12)
94*4882a593Smuzhiyun #define RK3588_GRF_SOC_STATUS1		0x0384
95*4882a593Smuzhiyun #define RK3588_HDMI0_LOW_MORETHAN100MS	BIT(20)
96*4882a593Smuzhiyun #define RK3588_HDMI0_HPD_PORT_LEVEL	BIT(19)
97*4882a593Smuzhiyun #define RK3588_HDMI0_IHPD_PORT		BIT(18)
98*4882a593Smuzhiyun #define RK3588_HDMI0_OHPD_INT		BIT(17)
99*4882a593Smuzhiyun #define RK3588_HDMI0_LEVEL_INT		BIT(16)
100*4882a593Smuzhiyun #define RK3588_HDMI0_INTR_CHANGE_CNT	(0x7 << 13)
101*4882a593Smuzhiyun #define RK3588_HDMI1_LOW_MORETHAN100MS	BIT(28)
102*4882a593Smuzhiyun #define RK3588_HDMI1_HPD_PORT_LEVEL	BIT(27)
103*4882a593Smuzhiyun #define RK3588_HDMI1_IHPD_PORT		BIT(26)
104*4882a593Smuzhiyun #define RK3588_HDMI1_OHPD_INT		BIT(25)
105*4882a593Smuzhiyun #define RK3588_HDMI1_LEVEL_INT		BIT(24)
106*4882a593Smuzhiyun #define RK3588_HDMI1_INTR_CHANGE_CNT	(0x7 << 21)
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun #define RK3588_GRF_VO1_CON3		0x000c
109*4882a593Smuzhiyun #define RK3588_COLOR_FORMAT_MASK	0xf
110*4882a593Smuzhiyun #define RK3588_RGB			0
111*4882a593Smuzhiyun #define RK3588_YUV422			0x1
112*4882a593Smuzhiyun #define RK3588_YUV444			0x2
113*4882a593Smuzhiyun #define RK3588_YUV420			0x3
114*4882a593Smuzhiyun #define RK3588_COMPRESSED_DATA		0xb
115*4882a593Smuzhiyun #define RK3588_COLOR_DEPTH_MASK		(0xf << 4)
116*4882a593Smuzhiyun #define RK3588_8BPC			0
117*4882a593Smuzhiyun #define RK3588_10BPC			(0x6 << 4)
118*4882a593Smuzhiyun #define RK3588_CECIN_MASK		BIT(8)
119*4882a593Smuzhiyun #define RK3588_SCLIN_MASK		BIT(9)
120*4882a593Smuzhiyun #define RK3588_SDAIN_MASK		BIT(10)
121*4882a593Smuzhiyun #define RK3588_MODE_MASK		BIT(11)
122*4882a593Smuzhiyun #define RK3588_COMPRESS_MODE_MASK	BIT(12)
123*4882a593Smuzhiyun #define RK3588_I2S_SEL_MASK		BIT(13)
124*4882a593Smuzhiyun #define RK3588_SPDIF_SEL_MASK		BIT(14)
125*4882a593Smuzhiyun #define RK3588_GRF_VO1_CON4		0x0010
126*4882a593Smuzhiyun #define RK3588_HDMI21_MASK		BIT(0)
127*4882a593Smuzhiyun #define RK3588_GRF_VO1_CON9		0x0024
128*4882a593Smuzhiyun #define RK3588_HDMI0_GRANT_SEL		BIT(10)
129*4882a593Smuzhiyun #define RK3588_HDMI0_GRANT_SW		BIT(11)
130*4882a593Smuzhiyun #define RK3588_HDMI1_GRANT_SEL		BIT(12)
131*4882a593Smuzhiyun #define RK3588_HDMI1_GRANT_SW		BIT(13)
132*4882a593Smuzhiyun #define RK3588_GRF_VO1_CON6		0x0018
133*4882a593Smuzhiyun #define RK3588_GRF_VO1_CON7		0x001c
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun #define COLOR_DEPTH_10BIT		BIT(31)
136*4882a593Smuzhiyun #define HDMI_FRL_MODE			BIT(30)
137*4882a593Smuzhiyun #define HDMI_EARC_MODE			BIT(29)
138*4882a593Smuzhiyun #define DATA_RATE_MASK			0xFFFFFFF
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun #define HDMI20_MAX_RATE			600000
141*4882a593Smuzhiyun #define HDMI_8K60_RATE			2376000
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun /**
144*4882a593Smuzhiyun  * struct rockchip_hdmi_chip_data - splite the grf setting of kind of chips
145*4882a593Smuzhiyun  * @lcdsel_grf_reg: grf register offset of lcdc select
146*4882a593Smuzhiyun  * @ddc_en_reg: grf register offset of hdmi ddc enable
147*4882a593Smuzhiyun  * @lcdsel_big: reg value of selecting vop big for HDMI
148*4882a593Smuzhiyun  * @lcdsel_lit: reg value of selecting vop little for HDMI
149*4882a593Smuzhiyun  */
150*4882a593Smuzhiyun struct rockchip_hdmi_chip_data {
151*4882a593Smuzhiyun 	int	lcdsel_grf_reg;
152*4882a593Smuzhiyun 	int	ddc_en_reg;
153*4882a593Smuzhiyun 	u32	lcdsel_big;
154*4882a593Smuzhiyun 	u32	lcdsel_lit;
155*4882a593Smuzhiyun 	bool	split_mode;
156*4882a593Smuzhiyun };
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun enum hdmi_frl_rate_per_lane {
159*4882a593Smuzhiyun 	FRL_12G_PER_LANE = 12,
160*4882a593Smuzhiyun 	FRL_10G_PER_LANE = 10,
161*4882a593Smuzhiyun 	FRL_8G_PER_LANE = 8,
162*4882a593Smuzhiyun 	FRL_6G_PER_LANE = 6,
163*4882a593Smuzhiyun 	FRL_3G_PER_LANE = 3,
164*4882a593Smuzhiyun };
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun struct rockchip_hdmi {
167*4882a593Smuzhiyun 	struct device *dev;
168*4882a593Smuzhiyun 	struct regmap *regmap;
169*4882a593Smuzhiyun 	struct regmap *vo1_regmap;
170*4882a593Smuzhiyun 	void __iomem *gpio_base;
171*4882a593Smuzhiyun 	struct drm_encoder encoder;
172*4882a593Smuzhiyun 	struct drm_device *drm_dev;
173*4882a593Smuzhiyun 	const struct rockchip_hdmi_chip_data *chip_data;
174*4882a593Smuzhiyun 	struct dw_hdmi_plat_data *plat_data;
175*4882a593Smuzhiyun 	struct clk *aud_clk;
176*4882a593Smuzhiyun 	struct clk *phyref_clk;
177*4882a593Smuzhiyun 	struct clk *grf_clk;
178*4882a593Smuzhiyun 	struct clk *hclk_vio;
179*4882a593Smuzhiyun 	struct clk *hclk_vo1;
180*4882a593Smuzhiyun 	struct clk *hclk_vop;
181*4882a593Smuzhiyun 	struct clk *hpd_clk;
182*4882a593Smuzhiyun 	struct clk *pclk;
183*4882a593Smuzhiyun 	struct clk *earc_clk;
184*4882a593Smuzhiyun 	struct clk *hdmitx_ref;
185*4882a593Smuzhiyun 	struct clk *link_clk;
186*4882a593Smuzhiyun 	struct dw_hdmi *hdmi;
187*4882a593Smuzhiyun 	struct dw_hdmi_qp *hdmi_qp;
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	struct phy *phy;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	u32 max_tmdsclk;
192*4882a593Smuzhiyun 	bool unsupported_yuv_input;
193*4882a593Smuzhiyun 	bool unsupported_deep_color;
194*4882a593Smuzhiyun 	bool skip_check_420_mode;
195*4882a593Smuzhiyun 	bool hpd_wake_en;
196*4882a593Smuzhiyun 	u8 force_output;
197*4882a593Smuzhiyun 	u8 id;
198*4882a593Smuzhiyun 	bool hpd_stat;
199*4882a593Smuzhiyun 	bool is_hdmi_qp;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	unsigned long bus_format;
202*4882a593Smuzhiyun 	unsigned long output_bus_format;
203*4882a593Smuzhiyun 	unsigned long enc_out_encoding;
204*4882a593Smuzhiyun 	unsigned long prev_bus_format;
205*4882a593Smuzhiyun 	int color_changed;
206*4882a593Smuzhiyun 	int hpd_irq;
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	struct drm_property *color_depth_property;
209*4882a593Smuzhiyun 	struct drm_property *hdmi_output_property;
210*4882a593Smuzhiyun 	struct drm_property *colordepth_capacity;
211*4882a593Smuzhiyun 	struct drm_property *outputmode_capacity;
212*4882a593Smuzhiyun 	struct drm_property *quant_range;
213*4882a593Smuzhiyun 	struct drm_property *hdr_panel_metadata_property;
214*4882a593Smuzhiyun 	struct drm_property *next_hdr_sink_data_property;
215*4882a593Smuzhiyun 	struct drm_property *output_hdmi_dvi;
216*4882a593Smuzhiyun 	struct drm_property *output_type_capacity;
217*4882a593Smuzhiyun 	struct drm_property *allm_capacity;
218*4882a593Smuzhiyun 	struct drm_property *allm_enable;
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	struct drm_property_blob *hdr_panel_blob_ptr;
221*4882a593Smuzhiyun 	struct drm_property_blob *next_hdr_data_ptr;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	unsigned int colordepth;
224*4882a593Smuzhiyun 	unsigned int colorimetry;
225*4882a593Smuzhiyun 	unsigned int hdmi_quant_range;
226*4882a593Smuzhiyun 	unsigned int phy_bus_width;
227*4882a593Smuzhiyun 	unsigned int enable_allm;
228*4882a593Smuzhiyun 	enum rk_if_color_format hdmi_output;
229*4882a593Smuzhiyun 	struct rockchip_drm_sub_dev sub_dev;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	u8 max_frl_rate_per_lane;
232*4882a593Smuzhiyun 	u8 max_lanes;
233*4882a593Smuzhiyun 	u8 add_func;
234*4882a593Smuzhiyun 	u8 edid_colorimetry;
235*4882a593Smuzhiyun 	struct rockchip_drm_dsc_cap dsc_cap;
236*4882a593Smuzhiyun 	struct next_hdr_sink_data next_hdr_data;
237*4882a593Smuzhiyun 	struct dw_hdmi_link_config link_cfg;
238*4882a593Smuzhiyun 	struct gpio_desc *enable_gpio;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	struct delayed_work work;
241*4882a593Smuzhiyun 	struct workqueue_struct *workqueue;
242*4882a593Smuzhiyun 	struct gpio_desc *hpd_gpiod;
243*4882a593Smuzhiyun 	struct pinctrl *p;
244*4882a593Smuzhiyun 	struct pinctrl_state *idle_state;
245*4882a593Smuzhiyun 	struct pinctrl_state *default_state;
246*4882a593Smuzhiyun };
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun #define to_rockchip_hdmi(x)	container_of(x, struct rockchip_hdmi, x)
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun /*
251*4882a593Smuzhiyun  * There are some rates that would be ranged for better clock jitter at
252*4882a593Smuzhiyun  * Chrome OS tree, like 25.175Mhz would range to 25.170732Mhz. But due
253*4882a593Smuzhiyun  * to the clock is aglined to KHz in struct drm_display_mode, this would
254*4882a593Smuzhiyun  * bring some inaccurate error if we still run the compute_n math, so
255*4882a593Smuzhiyun  * let's just code an const table for it until we can actually get the
256*4882a593Smuzhiyun  * right clock rate.
257*4882a593Smuzhiyun  */
258*4882a593Smuzhiyun static const struct dw_hdmi_audio_tmds_n rockchip_werid_tmds_n_table[] = {
259*4882a593Smuzhiyun 	/* 25176471 for 25.175 MHz = 428000000 / 17. */
260*4882a593Smuzhiyun 	{ .tmds = 25177000, .n_32k = 4352, .n_44k1 = 14994, .n_48k = 6528, },
261*4882a593Smuzhiyun 	/* 57290323 for 57.284 MHz */
262*4882a593Smuzhiyun 	{ .tmds = 57291000, .n_32k = 3968, .n_44k1 = 4557, .n_48k = 5952, },
263*4882a593Smuzhiyun 	/* 74437500 for 74.44 MHz = 297750000 / 4 */
264*4882a593Smuzhiyun 	{ .tmds = 74438000, .n_32k = 8192, .n_44k1 = 18816, .n_48k = 4096, },
265*4882a593Smuzhiyun 	/* 118666667 for 118.68 MHz */
266*4882a593Smuzhiyun 	{ .tmds = 118667000, .n_32k = 4224, .n_44k1 = 5292, .n_48k = 6336, },
267*4882a593Smuzhiyun 	/* 121714286 for 121.75 MHz */
268*4882a593Smuzhiyun 	{ .tmds = 121715000, .n_32k = 4480, .n_44k1 = 6174, .n_48k = 6272, },
269*4882a593Smuzhiyun 	/* 136800000 for 136.75 MHz */
270*4882a593Smuzhiyun 	{ .tmds = 136800000, .n_32k = 4096, .n_44k1 = 5684, .n_48k = 6144, },
271*4882a593Smuzhiyun 	/* End of table */
272*4882a593Smuzhiyun 	{ .tmds = 0,         .n_32k = 0,    .n_44k1 = 0,    .n_48k = 0, },
273*4882a593Smuzhiyun };
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
276*4882a593Smuzhiyun 	{
277*4882a593Smuzhiyun 		30666000, {
278*4882a593Smuzhiyun 			{ 0x00b3, 0x0000 },
279*4882a593Smuzhiyun 			{ 0x2153, 0x0000 },
280*4882a593Smuzhiyun 			{ 0x40f3, 0x0000 },
281*4882a593Smuzhiyun 		},
282*4882a593Smuzhiyun 	},  {
283*4882a593Smuzhiyun 		36800000, {
284*4882a593Smuzhiyun 			{ 0x00b3, 0x0000 },
285*4882a593Smuzhiyun 			{ 0x2153, 0x0000 },
286*4882a593Smuzhiyun 			{ 0x40a2, 0x0001 },
287*4882a593Smuzhiyun 		},
288*4882a593Smuzhiyun 	},  {
289*4882a593Smuzhiyun 		46000000, {
290*4882a593Smuzhiyun 			{ 0x00b3, 0x0000 },
291*4882a593Smuzhiyun 			{ 0x2142, 0x0001 },
292*4882a593Smuzhiyun 			{ 0x40a2, 0x0001 },
293*4882a593Smuzhiyun 		},
294*4882a593Smuzhiyun 	},  {
295*4882a593Smuzhiyun 		61333000, {
296*4882a593Smuzhiyun 			{ 0x0072, 0x0001 },
297*4882a593Smuzhiyun 			{ 0x2142, 0x0001 },
298*4882a593Smuzhiyun 			{ 0x40a2, 0x0001 },
299*4882a593Smuzhiyun 		},
300*4882a593Smuzhiyun 	},  {
301*4882a593Smuzhiyun 		73600000, {
302*4882a593Smuzhiyun 			{ 0x0072, 0x0001 },
303*4882a593Smuzhiyun 			{ 0x2142, 0x0001 },
304*4882a593Smuzhiyun 			{ 0x4061, 0x0002 },
305*4882a593Smuzhiyun 		},
306*4882a593Smuzhiyun 	},  {
307*4882a593Smuzhiyun 		92000000, {
308*4882a593Smuzhiyun 			{ 0x0072, 0x0001 },
309*4882a593Smuzhiyun 			{ 0x2145, 0x0002 },
310*4882a593Smuzhiyun 			{ 0x4061, 0x0002 },
311*4882a593Smuzhiyun 		},
312*4882a593Smuzhiyun 	},  {
313*4882a593Smuzhiyun 		122666000, {
314*4882a593Smuzhiyun 			{ 0x0051, 0x0002 },
315*4882a593Smuzhiyun 			{ 0x2145, 0x0002 },
316*4882a593Smuzhiyun 			{ 0x4061, 0x0002 },
317*4882a593Smuzhiyun 		},
318*4882a593Smuzhiyun 	},  {
319*4882a593Smuzhiyun 		147200000, {
320*4882a593Smuzhiyun 			{ 0x0051, 0x0002 },
321*4882a593Smuzhiyun 			{ 0x2145, 0x0002 },
322*4882a593Smuzhiyun 			{ 0x4064, 0x0003 },
323*4882a593Smuzhiyun 		},
324*4882a593Smuzhiyun 	},  {
325*4882a593Smuzhiyun 		184000000, {
326*4882a593Smuzhiyun 			{ 0x0051, 0x0002 },
327*4882a593Smuzhiyun 			{ 0x214c, 0x0003 },
328*4882a593Smuzhiyun 			{ 0x4064, 0x0003 },
329*4882a593Smuzhiyun 		},
330*4882a593Smuzhiyun 	},  {
331*4882a593Smuzhiyun 		226666000, {
332*4882a593Smuzhiyun 			{ 0x0040, 0x0003 },
333*4882a593Smuzhiyun 			{ 0x214c, 0x0003 },
334*4882a593Smuzhiyun 			{ 0x4064, 0x0003 },
335*4882a593Smuzhiyun 		},
336*4882a593Smuzhiyun 	},  {
337*4882a593Smuzhiyun 		272000000, {
338*4882a593Smuzhiyun 			{ 0x0040, 0x0003 },
339*4882a593Smuzhiyun 			{ 0x214c, 0x0003 },
340*4882a593Smuzhiyun 			{ 0x5a64, 0x0003 },
341*4882a593Smuzhiyun 		},
342*4882a593Smuzhiyun 	},  {
343*4882a593Smuzhiyun 		340000000, {
344*4882a593Smuzhiyun 			{ 0x0040, 0x0003 },
345*4882a593Smuzhiyun 			{ 0x3b4c, 0x0003 },
346*4882a593Smuzhiyun 			{ 0x5a64, 0x0003 },
347*4882a593Smuzhiyun 		},
348*4882a593Smuzhiyun 	},  {
349*4882a593Smuzhiyun 		600000000, {
350*4882a593Smuzhiyun 			{ 0x1a40, 0x0003 },
351*4882a593Smuzhiyun 			{ 0x3b4c, 0x0003 },
352*4882a593Smuzhiyun 			{ 0x5a64, 0x0003 },
353*4882a593Smuzhiyun 		},
354*4882a593Smuzhiyun 	},  {
355*4882a593Smuzhiyun 		~0UL, {
356*4882a593Smuzhiyun 			{ 0x0000, 0x0000 },
357*4882a593Smuzhiyun 			{ 0x0000, 0x0000 },
358*4882a593Smuzhiyun 			{ 0x0000, 0x0000 },
359*4882a593Smuzhiyun 		},
360*4882a593Smuzhiyun 	}
361*4882a593Smuzhiyun };
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun static const struct dw_hdmi_mpll_config rockchip_mpll_cfg_420[] = {
364*4882a593Smuzhiyun 	{
365*4882a593Smuzhiyun 		30666000, {
366*4882a593Smuzhiyun 			{ 0x00b7, 0x0000 },
367*4882a593Smuzhiyun 			{ 0x2157, 0x0000 },
368*4882a593Smuzhiyun 			{ 0x40f7, 0x0000 },
369*4882a593Smuzhiyun 		},
370*4882a593Smuzhiyun 	},  {
371*4882a593Smuzhiyun 		92000000, {
372*4882a593Smuzhiyun 			{ 0x00b7, 0x0000 },
373*4882a593Smuzhiyun 			{ 0x2143, 0x0001 },
374*4882a593Smuzhiyun 			{ 0x40a3, 0x0001 },
375*4882a593Smuzhiyun 		},
376*4882a593Smuzhiyun 	},  {
377*4882a593Smuzhiyun 		184000000, {
378*4882a593Smuzhiyun 			{ 0x0073, 0x0001 },
379*4882a593Smuzhiyun 			{ 0x2146, 0x0002 },
380*4882a593Smuzhiyun 			{ 0x4062, 0x0002 },
381*4882a593Smuzhiyun 		},
382*4882a593Smuzhiyun 	},  {
383*4882a593Smuzhiyun 		340000000, {
384*4882a593Smuzhiyun 			{ 0x0052, 0x0003 },
385*4882a593Smuzhiyun 			{ 0x214d, 0x0003 },
386*4882a593Smuzhiyun 			{ 0x4065, 0x0003 },
387*4882a593Smuzhiyun 		},
388*4882a593Smuzhiyun 	},  {
389*4882a593Smuzhiyun 		600000000, {
390*4882a593Smuzhiyun 			{ 0x0041, 0x0003 },
391*4882a593Smuzhiyun 			{ 0x3b4d, 0x0003 },
392*4882a593Smuzhiyun 			{ 0x5a65, 0x0003 },
393*4882a593Smuzhiyun 		},
394*4882a593Smuzhiyun 	},  {
395*4882a593Smuzhiyun 		~0UL, {
396*4882a593Smuzhiyun 			{ 0x0000, 0x0000 },
397*4882a593Smuzhiyun 			{ 0x0000, 0x0000 },
398*4882a593Smuzhiyun 			{ 0x0000, 0x0000 },
399*4882a593Smuzhiyun 		},
400*4882a593Smuzhiyun 	}
401*4882a593Smuzhiyun };
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun static const struct dw_hdmi_mpll_config rockchip_rk3288w_mpll_cfg_420[] = {
404*4882a593Smuzhiyun 	{
405*4882a593Smuzhiyun 		30666000, {
406*4882a593Smuzhiyun 			{ 0x00b7, 0x0000 },
407*4882a593Smuzhiyun 			{ 0x2157, 0x0000 },
408*4882a593Smuzhiyun 			{ 0x40f7, 0x0000 },
409*4882a593Smuzhiyun 		},
410*4882a593Smuzhiyun 	},  {
411*4882a593Smuzhiyun 		92000000, {
412*4882a593Smuzhiyun 			{ 0x00b7, 0x0000 },
413*4882a593Smuzhiyun 			{ 0x2143, 0x0001 },
414*4882a593Smuzhiyun 			{ 0x40a3, 0x0001 },
415*4882a593Smuzhiyun 		},
416*4882a593Smuzhiyun 	},  {
417*4882a593Smuzhiyun 		184000000, {
418*4882a593Smuzhiyun 			{ 0x0073, 0x0001 },
419*4882a593Smuzhiyun 			{ 0x2146, 0x0002 },
420*4882a593Smuzhiyun 			{ 0x4062, 0x0002 },
421*4882a593Smuzhiyun 		},
422*4882a593Smuzhiyun 	},  {
423*4882a593Smuzhiyun 		340000000, {
424*4882a593Smuzhiyun 			{ 0x0052, 0x0003 },
425*4882a593Smuzhiyun 			{ 0x214d, 0x0003 },
426*4882a593Smuzhiyun 			{ 0x4065, 0x0003 },
427*4882a593Smuzhiyun 		},
428*4882a593Smuzhiyun 	},  {
429*4882a593Smuzhiyun 		600000000, {
430*4882a593Smuzhiyun 			{ 0x0040, 0x0003 },
431*4882a593Smuzhiyun 			{ 0x3b4c, 0x0003 },
432*4882a593Smuzhiyun 			{ 0x5a65, 0x0003 },
433*4882a593Smuzhiyun 		},
434*4882a593Smuzhiyun 	},  {
435*4882a593Smuzhiyun 		~0UL, {
436*4882a593Smuzhiyun 			{ 0x0000, 0x0000 },
437*4882a593Smuzhiyun 			{ 0x0000, 0x0000 },
438*4882a593Smuzhiyun 			{ 0x0000, 0x0000 },
439*4882a593Smuzhiyun 		},
440*4882a593Smuzhiyun 	}
441*4882a593Smuzhiyun };
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
444*4882a593Smuzhiyun 	/*      pixelclk    bpp8    bpp10   bpp12 */
445*4882a593Smuzhiyun 	{
446*4882a593Smuzhiyun 		600000000, { 0x0000, 0x0000, 0x0000 },
447*4882a593Smuzhiyun 	},  {
448*4882a593Smuzhiyun 		~0UL,      { 0x0000, 0x0000, 0x0000},
449*4882a593Smuzhiyun 	}
450*4882a593Smuzhiyun };
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun static struct dw_hdmi_phy_config rockchip_phy_config[] = {
453*4882a593Smuzhiyun 	/*pixelclk   symbol   term   vlev*/
454*4882a593Smuzhiyun 	{ 74250000,  0x8009, 0x0004, 0x0272},
455*4882a593Smuzhiyun 	{ 165000000, 0x802b, 0x0004, 0x0209},
456*4882a593Smuzhiyun 	{ 297000000, 0x8039, 0x0005, 0x028d},
457*4882a593Smuzhiyun 	{ 594000000, 0x8039, 0x0000, 0x019d},
458*4882a593Smuzhiyun 	{ ~0UL,	     0x0000, 0x0000, 0x0000},
459*4882a593Smuzhiyun 	{ ~0UL,      0x0000, 0x0000, 0x0000},
460*4882a593Smuzhiyun };
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun enum ROW_INDEX_BPP {
463*4882a593Smuzhiyun 	ROW_INDEX_6BPP = 0,
464*4882a593Smuzhiyun 	ROW_INDEX_8BPP,
465*4882a593Smuzhiyun 	ROW_INDEX_10BPP,
466*4882a593Smuzhiyun 	ROW_INDEX_12BPP,
467*4882a593Smuzhiyun 	ROW_INDEX_23BPP,
468*4882a593Smuzhiyun 	MAX_ROW_INDEX
469*4882a593Smuzhiyun };
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun enum COLUMN_INDEX_BPC {
472*4882a593Smuzhiyun 	COLUMN_INDEX_8BPC = 0,
473*4882a593Smuzhiyun 	COLUMN_INDEX_10BPC,
474*4882a593Smuzhiyun 	COLUMN_INDEX_12BPC,
475*4882a593Smuzhiyun 	COLUMN_INDEX_14BPC,
476*4882a593Smuzhiyun 	COLUMN_INDEX_16BPC,
477*4882a593Smuzhiyun 	MAX_COLUMN_INDEX
478*4882a593Smuzhiyun };
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun #define PPS_TABLE_LEN 8
481*4882a593Smuzhiyun #define PPS_BPP_LEN 4
482*4882a593Smuzhiyun #define PPS_BPC_LEN 2
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun struct pps_data {
485*4882a593Smuzhiyun 	u32 pic_width;
486*4882a593Smuzhiyun 	u32 pic_height;
487*4882a593Smuzhiyun 	u32 slice_width;
488*4882a593Smuzhiyun 	u32 slice_height;
489*4882a593Smuzhiyun 	bool convert_rgb;
490*4882a593Smuzhiyun 	u8 bpc;
491*4882a593Smuzhiyun 	u8 bpp;
492*4882a593Smuzhiyun 	u8 raw_pps[128];
493*4882a593Smuzhiyun };
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun /*
496*4882a593Smuzhiyun  * Selected Rate Control Related Parameter Recommended Values
497*4882a593Smuzhiyun  * from DSC_v1.11 spec & C Model release: DSC_model_20161212
498*4882a593Smuzhiyun  */
499*4882a593Smuzhiyun static struct pps_data pps_datas[PPS_TABLE_LEN] = {
500*4882a593Smuzhiyun 	{
501*4882a593Smuzhiyun 		/* 7680x4320/960X96 rgb 8bpc 12bpp */
502*4882a593Smuzhiyun 		7680, 4320, 960, 96, 1, 8, 192,
503*4882a593Smuzhiyun 		{
504*4882a593Smuzhiyun 			0x12, 0x00, 0x00, 0x8d, 0x30, 0xc0, 0x10, 0xe0,
505*4882a593Smuzhiyun 			0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x05, 0xa0,
506*4882a593Smuzhiyun 			0x01, 0x55, 0x03, 0x90, 0x00, 0x0a, 0x05, 0xc9,
507*4882a593Smuzhiyun 			0x00, 0xa0, 0x00, 0x0f, 0x01, 0x44, 0x01, 0xaa,
508*4882a593Smuzhiyun 			0x08, 0x00, 0x10, 0xf4, 0x03, 0x0c, 0x20, 0x00,
509*4882a593Smuzhiyun 			0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
510*4882a593Smuzhiyun 			0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
511*4882a593Smuzhiyun 			0x7d, 0x7e, 0x00, 0x82, 0x00, 0xc0, 0x09, 0x00,
512*4882a593Smuzhiyun 			0x09, 0x7e, 0x19, 0xbc, 0x19, 0xba, 0x19, 0xf8,
513*4882a593Smuzhiyun 			0x1a, 0x38, 0x1a, 0x38, 0x1a, 0x76, 0x2a, 0x76,
514*4882a593Smuzhiyun 			0x2a, 0x76, 0x2a, 0x74, 0x3a, 0xb4, 0x52, 0xf4,
515*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
516*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
517*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
518*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
519*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
520*4882a593Smuzhiyun 		},
521*4882a593Smuzhiyun 	},
522*4882a593Smuzhiyun 	{
523*4882a593Smuzhiyun 		/* 7680x4320/960X96 rgb 8bpc 11bpp */
524*4882a593Smuzhiyun 		7680, 4320, 960, 96, 1, 8, 176,
525*4882a593Smuzhiyun 		{
526*4882a593Smuzhiyun 			0x12, 0x00, 0x00, 0x8d, 0x30, 0xb0, 0x10, 0xe0,
527*4882a593Smuzhiyun 			0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x05, 0x28,
528*4882a593Smuzhiyun 			0x01, 0x74, 0x03, 0x40, 0x00, 0x0f, 0x06, 0xe0,
529*4882a593Smuzhiyun 			0x00, 0x2d, 0x00, 0x0f, 0x01, 0x44, 0x01, 0x33,
530*4882a593Smuzhiyun 			0x0f, 0x00, 0x10, 0xf4, 0x03, 0x0c, 0x20, 0x00,
531*4882a593Smuzhiyun 			0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
532*4882a593Smuzhiyun 			0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
533*4882a593Smuzhiyun 			0x7d, 0x7e, 0x00, 0x82, 0x01, 0x00, 0x09, 0x40,
534*4882a593Smuzhiyun 			0x09, 0xbe, 0x19, 0xfc, 0x19, 0xfa, 0x19, 0xf8,
535*4882a593Smuzhiyun 			0x1a, 0x38, 0x1a, 0x38, 0x1a, 0x76, 0x2a, 0x76,
536*4882a593Smuzhiyun 			0x2a, 0x76, 0x2a, 0xb4, 0x3a, 0xb4, 0x52, 0xf4,
537*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
538*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
539*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
540*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
541*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
542*4882a593Smuzhiyun 		},
543*4882a593Smuzhiyun 	},
544*4882a593Smuzhiyun 	{
545*4882a593Smuzhiyun 		/* 7680x4320/960X96 rgb 8bpc 10bpp */
546*4882a593Smuzhiyun 		7680, 4320, 960, 96, 1, 8, 160,
547*4882a593Smuzhiyun 		{
548*4882a593Smuzhiyun 			0x12, 0x00, 0x00, 0x8d, 0x30, 0xa0, 0x10, 0xe0,
549*4882a593Smuzhiyun 			0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x04, 0xb0,
550*4882a593Smuzhiyun 			0x01, 0x9a, 0x02, 0xe0, 0x00, 0x19, 0x09, 0xb0,
551*4882a593Smuzhiyun 			0x00, 0x12, 0x00, 0x0f, 0x01, 0x44, 0x00, 0xbb,
552*4882a593Smuzhiyun 			0x16, 0x00, 0x10, 0xec, 0x03, 0x0c, 0x20, 0x00,
553*4882a593Smuzhiyun 			0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
554*4882a593Smuzhiyun 			0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
555*4882a593Smuzhiyun 			0x7d, 0x7e, 0x00, 0xc2, 0x01, 0x00, 0x09, 0x40,
556*4882a593Smuzhiyun 			0x09, 0xbe, 0x19, 0xfc, 0x19, 0xfa, 0x19, 0xf8,
557*4882a593Smuzhiyun 			0x1a, 0x38, 0x1a, 0x78, 0x1a, 0x76, 0x2a, 0xb6,
558*4882a593Smuzhiyun 			0x2a, 0xb6, 0x2a, 0xf4, 0x3a, 0xf4, 0x5b, 0x34,
559*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
560*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
561*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
562*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
563*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
564*4882a593Smuzhiyun 		},
565*4882a593Smuzhiyun 	},
566*4882a593Smuzhiyun 	{
567*4882a593Smuzhiyun 		/* 7680x4320/960X96 rgb 8bpc 9bpp */
568*4882a593Smuzhiyun 		7680, 4320, 960, 96, 1, 8, 144,
569*4882a593Smuzhiyun 		{
570*4882a593Smuzhiyun 			0x12, 0x00, 0x00, 0x8d, 0x30, 0x90, 0x10, 0xe0,
571*4882a593Smuzhiyun 			0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x04, 0x38,
572*4882a593Smuzhiyun 			0x01, 0xc7, 0x03, 0x16, 0x00, 0x1c, 0x08, 0xc7,
573*4882a593Smuzhiyun 			0x00, 0x10, 0x00, 0x0f, 0x01, 0x44, 0x00, 0xaa,
574*4882a593Smuzhiyun 			0x17, 0x00, 0x10, 0xf1, 0x03, 0x0c, 0x20, 0x00,
575*4882a593Smuzhiyun 			0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
576*4882a593Smuzhiyun 			0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
577*4882a593Smuzhiyun 			0x7d, 0x7e, 0x00, 0xc2, 0x01, 0x00, 0x09, 0x40,
578*4882a593Smuzhiyun 			0x09, 0xbe, 0x19, 0xfc, 0x19, 0xfa, 0x19, 0xf8,
579*4882a593Smuzhiyun 			0x1a, 0x38, 0x1a, 0x78, 0x1a, 0x76, 0x2a, 0xb6,
580*4882a593Smuzhiyun 			0x2a, 0xb6, 0x2a, 0xf4, 0x3a, 0xf4, 0x63, 0x74,
581*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
582*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
583*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
584*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
585*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
586*4882a593Smuzhiyun 		},
587*4882a593Smuzhiyun 	},
588*4882a593Smuzhiyun 	{
589*4882a593Smuzhiyun 		/* 7680x4320/960X96 rgb 10bpc 12bpp */
590*4882a593Smuzhiyun 		7680, 4320, 960, 96, 1, 10, 192,
591*4882a593Smuzhiyun 		{
592*4882a593Smuzhiyun 			0x12, 0x00, 0x00, 0xad, 0x30, 0xc0, 0x10, 0xe0,
593*4882a593Smuzhiyun 			0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x05, 0xa0,
594*4882a593Smuzhiyun 			0x01, 0x55, 0x03, 0x90, 0x00, 0x0a, 0x05, 0xc9,
595*4882a593Smuzhiyun 			0x00, 0xa0, 0x00, 0x0f, 0x01, 0x44, 0x01, 0xaa,
596*4882a593Smuzhiyun 			0x08, 0x00, 0x10, 0xf4, 0x07, 0x10, 0x20, 0x00,
597*4882a593Smuzhiyun 			0x06, 0x0f, 0x0f, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
598*4882a593Smuzhiyun 			0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
599*4882a593Smuzhiyun 			0x7d, 0x7e, 0x01, 0x02, 0x11, 0x80, 0x22, 0x00,
600*4882a593Smuzhiyun 			0x22, 0x7e, 0x32, 0xbc, 0x32, 0xba, 0x3a, 0xf8,
601*4882a593Smuzhiyun 			0x3b, 0x38, 0x3b, 0x38, 0x3b, 0x76, 0x4b, 0x76,
602*4882a593Smuzhiyun 			0x4b, 0x76, 0x4b, 0x74, 0x5b, 0xb4, 0x73, 0xf4,
603*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
604*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
605*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
606*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
607*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
608*4882a593Smuzhiyun 		},
609*4882a593Smuzhiyun 	},
610*4882a593Smuzhiyun 	{
611*4882a593Smuzhiyun 		/* 7680x4320/960X96 rgb 10bpc 11bpp */
612*4882a593Smuzhiyun 		7680, 4320, 960, 96, 1, 10, 176,
613*4882a593Smuzhiyun 		{
614*4882a593Smuzhiyun 			0x12, 0x00, 0x00, 0xad, 0x30, 0xb0, 0x10, 0xe0,
615*4882a593Smuzhiyun 			0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x05, 0x28,
616*4882a593Smuzhiyun 			0x01, 0x74, 0x03, 0x40, 0x00, 0x0f, 0x06, 0xe0,
617*4882a593Smuzhiyun 			0x00, 0x2d, 0x00, 0x0f, 0x01, 0x44, 0x01, 0x33,
618*4882a593Smuzhiyun 			0x0f, 0x00, 0x10, 0xf4, 0x07, 0x10, 0x20, 0x00,
619*4882a593Smuzhiyun 			0x06, 0x0f, 0x0f, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
620*4882a593Smuzhiyun 			0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
621*4882a593Smuzhiyun 			0x7d, 0x7e, 0x01, 0x42, 0x19, 0xc0, 0x2a, 0x40,
622*4882a593Smuzhiyun 			0x2a, 0xbe, 0x3a, 0xfc, 0x3a, 0xfa, 0x3a, 0xf8,
623*4882a593Smuzhiyun 			0x3b, 0x38, 0x3b, 0x38, 0x3b, 0x76, 0x4b, 0x76,
624*4882a593Smuzhiyun 			0x4b, 0x76, 0x4b, 0xb4, 0x5b, 0xb4, 0x73, 0xf4,
625*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
626*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
627*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
628*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
629*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
630*4882a593Smuzhiyun 		},
631*4882a593Smuzhiyun 	},
632*4882a593Smuzhiyun 	{
633*4882a593Smuzhiyun 		/* 7680x4320/960X96 rgb 10bpc 10bpp */
634*4882a593Smuzhiyun 		7680, 4320, 960, 96, 1, 10, 160,
635*4882a593Smuzhiyun 		{
636*4882a593Smuzhiyun 			0x12, 0x00, 0x00, 0xad, 0x30, 0xa0, 0x10, 0xe0,
637*4882a593Smuzhiyun 			0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x04, 0xb0,
638*4882a593Smuzhiyun 			0x01, 0x9a, 0x02, 0xe0, 0x00, 0x19, 0x09, 0xb0,
639*4882a593Smuzhiyun 			0x00, 0x12, 0x00, 0x0f, 0x01, 0x44, 0x00, 0xbb,
640*4882a593Smuzhiyun 			0x16, 0x00, 0x10, 0xec, 0x07, 0x10, 0x20, 0x00,
641*4882a593Smuzhiyun 			0x06, 0x0f, 0x0f, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
642*4882a593Smuzhiyun 			0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
643*4882a593Smuzhiyun 			0x7d, 0x7e, 0x01, 0xc2, 0x22, 0x00, 0x2a, 0x40,
644*4882a593Smuzhiyun 			0x2a, 0xbe, 0x3a, 0xfc, 0x3a, 0xfa, 0x3a, 0xf8,
645*4882a593Smuzhiyun 			0x3b, 0x38, 0x3b, 0x78, 0x3b, 0x76, 0x4b, 0xb6,
646*4882a593Smuzhiyun 			0x4b, 0xb6, 0x4b, 0xf4, 0x63, 0xf4, 0x7c, 0x34,
647*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
648*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
649*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
650*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
651*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
652*4882a593Smuzhiyun 		},
653*4882a593Smuzhiyun 	},
654*4882a593Smuzhiyun 	{
655*4882a593Smuzhiyun 		/* 7680x4320/960X96 rgb 10bpc 9bpp */
656*4882a593Smuzhiyun 		7680, 4320, 960, 96, 1, 10, 144,
657*4882a593Smuzhiyun 		{
658*4882a593Smuzhiyun 			0x12, 0x00, 0x00, 0xad, 0x30, 0x90, 0x10, 0xe0,
659*4882a593Smuzhiyun 			0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x04, 0x38,
660*4882a593Smuzhiyun 			0x01, 0xc7, 0x03, 0x16, 0x00, 0x1c, 0x08, 0xc7,
661*4882a593Smuzhiyun 			0x00, 0x10, 0x00, 0x0f, 0x01, 0x44, 0x00, 0xaa,
662*4882a593Smuzhiyun 			0x17, 0x00, 0x10, 0xf1, 0x07, 0x10, 0x20, 0x00,
663*4882a593Smuzhiyun 			0x06, 0x0f, 0x0f, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
664*4882a593Smuzhiyun 			0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
665*4882a593Smuzhiyun 			0x7d, 0x7e, 0x01, 0xc2, 0x22, 0x00, 0x2a, 0x40,
666*4882a593Smuzhiyun 			0x2a, 0xbe, 0x3a, 0xfc, 0x3a, 0xfa, 0x3a, 0xf8,
667*4882a593Smuzhiyun 			0x3b, 0x38, 0x3b, 0x78, 0x3b, 0x76, 0x4b, 0xb6,
668*4882a593Smuzhiyun 			0x4b, 0xb6, 0x4b, 0xf4, 0x63, 0xf4, 0x84, 0x74,
669*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
670*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
671*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
672*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
673*4882a593Smuzhiyun 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
674*4882a593Smuzhiyun 		},
675*4882a593Smuzhiyun 	},
676*4882a593Smuzhiyun };
677*4882a593Smuzhiyun 
hdmi_bus_fmt_is_rgb(unsigned int bus_format)678*4882a593Smuzhiyun static bool hdmi_bus_fmt_is_rgb(unsigned int bus_format)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun 	switch (bus_format) {
681*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_RGB888_1X24:
682*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_RGB101010_1X30:
683*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_RGB121212_1X36:
684*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_RGB161616_1X48:
685*4882a593Smuzhiyun 		return true;
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 	default:
688*4882a593Smuzhiyun 		return false;
689*4882a593Smuzhiyun 	}
690*4882a593Smuzhiyun }
691*4882a593Smuzhiyun 
hdmi_bus_fmt_is_yuv444(unsigned int bus_format)692*4882a593Smuzhiyun static bool hdmi_bus_fmt_is_yuv444(unsigned int bus_format)
693*4882a593Smuzhiyun {
694*4882a593Smuzhiyun 	switch (bus_format) {
695*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUV8_1X24:
696*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUV10_1X30:
697*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUV12_1X36:
698*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUV16_1X48:
699*4882a593Smuzhiyun 		return true;
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 	default:
702*4882a593Smuzhiyun 		return false;
703*4882a593Smuzhiyun 	}
704*4882a593Smuzhiyun }
705*4882a593Smuzhiyun 
hdmi_bus_fmt_is_yuv422(unsigned int bus_format)706*4882a593Smuzhiyun static bool hdmi_bus_fmt_is_yuv422(unsigned int bus_format)
707*4882a593Smuzhiyun {
708*4882a593Smuzhiyun 	switch (bus_format) {
709*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYVY8_1X16:
710*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYVY10_1X20:
711*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYVY12_1X24:
712*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUYV8_1X16:
713*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUYV10_1X20:
714*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUYV12_1X24:
715*4882a593Smuzhiyun 		return true;
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 	default:
718*4882a593Smuzhiyun 		return false;
719*4882a593Smuzhiyun 	}
720*4882a593Smuzhiyun }
721*4882a593Smuzhiyun 
hdmi_bus_fmt_is_yuv420(unsigned int bus_format)722*4882a593Smuzhiyun static bool hdmi_bus_fmt_is_yuv420(unsigned int bus_format)
723*4882a593Smuzhiyun {
724*4882a593Smuzhiyun 	switch (bus_format) {
725*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
726*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
727*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
728*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
729*4882a593Smuzhiyun 		return true;
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	default:
732*4882a593Smuzhiyun 	return false;
733*4882a593Smuzhiyun 	}
734*4882a593Smuzhiyun }
735*4882a593Smuzhiyun 
hdmi_bus_fmt_color_depth(unsigned int bus_format)736*4882a593Smuzhiyun static int hdmi_bus_fmt_color_depth(unsigned int bus_format)
737*4882a593Smuzhiyun {
738*4882a593Smuzhiyun 	switch (bus_format) {
739*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_RGB888_1X24:
740*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUV8_1X24:
741*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYVY8_1X16:
742*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUYV8_1X16:
743*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
744*4882a593Smuzhiyun 		return 8;
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_RGB101010_1X30:
747*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUV10_1X30:
748*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYVY10_1X20:
749*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUYV10_1X20:
750*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
751*4882a593Smuzhiyun 		return 10;
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_RGB121212_1X36:
754*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUV12_1X36:
755*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYVY12_1X24:
756*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUYV12_1X24:
757*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
758*4882a593Smuzhiyun 		return 12;
759*4882a593Smuzhiyun 
760*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_RGB161616_1X48:
761*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUV16_1X48:
762*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
763*4882a593Smuzhiyun 		return 16;
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun 	default:
766*4882a593Smuzhiyun 		return 0;
767*4882a593Smuzhiyun 	}
768*4882a593Smuzhiyun }
769*4882a593Smuzhiyun 
hdmi_bus_fmt_to_color_format(unsigned int bus_format)770*4882a593Smuzhiyun static int hdmi_bus_fmt_to_color_format(unsigned int bus_format)
771*4882a593Smuzhiyun {
772*4882a593Smuzhiyun 	switch (bus_format) {
773*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
774*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
775*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
776*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
777*4882a593Smuzhiyun 		return RK_IF_FORMAT_YCBCR420;
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUV8_1X24:
780*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUV10_1X30:
781*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUV12_1X36:
782*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUV16_1X48:
783*4882a593Smuzhiyun 		return RK_IF_FORMAT_YCBCR444;
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYVY8_1X16:
786*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUYV8_1X16:
787*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYVY10_1X20:
788*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUYV10_1X20:
789*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYVY12_1X24:
790*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YVYU12_1X24:
791*4882a593Smuzhiyun 		return RK_IF_FORMAT_YCBCR422;
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_RGB888_1X24:
794*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_RGB101010_1X30:
795*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_RGB121212_1X36:
796*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_RGB161616_1X48:
797*4882a593Smuzhiyun 	default:
798*4882a593Smuzhiyun 		return RK_IF_FORMAT_RGB;
799*4882a593Smuzhiyun 	}
800*4882a593Smuzhiyun }
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun static unsigned int
hdmi_get_tmdsclock(struct rockchip_hdmi * hdmi,unsigned long pixelclock)803*4882a593Smuzhiyun hdmi_get_tmdsclock(struct rockchip_hdmi *hdmi, unsigned long pixelclock)
804*4882a593Smuzhiyun {
805*4882a593Smuzhiyun 	unsigned int tmdsclock = pixelclock;
806*4882a593Smuzhiyun 	unsigned int depth =
807*4882a593Smuzhiyun 		hdmi_bus_fmt_color_depth(hdmi->output_bus_format);
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun 	if (!hdmi_bus_fmt_is_yuv422(hdmi->output_bus_format)) {
810*4882a593Smuzhiyun 		switch (depth) {
811*4882a593Smuzhiyun 		case 16:
812*4882a593Smuzhiyun 			tmdsclock = pixelclock * 2;
813*4882a593Smuzhiyun 			break;
814*4882a593Smuzhiyun 		case 12:
815*4882a593Smuzhiyun 			tmdsclock = pixelclock * 3 / 2;
816*4882a593Smuzhiyun 			break;
817*4882a593Smuzhiyun 		case 10:
818*4882a593Smuzhiyun 			tmdsclock = pixelclock * 5 / 4;
819*4882a593Smuzhiyun 			break;
820*4882a593Smuzhiyun 		default:
821*4882a593Smuzhiyun 			break;
822*4882a593Smuzhiyun 		}
823*4882a593Smuzhiyun 	}
824*4882a593Smuzhiyun 
825*4882a593Smuzhiyun 	return tmdsclock;
826*4882a593Smuzhiyun }
827*4882a593Smuzhiyun 
rockchip_hdmi_match_by_id(struct device * dev,const void * data)828*4882a593Smuzhiyun static int rockchip_hdmi_match_by_id(struct device *dev, const void *data)
829*4882a593Smuzhiyun {
830*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
831*4882a593Smuzhiyun 	const unsigned int *id = data;
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 	return hdmi->id == *id;
834*4882a593Smuzhiyun }
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun static struct rockchip_hdmi *
rockchip_hdmi_find_by_id(struct device_driver * drv,unsigned int id)837*4882a593Smuzhiyun rockchip_hdmi_find_by_id(struct device_driver *drv, unsigned int id)
838*4882a593Smuzhiyun {
839*4882a593Smuzhiyun 	struct device *dev;
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun 	dev = driver_find_device(drv, NULL, &id, rockchip_hdmi_match_by_id);
842*4882a593Smuzhiyun 	if (!dev)
843*4882a593Smuzhiyun 		return NULL;
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun 	return dev_get_drvdata(dev);
846*4882a593Smuzhiyun }
847*4882a593Smuzhiyun 
hdmi_select_link_config(struct rockchip_hdmi * hdmi,struct drm_crtc_state * crtc_state,unsigned int tmdsclk)848*4882a593Smuzhiyun static void hdmi_select_link_config(struct rockchip_hdmi *hdmi,
849*4882a593Smuzhiyun 				    struct drm_crtc_state *crtc_state,
850*4882a593Smuzhiyun 				    unsigned int tmdsclk)
851*4882a593Smuzhiyun {
852*4882a593Smuzhiyun 	struct drm_display_mode mode;
853*4882a593Smuzhiyun 	int max_lanes, max_rate_per_lane;
854*4882a593Smuzhiyun 	int max_dsc_lanes, max_dsc_rate_per_lane;
855*4882a593Smuzhiyun 	unsigned long max_frl_rate;
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 	drm_mode_copy(&mode, &crtc_state->mode);
858*4882a593Smuzhiyun 	if (hdmi->plat_data->split_mode)
859*4882a593Smuzhiyun 		drm_mode_convert_to_origin_mode(&mode);
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun 	max_lanes = hdmi->max_lanes;
862*4882a593Smuzhiyun 	max_rate_per_lane = hdmi->max_frl_rate_per_lane;
863*4882a593Smuzhiyun 	max_frl_rate = max_lanes * max_rate_per_lane * 1000000;
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun 	hdmi->link_cfg.dsc_mode = false;
866*4882a593Smuzhiyun 	hdmi->link_cfg.frl_lanes = max_lanes;
867*4882a593Smuzhiyun 	hdmi->link_cfg.rate_per_lane = max_rate_per_lane;
868*4882a593Smuzhiyun 	hdmi->link_cfg.add_func = hdmi->add_func;
869*4882a593Smuzhiyun 
870*4882a593Smuzhiyun 	if (!max_frl_rate || (tmdsclk < HDMI20_MAX_RATE && mode.clock < HDMI20_MAX_RATE)) {
871*4882a593Smuzhiyun 		dev_info(hdmi->dev, "use tmds mode\n");
872*4882a593Smuzhiyun 		hdmi->link_cfg.frl_mode = false;
873*4882a593Smuzhiyun 		return;
874*4882a593Smuzhiyun 	}
875*4882a593Smuzhiyun 
876*4882a593Smuzhiyun 	hdmi->link_cfg.frl_mode = true;
877*4882a593Smuzhiyun 
878*4882a593Smuzhiyun 	if (!hdmi->dsc_cap.v_1p2)
879*4882a593Smuzhiyun 		return;
880*4882a593Smuzhiyun 
881*4882a593Smuzhiyun 	max_dsc_lanes = hdmi->dsc_cap.max_lanes;
882*4882a593Smuzhiyun 	max_dsc_rate_per_lane =
883*4882a593Smuzhiyun 		hdmi->dsc_cap.max_frl_rate_per_lane;
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun 	if (mode.clock >= HDMI_8K60_RATE &&
886*4882a593Smuzhiyun 	    !hdmi_bus_fmt_is_yuv420(hdmi->bus_format) &&
887*4882a593Smuzhiyun 	    !hdmi_bus_fmt_is_yuv422(hdmi->bus_format)) {
888*4882a593Smuzhiyun 		hdmi->link_cfg.dsc_mode = true;
889*4882a593Smuzhiyun 		hdmi->link_cfg.frl_lanes = max_dsc_lanes;
890*4882a593Smuzhiyun 		hdmi->link_cfg.rate_per_lane = max_dsc_rate_per_lane;
891*4882a593Smuzhiyun 	} else {
892*4882a593Smuzhiyun 		hdmi->link_cfg.dsc_mode = false;
893*4882a593Smuzhiyun 		hdmi->link_cfg.frl_lanes = max_lanes;
894*4882a593Smuzhiyun 		hdmi->link_cfg.rate_per_lane = max_rate_per_lane;
895*4882a593Smuzhiyun 	}
896*4882a593Smuzhiyun }
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun /////////////////////////////////////////////////////////////////////////////////////
899*4882a593Smuzhiyun 
hdmi_dsc_get_slice_height(int vactive)900*4882a593Smuzhiyun static int hdmi_dsc_get_slice_height(int vactive)
901*4882a593Smuzhiyun {
902*4882a593Smuzhiyun 	int slice_height;
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun 	/*
905*4882a593Smuzhiyun 	 * Slice Height determination : HDMI2.1 Section 7.7.5.2
906*4882a593Smuzhiyun 	 * Select smallest slice height >=96, that results in a valid PPS and
907*4882a593Smuzhiyun 	 * requires minimum padding lines required for final slice.
908*4882a593Smuzhiyun 	 *
909*4882a593Smuzhiyun 	 * Assumption : Vactive is even.
910*4882a593Smuzhiyun 	 */
911*4882a593Smuzhiyun 	for (slice_height = 96; slice_height <= vactive; slice_height += 2)
912*4882a593Smuzhiyun 		if (vactive % slice_height == 0)
913*4882a593Smuzhiyun 			return slice_height;
914*4882a593Smuzhiyun 
915*4882a593Smuzhiyun 	return 0;
916*4882a593Smuzhiyun }
917*4882a593Smuzhiyun 
hdmi_dsc_get_num_slices(struct rockchip_hdmi * hdmi,struct drm_crtc_state * crtc_state,int src_max_slices,int src_max_slice_width,int hdmi_max_slices,int hdmi_throughput)918*4882a593Smuzhiyun static int hdmi_dsc_get_num_slices(struct rockchip_hdmi *hdmi,
919*4882a593Smuzhiyun 				   struct drm_crtc_state *crtc_state,
920*4882a593Smuzhiyun 				   int src_max_slices, int src_max_slice_width,
921*4882a593Smuzhiyun 				   int hdmi_max_slices, int hdmi_throughput)
922*4882a593Smuzhiyun {
923*4882a593Smuzhiyun /* Pixel rates in KPixels/sec */
924*4882a593Smuzhiyun #define HDMI_DSC_PEAK_PIXEL_RATE		2720000
925*4882a593Smuzhiyun /*
926*4882a593Smuzhiyun  * Rates at which the source and sink are required to process pixels in each
927*4882a593Smuzhiyun  * slice, can be two levels: either at least 340000KHz or at least 40000KHz.
928*4882a593Smuzhiyun  */
929*4882a593Smuzhiyun #define HDMI_DSC_MAX_ENC_THROUGHPUT_0		340000
930*4882a593Smuzhiyun #define HDMI_DSC_MAX_ENC_THROUGHPUT_1		400000
931*4882a593Smuzhiyun 
932*4882a593Smuzhiyun /* Spec limits the slice width to 2720 pixels */
933*4882a593Smuzhiyun #define MAX_HDMI_SLICE_WIDTH			2720
934*4882a593Smuzhiyun 	int kslice_adjust;
935*4882a593Smuzhiyun 	int adjusted_clk_khz;
936*4882a593Smuzhiyun 	int min_slices;
937*4882a593Smuzhiyun 	int target_slices;
938*4882a593Smuzhiyun 	int max_throughput; /* max clock freq. in khz per slice */
939*4882a593Smuzhiyun 	int max_slice_width;
940*4882a593Smuzhiyun 	int slice_width;
941*4882a593Smuzhiyun 	int pixel_clock = crtc_state->mode.clock;
942*4882a593Smuzhiyun 
943*4882a593Smuzhiyun 	if (!hdmi_throughput)
944*4882a593Smuzhiyun 		return 0;
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun 	/*
947*4882a593Smuzhiyun 	 * Slice Width determination : HDMI2.1 Section 7.7.5.1
948*4882a593Smuzhiyun 	 * kslice_adjust factor for 4:2:0, and 4:2:2 formats is 0.5, where as
949*4882a593Smuzhiyun 	 * for 4:4:4 is 1.0. Multiplying these factors by 10 and later
950*4882a593Smuzhiyun 	 * dividing adjusted clock value by 10.
951*4882a593Smuzhiyun 	 */
952*4882a593Smuzhiyun 	if (hdmi_bus_fmt_is_yuv444(hdmi->output_bus_format) ||
953*4882a593Smuzhiyun 	    hdmi_bus_fmt_is_rgb(hdmi->output_bus_format))
954*4882a593Smuzhiyun 		kslice_adjust = 10;
955*4882a593Smuzhiyun 	else
956*4882a593Smuzhiyun 		kslice_adjust = 5;
957*4882a593Smuzhiyun 
958*4882a593Smuzhiyun 	/*
959*4882a593Smuzhiyun 	 * As per spec, the rate at which the source and the sink process
960*4882a593Smuzhiyun 	 * the pixels per slice are at two levels: at least 340Mhz or 400Mhz.
961*4882a593Smuzhiyun 	 * This depends upon the pixel clock rate and output formats
962*4882a593Smuzhiyun 	 * (kslice adjust).
963*4882a593Smuzhiyun 	 * If pixel clock * kslice adjust >= 2720MHz slices can be processed
964*4882a593Smuzhiyun 	 * at max 340MHz, otherwise they can be processed at max 400MHz.
965*4882a593Smuzhiyun 	 */
966*4882a593Smuzhiyun 
967*4882a593Smuzhiyun 	adjusted_clk_khz = DIV_ROUND_UP(kslice_adjust * pixel_clock, 10);
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun 	if (adjusted_clk_khz <= HDMI_DSC_PEAK_PIXEL_RATE)
970*4882a593Smuzhiyun 		max_throughput = HDMI_DSC_MAX_ENC_THROUGHPUT_0;
971*4882a593Smuzhiyun 	else
972*4882a593Smuzhiyun 		max_throughput = HDMI_DSC_MAX_ENC_THROUGHPUT_1;
973*4882a593Smuzhiyun 
974*4882a593Smuzhiyun 	/*
975*4882a593Smuzhiyun 	 * Taking into account the sink's capability for maximum
976*4882a593Smuzhiyun 	 * clock per slice (in MHz) as read from HF-VSDB.
977*4882a593Smuzhiyun 	 */
978*4882a593Smuzhiyun 	max_throughput = min(max_throughput, hdmi_throughput * 1000);
979*4882a593Smuzhiyun 
980*4882a593Smuzhiyun 	min_slices = DIV_ROUND_UP(adjusted_clk_khz, max_throughput);
981*4882a593Smuzhiyun 	max_slice_width = min(MAX_HDMI_SLICE_WIDTH, src_max_slice_width);
982*4882a593Smuzhiyun 
983*4882a593Smuzhiyun 	/*
984*4882a593Smuzhiyun 	 * Keep on increasing the num of slices/line, starting from min_slices
985*4882a593Smuzhiyun 	 * per line till we get such a number, for which the slice_width is
986*4882a593Smuzhiyun 	 * just less than max_slice_width. The slices/line selected should be
987*4882a593Smuzhiyun 	 * less than or equal to the max horizontal slices that the combination
988*4882a593Smuzhiyun 	 * of PCON encoder and HDMI decoder can support.
989*4882a593Smuzhiyun 	 */
990*4882a593Smuzhiyun 	do {
991*4882a593Smuzhiyun 		if (min_slices <= 1 && src_max_slices >= 1 && hdmi_max_slices >= 1)
992*4882a593Smuzhiyun 			target_slices = 1;
993*4882a593Smuzhiyun 		else if (min_slices <= 2 && src_max_slices >= 2 && hdmi_max_slices >= 2)
994*4882a593Smuzhiyun 			target_slices = 2;
995*4882a593Smuzhiyun 		else if (min_slices <= 4 && src_max_slices >= 4 && hdmi_max_slices >= 4)
996*4882a593Smuzhiyun 			target_slices = 4;
997*4882a593Smuzhiyun 		else if (min_slices <= 8 && src_max_slices >= 8 && hdmi_max_slices >= 8)
998*4882a593Smuzhiyun 			target_slices = 8;
999*4882a593Smuzhiyun 		else if (min_slices <= 12 && src_max_slices >= 12 && hdmi_max_slices >= 12)
1000*4882a593Smuzhiyun 			target_slices = 12;
1001*4882a593Smuzhiyun 		else if (min_slices <= 16 && src_max_slices >= 16 && hdmi_max_slices >= 16)
1002*4882a593Smuzhiyun 			target_slices = 16;
1003*4882a593Smuzhiyun 		else
1004*4882a593Smuzhiyun 			return 0;
1005*4882a593Smuzhiyun 
1006*4882a593Smuzhiyun 		slice_width = DIV_ROUND_UP(crtc_state->mode.hdisplay, target_slices);
1007*4882a593Smuzhiyun 		if (slice_width > max_slice_width)
1008*4882a593Smuzhiyun 			min_slices = target_slices + 1;
1009*4882a593Smuzhiyun 	} while (slice_width > max_slice_width);
1010*4882a593Smuzhiyun 
1011*4882a593Smuzhiyun 	return target_slices;
1012*4882a593Smuzhiyun }
1013*4882a593Smuzhiyun 
hdmi_dsc_slices(struct rockchip_hdmi * hdmi,struct drm_crtc_state * crtc_state)1014*4882a593Smuzhiyun static int hdmi_dsc_slices(struct rockchip_hdmi *hdmi,
1015*4882a593Smuzhiyun 			   struct drm_crtc_state *crtc_state)
1016*4882a593Smuzhiyun {
1017*4882a593Smuzhiyun 	int hdmi_throughput = hdmi->dsc_cap.clk_per_slice;
1018*4882a593Smuzhiyun 	int hdmi_max_slices = hdmi->dsc_cap.max_slices;
1019*4882a593Smuzhiyun 	int rk_max_slices = 8;
1020*4882a593Smuzhiyun 	int rk_max_slice_width = 2048;
1021*4882a593Smuzhiyun 
1022*4882a593Smuzhiyun 	return hdmi_dsc_get_num_slices(hdmi, crtc_state, rk_max_slices,
1023*4882a593Smuzhiyun 				       rk_max_slice_width,
1024*4882a593Smuzhiyun 				       hdmi_max_slices, hdmi_throughput);
1025*4882a593Smuzhiyun }
1026*4882a593Smuzhiyun 
1027*4882a593Smuzhiyun static int
hdmi_dsc_get_bpp(struct rockchip_hdmi * hdmi,int src_fractional_bpp,int slice_width,int num_slices,bool hdmi_all_bpp,int hdmi_max_chunk_bytes)1028*4882a593Smuzhiyun hdmi_dsc_get_bpp(struct rockchip_hdmi *hdmi, int src_fractional_bpp,
1029*4882a593Smuzhiyun 		 int slice_width, int num_slices, bool hdmi_all_bpp,
1030*4882a593Smuzhiyun 		 int hdmi_max_chunk_bytes)
1031*4882a593Smuzhiyun {
1032*4882a593Smuzhiyun 	int max_dsc_bpp, min_dsc_bpp;
1033*4882a593Smuzhiyun 	int target_bytes;
1034*4882a593Smuzhiyun 	bool bpp_found = false;
1035*4882a593Smuzhiyun 	int bpp_decrement_x16;
1036*4882a593Smuzhiyun 	int bpp_target;
1037*4882a593Smuzhiyun 	int bpp_target_x16;
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun 	/*
1040*4882a593Smuzhiyun 	 * Get min bpp and max bpp as per Table 7.23, in HDMI2.1 spec
1041*4882a593Smuzhiyun 	 * Start with the max bpp and keep on decrementing with
1042*4882a593Smuzhiyun 	 * fractional bpp, if supported by PCON DSC encoder
1043*4882a593Smuzhiyun 	 *
1044*4882a593Smuzhiyun 	 * for each bpp we check if no of bytes can be supported by HDMI sink
1045*4882a593Smuzhiyun 	 */
1046*4882a593Smuzhiyun 
1047*4882a593Smuzhiyun 	/* only 9\10\12 bpp was tested */
1048*4882a593Smuzhiyun 	min_dsc_bpp = 9;
1049*4882a593Smuzhiyun 	max_dsc_bpp = 12;
1050*4882a593Smuzhiyun 
1051*4882a593Smuzhiyun 	/*
1052*4882a593Smuzhiyun 	 * Taking into account if all dsc_all_bpp supported by HDMI2.1 sink
1053*4882a593Smuzhiyun 	 * Section 7.7.34 : Source shall not enable compressed Video
1054*4882a593Smuzhiyun 	 * Transport with bpp_target settings above 12 bpp unless
1055*4882a593Smuzhiyun 	 * DSC_all_bpp is set to 1.
1056*4882a593Smuzhiyun 	 */
1057*4882a593Smuzhiyun 	if (!hdmi_all_bpp)
1058*4882a593Smuzhiyun 		max_dsc_bpp = min(max_dsc_bpp, 12);
1059*4882a593Smuzhiyun 
1060*4882a593Smuzhiyun 	/*
1061*4882a593Smuzhiyun 	 * The Sink has a limit of compressed data in bytes for a scanline,
1062*4882a593Smuzhiyun 	 * as described in max_chunk_bytes field in HFVSDB block of edid.
1063*4882a593Smuzhiyun 	 * The no. of bytes depend on the target bits per pixel that the
1064*4882a593Smuzhiyun 	 * source configures. So we start with the max_bpp and calculate
1065*4882a593Smuzhiyun 	 * the target_chunk_bytes. We keep on decrementing the target_bpp,
1066*4882a593Smuzhiyun 	 * till we get the target_chunk_bytes just less than what the sink's
1067*4882a593Smuzhiyun 	 * max_chunk_bytes, or else till we reach the min_dsc_bpp.
1068*4882a593Smuzhiyun 	 *
1069*4882a593Smuzhiyun 	 * The decrement is according to the fractional support from PCON DSC
1070*4882a593Smuzhiyun 	 * encoder. For fractional BPP we use bpp_target as a multiple of 16.
1071*4882a593Smuzhiyun 	 *
1072*4882a593Smuzhiyun 	 * bpp_target_x16 = bpp_target * 16
1073*4882a593Smuzhiyun 	 * So we need to decrement by {1, 2, 4, 8, 16} for fractional bpps
1074*4882a593Smuzhiyun 	 * {1/16, 1/8, 1/4, 1/2, 1} respectively.
1075*4882a593Smuzhiyun 	 */
1076*4882a593Smuzhiyun 
1077*4882a593Smuzhiyun 	bpp_target = max_dsc_bpp;
1078*4882a593Smuzhiyun 
1079*4882a593Smuzhiyun 	/* src does not support fractional bpp implies decrement by 16 for bppx16 */
1080*4882a593Smuzhiyun 	if (!src_fractional_bpp)
1081*4882a593Smuzhiyun 		src_fractional_bpp = 1;
1082*4882a593Smuzhiyun 	bpp_decrement_x16 = DIV_ROUND_UP(16, src_fractional_bpp);
1083*4882a593Smuzhiyun 	bpp_target_x16 = bpp_target * 16;
1084*4882a593Smuzhiyun 
1085*4882a593Smuzhiyun 	while (bpp_target_x16 > (min_dsc_bpp * 16)) {
1086*4882a593Smuzhiyun 		int bpp;
1087*4882a593Smuzhiyun 
1088*4882a593Smuzhiyun 		bpp = DIV_ROUND_UP(bpp_target_x16, 16);
1089*4882a593Smuzhiyun 		target_bytes = DIV_ROUND_UP((num_slices * slice_width * bpp), 8);
1090*4882a593Smuzhiyun 		if (target_bytes <= hdmi_max_chunk_bytes) {
1091*4882a593Smuzhiyun 			bpp_found = true;
1092*4882a593Smuzhiyun 			break;
1093*4882a593Smuzhiyun 		}
1094*4882a593Smuzhiyun 		bpp_target_x16 -= bpp_decrement_x16;
1095*4882a593Smuzhiyun 	}
1096*4882a593Smuzhiyun 	if (bpp_found)
1097*4882a593Smuzhiyun 		return bpp_target_x16;
1098*4882a593Smuzhiyun 
1099*4882a593Smuzhiyun 	return 0;
1100*4882a593Smuzhiyun }
1101*4882a593Smuzhiyun 
1102*4882a593Smuzhiyun static int
dw_hdmi_dsc_bpp(struct rockchip_hdmi * hdmi,int num_slices,int slice_width)1103*4882a593Smuzhiyun dw_hdmi_dsc_bpp(struct rockchip_hdmi *hdmi,
1104*4882a593Smuzhiyun 		int num_slices, int slice_width)
1105*4882a593Smuzhiyun {
1106*4882a593Smuzhiyun 	bool hdmi_all_bpp = hdmi->dsc_cap.all_bpp;
1107*4882a593Smuzhiyun 	int fractional_bpp = 0;
1108*4882a593Smuzhiyun 	int hdmi_max_chunk_bytes = hdmi->dsc_cap.total_chunk_kbytes * 1024;
1109*4882a593Smuzhiyun 
1110*4882a593Smuzhiyun 	return hdmi_dsc_get_bpp(hdmi, fractional_bpp, slice_width,
1111*4882a593Smuzhiyun 				num_slices, hdmi_all_bpp,
1112*4882a593Smuzhiyun 				hdmi_max_chunk_bytes);
1113*4882a593Smuzhiyun }
1114*4882a593Smuzhiyun 
dw_hdmi_qp_set_link_cfg(struct rockchip_hdmi * hdmi,u16 pic_width,u16 pic_height,u16 slice_width,u16 slice_height,u16 bits_per_pixel,u8 bits_per_component)1115*4882a593Smuzhiyun static int dw_hdmi_qp_set_link_cfg(struct rockchip_hdmi *hdmi,
1116*4882a593Smuzhiyun 				   u16 pic_width, u16 pic_height,
1117*4882a593Smuzhiyun 				   u16 slice_width, u16 slice_height,
1118*4882a593Smuzhiyun 				   u16 bits_per_pixel, u8 bits_per_component)
1119*4882a593Smuzhiyun {
1120*4882a593Smuzhiyun 	int i;
1121*4882a593Smuzhiyun 
1122*4882a593Smuzhiyun 	for (i = 0; i < PPS_TABLE_LEN; i++)
1123*4882a593Smuzhiyun 		if (pic_width == pps_datas[i].pic_width &&
1124*4882a593Smuzhiyun 		    pic_height == pps_datas[i].pic_height &&
1125*4882a593Smuzhiyun 		    slice_width == pps_datas[i].slice_width &&
1126*4882a593Smuzhiyun 		    slice_height == pps_datas[i].slice_height &&
1127*4882a593Smuzhiyun 		    bits_per_component == pps_datas[i].bpc &&
1128*4882a593Smuzhiyun 		    bits_per_pixel == pps_datas[i].bpp &&
1129*4882a593Smuzhiyun 		    hdmi_bus_fmt_is_rgb(hdmi->output_bus_format) == pps_datas[i].convert_rgb)
1130*4882a593Smuzhiyun 			break;
1131*4882a593Smuzhiyun 
1132*4882a593Smuzhiyun 	if (i == PPS_TABLE_LEN) {
1133*4882a593Smuzhiyun 		dev_err(hdmi->dev, "can't find pps cfg!\n");
1134*4882a593Smuzhiyun 		return -EINVAL;
1135*4882a593Smuzhiyun 	}
1136*4882a593Smuzhiyun 
1137*4882a593Smuzhiyun 	memcpy(hdmi->link_cfg.pps_payload, pps_datas[i].raw_pps, 128);
1138*4882a593Smuzhiyun 	hdmi->link_cfg.hcactive = DIV_ROUND_UP(slice_width * (bits_per_pixel / 16), 8) *
1139*4882a593Smuzhiyun 		(pic_width / slice_width);
1140*4882a593Smuzhiyun 
1141*4882a593Smuzhiyun 	return 0;
1142*4882a593Smuzhiyun }
1143*4882a593Smuzhiyun 
dw_hdmi_qp_dsc_configure(struct rockchip_hdmi * hdmi,struct rockchip_crtc_state * s,struct drm_crtc_state * crtc_state)1144*4882a593Smuzhiyun static void dw_hdmi_qp_dsc_configure(struct rockchip_hdmi *hdmi,
1145*4882a593Smuzhiyun 				     struct rockchip_crtc_state *s,
1146*4882a593Smuzhiyun 				     struct drm_crtc_state *crtc_state)
1147*4882a593Smuzhiyun {
1148*4882a593Smuzhiyun 	int ret;
1149*4882a593Smuzhiyun 	int slice_height;
1150*4882a593Smuzhiyun 	int slice_width;
1151*4882a593Smuzhiyun 	int bits_per_pixel;
1152*4882a593Smuzhiyun 	int slice_count;
1153*4882a593Smuzhiyun 	bool hdmi_is_dsc_1_2;
1154*4882a593Smuzhiyun 	unsigned int depth = hdmi_bus_fmt_color_depth(hdmi->output_bus_format);
1155*4882a593Smuzhiyun 
1156*4882a593Smuzhiyun 	if (!crtc_state)
1157*4882a593Smuzhiyun 		return;
1158*4882a593Smuzhiyun 
1159*4882a593Smuzhiyun 	hdmi_is_dsc_1_2 = hdmi->dsc_cap.v_1p2;
1160*4882a593Smuzhiyun 
1161*4882a593Smuzhiyun 	if (!hdmi_is_dsc_1_2)
1162*4882a593Smuzhiyun 		return;
1163*4882a593Smuzhiyun 
1164*4882a593Smuzhiyun 	slice_height = hdmi_dsc_get_slice_height(crtc_state->mode.vdisplay);
1165*4882a593Smuzhiyun 	if (!slice_height)
1166*4882a593Smuzhiyun 		return;
1167*4882a593Smuzhiyun 
1168*4882a593Smuzhiyun 	slice_count = hdmi_dsc_slices(hdmi, crtc_state);
1169*4882a593Smuzhiyun 	if (!slice_count)
1170*4882a593Smuzhiyun 		return;
1171*4882a593Smuzhiyun 
1172*4882a593Smuzhiyun 	slice_width = DIV_ROUND_UP(crtc_state->mode.hdisplay, slice_count);
1173*4882a593Smuzhiyun 
1174*4882a593Smuzhiyun 	bits_per_pixel = dw_hdmi_dsc_bpp(hdmi, slice_count, slice_width);
1175*4882a593Smuzhiyun 	if (!bits_per_pixel)
1176*4882a593Smuzhiyun 		return;
1177*4882a593Smuzhiyun 
1178*4882a593Smuzhiyun 	ret = dw_hdmi_qp_set_link_cfg(hdmi, crtc_state->mode.hdisplay,
1179*4882a593Smuzhiyun 				      crtc_state->mode.vdisplay, slice_width,
1180*4882a593Smuzhiyun 				      slice_height, bits_per_pixel, depth);
1181*4882a593Smuzhiyun 
1182*4882a593Smuzhiyun 	if (ret) {
1183*4882a593Smuzhiyun 		dev_err(hdmi->dev, "set vdsc cfg failed\n");
1184*4882a593Smuzhiyun 		return;
1185*4882a593Smuzhiyun 	}
1186*4882a593Smuzhiyun 	dev_info(hdmi->dev, "dsc_enable\n");
1187*4882a593Smuzhiyun 	s->dsc_enable = 1;
1188*4882a593Smuzhiyun 	s->dsc_sink_cap.version_major = 1;
1189*4882a593Smuzhiyun 	s->dsc_sink_cap.version_minor = 2;
1190*4882a593Smuzhiyun 	s->dsc_sink_cap.slice_width = slice_width;
1191*4882a593Smuzhiyun 	s->dsc_sink_cap.slice_height = slice_height;
1192*4882a593Smuzhiyun 	s->dsc_sink_cap.target_bits_per_pixel_x16 = bits_per_pixel;
1193*4882a593Smuzhiyun 	s->dsc_sink_cap.block_pred = 1;
1194*4882a593Smuzhiyun 	s->dsc_sink_cap.native_420 = 0;
1195*4882a593Smuzhiyun 
1196*4882a593Smuzhiyun 	memcpy(&s->pps, hdmi->link_cfg.pps_payload, 128);
1197*4882a593Smuzhiyun }
1198*4882a593Smuzhiyun /////////////////////////////////////////////////////////////////////////////////////////
1199*4882a593Smuzhiyun 
rockchip_hdmi_update_phy_table(struct rockchip_hdmi * hdmi,u32 * config,int phy_table_size)1200*4882a593Smuzhiyun static int rockchip_hdmi_update_phy_table(struct rockchip_hdmi *hdmi,
1201*4882a593Smuzhiyun 					  u32 *config,
1202*4882a593Smuzhiyun 					  int phy_table_size)
1203*4882a593Smuzhiyun {
1204*4882a593Smuzhiyun 	int i;
1205*4882a593Smuzhiyun 
1206*4882a593Smuzhiyun 	if (phy_table_size > ARRAY_SIZE(rockchip_phy_config)) {
1207*4882a593Smuzhiyun 		dev_err(hdmi->dev, "phy table array number is out of range\n");
1208*4882a593Smuzhiyun 		return -E2BIG;
1209*4882a593Smuzhiyun 	}
1210*4882a593Smuzhiyun 
1211*4882a593Smuzhiyun 	for (i = 0; i < phy_table_size; i++) {
1212*4882a593Smuzhiyun 		if (config[i * 4] != 0)
1213*4882a593Smuzhiyun 			rockchip_phy_config[i].mpixelclock = (u64)config[i * 4];
1214*4882a593Smuzhiyun 		else
1215*4882a593Smuzhiyun 			rockchip_phy_config[i].mpixelclock = ~0UL;
1216*4882a593Smuzhiyun 		rockchip_phy_config[i].sym_ctr = (u16)config[i * 4 + 1];
1217*4882a593Smuzhiyun 		rockchip_phy_config[i].term = (u16)config[i * 4 + 2];
1218*4882a593Smuzhiyun 		rockchip_phy_config[i].vlev_ctr = (u16)config[i * 4 + 3];
1219*4882a593Smuzhiyun 	}
1220*4882a593Smuzhiyun 
1221*4882a593Smuzhiyun 	return 0;
1222*4882a593Smuzhiyun }
1223*4882a593Smuzhiyun 
repo_hpd_event(struct work_struct * p_work)1224*4882a593Smuzhiyun static void repo_hpd_event(struct work_struct *p_work)
1225*4882a593Smuzhiyun {
1226*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = container_of(p_work, struct rockchip_hdmi, work.work);
1227*4882a593Smuzhiyun 	bool change;
1228*4882a593Smuzhiyun 
1229*4882a593Smuzhiyun 	change = drm_helper_hpd_irq_event(hdmi->drm_dev);
1230*4882a593Smuzhiyun 	if (change) {
1231*4882a593Smuzhiyun 		dev_dbg(hdmi->dev, "hpd stat changed:%d\n", hdmi->hpd_stat);
1232*4882a593Smuzhiyun 		dw_hdmi_qp_cec_set_hpd(hdmi->hdmi_qp, hdmi->hpd_stat, change);
1233*4882a593Smuzhiyun 	}
1234*4882a593Smuzhiyun }
1235*4882a593Smuzhiyun 
rockchip_hdmi_hardirq(int irq,void * dev_id)1236*4882a593Smuzhiyun static irqreturn_t rockchip_hdmi_hardirq(int irq, void *dev_id)
1237*4882a593Smuzhiyun {
1238*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = dev_id;
1239*4882a593Smuzhiyun 	u32 intr_stat, val;
1240*4882a593Smuzhiyun 
1241*4882a593Smuzhiyun 	regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
1242*4882a593Smuzhiyun 
1243*4882a593Smuzhiyun 	if (intr_stat) {
1244*4882a593Smuzhiyun 		dev_dbg(hdmi->dev, "hpd irq %#x\n", intr_stat);
1245*4882a593Smuzhiyun 
1246*4882a593Smuzhiyun 		if (!hdmi->id)
1247*4882a593Smuzhiyun 			val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK,
1248*4882a593Smuzhiyun 					    RK3588_HDMI0_HPD_INT_MSK);
1249*4882a593Smuzhiyun 		else
1250*4882a593Smuzhiyun 			val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_MSK,
1251*4882a593Smuzhiyun 					    RK3588_HDMI1_HPD_INT_MSK);
1252*4882a593Smuzhiyun 		regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
1253*4882a593Smuzhiyun 		return IRQ_WAKE_THREAD;
1254*4882a593Smuzhiyun 	}
1255*4882a593Smuzhiyun 
1256*4882a593Smuzhiyun 	return IRQ_NONE;
1257*4882a593Smuzhiyun }
1258*4882a593Smuzhiyun 
rockchip_hdmi_irq(int irq,void * dev_id)1259*4882a593Smuzhiyun static irqreturn_t rockchip_hdmi_irq(int irq, void *dev_id)
1260*4882a593Smuzhiyun {
1261*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = dev_id;
1262*4882a593Smuzhiyun 	u32 intr_stat, val;
1263*4882a593Smuzhiyun 	int msecs;
1264*4882a593Smuzhiyun 	bool stat;
1265*4882a593Smuzhiyun 
1266*4882a593Smuzhiyun 	regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
1267*4882a593Smuzhiyun 
1268*4882a593Smuzhiyun 	if (!intr_stat)
1269*4882a593Smuzhiyun 		return IRQ_NONE;
1270*4882a593Smuzhiyun 
1271*4882a593Smuzhiyun 	if (!hdmi->id) {
1272*4882a593Smuzhiyun 		val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR,
1273*4882a593Smuzhiyun 				    RK3588_HDMI0_HPD_INT_CLR);
1274*4882a593Smuzhiyun 		if (intr_stat & RK3588_HDMI0_LEVEL_INT)
1275*4882a593Smuzhiyun 			stat = true;
1276*4882a593Smuzhiyun 		else
1277*4882a593Smuzhiyun 			stat = false;
1278*4882a593Smuzhiyun 	} else {
1279*4882a593Smuzhiyun 		val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_CLR,
1280*4882a593Smuzhiyun 				    RK3588_HDMI1_HPD_INT_CLR);
1281*4882a593Smuzhiyun 		if (intr_stat & RK3588_HDMI1_LEVEL_INT)
1282*4882a593Smuzhiyun 			stat = true;
1283*4882a593Smuzhiyun 		else
1284*4882a593Smuzhiyun 			stat = false;
1285*4882a593Smuzhiyun 	}
1286*4882a593Smuzhiyun 
1287*4882a593Smuzhiyun 	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
1288*4882a593Smuzhiyun 
1289*4882a593Smuzhiyun 	if (stat) {
1290*4882a593Smuzhiyun 		hdmi->hpd_stat = true;
1291*4882a593Smuzhiyun 		msecs = 150;
1292*4882a593Smuzhiyun 	} else {
1293*4882a593Smuzhiyun 		hdmi->hpd_stat = false;
1294*4882a593Smuzhiyun 		msecs = 20;
1295*4882a593Smuzhiyun 	}
1296*4882a593Smuzhiyun 	mod_delayed_work(hdmi->workqueue, &hdmi->work, msecs_to_jiffies(msecs));
1297*4882a593Smuzhiyun 
1298*4882a593Smuzhiyun 	if (!hdmi->id) {
1299*4882a593Smuzhiyun 		val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR,
1300*4882a593Smuzhiyun 				    RK3588_HDMI0_HPD_INT_CLR) |
1301*4882a593Smuzhiyun 		      HIWORD_UPDATE(0, RK3588_HDMI0_HPD_INT_MSK);
1302*4882a593Smuzhiyun 	} else {
1303*4882a593Smuzhiyun 		val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_CLR,
1304*4882a593Smuzhiyun 				    RK3588_HDMI1_HPD_INT_CLR) |
1305*4882a593Smuzhiyun 		      HIWORD_UPDATE(0, RK3588_HDMI1_HPD_INT_MSK);
1306*4882a593Smuzhiyun 	}
1307*4882a593Smuzhiyun 
1308*4882a593Smuzhiyun 	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
1309*4882a593Smuzhiyun 
1310*4882a593Smuzhiyun 	return IRQ_HANDLED;
1311*4882a593Smuzhiyun }
1312*4882a593Smuzhiyun 
init_hpd_work(struct rockchip_hdmi * hdmi)1313*4882a593Smuzhiyun static void init_hpd_work(struct rockchip_hdmi *hdmi)
1314*4882a593Smuzhiyun {
1315*4882a593Smuzhiyun 	hdmi->workqueue = create_workqueue("hpd_queue");
1316*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&hdmi->work, repo_hpd_event);
1317*4882a593Smuzhiyun }
1318*4882a593Smuzhiyun 
rockchip_hdmi_hpd_irq_handler(int irq,void * arg)1319*4882a593Smuzhiyun static irqreturn_t rockchip_hdmi_hpd_irq_handler(int irq, void *arg)
1320*4882a593Smuzhiyun {
1321*4882a593Smuzhiyun 	u32 val;
1322*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = arg;
1323*4882a593Smuzhiyun 
1324*4882a593Smuzhiyun 	val = gpiod_get_value(hdmi->hpd_gpiod);
1325*4882a593Smuzhiyun 	if (val) {
1326*4882a593Smuzhiyun 		val = HIWORD_UPDATE(RK3528_HDMI_SNKDET, RK3528_HDMI_SNKDET);
1327*4882a593Smuzhiyun 		if (hdmi->hdmi && hdmi->hpd_wake_en && hdmi->hpd_gpiod)
1328*4882a593Smuzhiyun 			dw_hdmi_set_hpd_wake(hdmi->hdmi);
1329*4882a593Smuzhiyun 	} else {
1330*4882a593Smuzhiyun 		val = HIWORD_UPDATE(0, RK3528_HDMI_SNKDET);
1331*4882a593Smuzhiyun 	}
1332*4882a593Smuzhiyun 	regmap_write(hdmi->regmap, RK3528_VO_GRF_HDMI_MASK, val);
1333*4882a593Smuzhiyun 
1334*4882a593Smuzhiyun 	return IRQ_HANDLED;
1335*4882a593Smuzhiyun }
1336*4882a593Smuzhiyun 
dw_hdmi_rk3528_gpio_hpd_init(struct rockchip_hdmi * hdmi)1337*4882a593Smuzhiyun static void dw_hdmi_rk3528_gpio_hpd_init(struct rockchip_hdmi *hdmi)
1338*4882a593Smuzhiyun {
1339*4882a593Smuzhiyun 	u32 val;
1340*4882a593Smuzhiyun 
1341*4882a593Smuzhiyun 	if (hdmi->hpd_gpiod) {
1342*4882a593Smuzhiyun 		/* gpio0_a2's input enable is controlled by gpio output data bit */
1343*4882a593Smuzhiyun 		val = HIWORD_UPDATE(RK3528_GPIO0_A2_DR, RK3528_GPIO0_A2_DR);
1344*4882a593Smuzhiyun 		writel(val, hdmi->gpio_base + RK3528_GPIO_SWPORT_DR_L);
1345*4882a593Smuzhiyun 
1346*4882a593Smuzhiyun 		val = HIWORD_UPDATE(RK3528_HDMI_SNKDET_SEL | RK3528_HDMI_SDAIN_MSK |
1347*4882a593Smuzhiyun 				    RK3528_HDMI_SCLIN_MSK,
1348*4882a593Smuzhiyun 				    RK3528_HDMI_SNKDET_SEL | RK3528_HDMI_SDAIN_MSK |
1349*4882a593Smuzhiyun 				    RK3528_HDMI_SCLIN_MSK);
1350*4882a593Smuzhiyun 	} else {
1351*4882a593Smuzhiyun 		val = HIWORD_UPDATE(RK3528_HDMI_SDAIN_MSK | RK3528_HDMI_SCLIN_MSK,
1352*4882a593Smuzhiyun 				    RK3528_HDMI_SDAIN_MSK | RK3528_HDMI_SCLIN_MSK);
1353*4882a593Smuzhiyun 	}
1354*4882a593Smuzhiyun 
1355*4882a593Smuzhiyun 	regmap_write(hdmi->regmap, RK3528_VO_GRF_HDMI_MASK, val);
1356*4882a593Smuzhiyun 
1357*4882a593Smuzhiyun 	val = gpiod_get_value(hdmi->hpd_gpiod);
1358*4882a593Smuzhiyun 	if (val) {
1359*4882a593Smuzhiyun 		val = HIWORD_UPDATE(RK3528_HDMI_SNKDET, RK3528_HDMI_SNKDET);
1360*4882a593Smuzhiyun 		if (hdmi->hdmi && hdmi->hpd_wake_en && hdmi->hpd_gpiod)
1361*4882a593Smuzhiyun 			dw_hdmi_set_hpd_wake(hdmi->hdmi);
1362*4882a593Smuzhiyun 	} else {
1363*4882a593Smuzhiyun 		val = HIWORD_UPDATE(0, RK3528_HDMI_SNKDET);
1364*4882a593Smuzhiyun 	}
1365*4882a593Smuzhiyun 	regmap_write(hdmi->regmap, RK3528_VO_GRF_HDMI_MASK, val);
1366*4882a593Smuzhiyun }
1367*4882a593Smuzhiyun 
rockchip_hdmi_parse_dt(struct rockchip_hdmi * hdmi)1368*4882a593Smuzhiyun static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
1369*4882a593Smuzhiyun {
1370*4882a593Smuzhiyun 	int ret, val, phy_table_size;
1371*4882a593Smuzhiyun 	u32 *phy_config;
1372*4882a593Smuzhiyun 	struct device_node *np = hdmi->dev->of_node;
1373*4882a593Smuzhiyun 
1374*4882a593Smuzhiyun 	hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
1375*4882a593Smuzhiyun 	if (IS_ERR(hdmi->regmap)) {
1376*4882a593Smuzhiyun 		DRM_DEV_ERROR(hdmi->dev, "Unable to get rockchip,grf\n");
1377*4882a593Smuzhiyun 		return PTR_ERR(hdmi->regmap);
1378*4882a593Smuzhiyun 	}
1379*4882a593Smuzhiyun 
1380*4882a593Smuzhiyun 	if (hdmi->is_hdmi_qp) {
1381*4882a593Smuzhiyun 		hdmi->vo1_regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,vo1_grf");
1382*4882a593Smuzhiyun 		if (IS_ERR(hdmi->vo1_regmap)) {
1383*4882a593Smuzhiyun 			DRM_DEV_ERROR(hdmi->dev, "Unable to get rockchip,vo1_grf\n");
1384*4882a593Smuzhiyun 			return PTR_ERR(hdmi->vo1_regmap);
1385*4882a593Smuzhiyun 		}
1386*4882a593Smuzhiyun 	}
1387*4882a593Smuzhiyun 
1388*4882a593Smuzhiyun 	hdmi->phyref_clk = devm_clk_get(hdmi->dev, "vpll");
1389*4882a593Smuzhiyun 	if (PTR_ERR(hdmi->phyref_clk) == -ENOENT)
1390*4882a593Smuzhiyun 		hdmi->phyref_clk = devm_clk_get(hdmi->dev, "ref");
1391*4882a593Smuzhiyun 
1392*4882a593Smuzhiyun 	if (PTR_ERR(hdmi->phyref_clk) == -ENOENT) {
1393*4882a593Smuzhiyun 		hdmi->phyref_clk = NULL;
1394*4882a593Smuzhiyun 	} else if (PTR_ERR(hdmi->phyref_clk) == -EPROBE_DEFER) {
1395*4882a593Smuzhiyun 		return -EPROBE_DEFER;
1396*4882a593Smuzhiyun 	} else if (IS_ERR(hdmi->phyref_clk)) {
1397*4882a593Smuzhiyun 		DRM_DEV_ERROR(hdmi->dev, "failed to get grf clock\n");
1398*4882a593Smuzhiyun 		return PTR_ERR(hdmi->phyref_clk);
1399*4882a593Smuzhiyun 	}
1400*4882a593Smuzhiyun 
1401*4882a593Smuzhiyun 	hdmi->grf_clk = devm_clk_get(hdmi->dev, "grf");
1402*4882a593Smuzhiyun 	if (PTR_ERR(hdmi->grf_clk) == -ENOENT) {
1403*4882a593Smuzhiyun 		hdmi->grf_clk = NULL;
1404*4882a593Smuzhiyun 	} else if (PTR_ERR(hdmi->grf_clk) == -EPROBE_DEFER) {
1405*4882a593Smuzhiyun 		return -EPROBE_DEFER;
1406*4882a593Smuzhiyun 	} else if (IS_ERR(hdmi->grf_clk)) {
1407*4882a593Smuzhiyun 		DRM_DEV_ERROR(hdmi->dev, "failed to get grf clock\n");
1408*4882a593Smuzhiyun 		return PTR_ERR(hdmi->grf_clk);
1409*4882a593Smuzhiyun 	}
1410*4882a593Smuzhiyun 
1411*4882a593Smuzhiyun 	hdmi->hclk_vio = devm_clk_get(hdmi->dev, "hclk_vio");
1412*4882a593Smuzhiyun 	if (PTR_ERR(hdmi->hclk_vio) == -ENOENT) {
1413*4882a593Smuzhiyun 		hdmi->hclk_vio = NULL;
1414*4882a593Smuzhiyun 	} else if (PTR_ERR(hdmi->hclk_vio) == -EPROBE_DEFER) {
1415*4882a593Smuzhiyun 		return -EPROBE_DEFER;
1416*4882a593Smuzhiyun 	} else if (IS_ERR(hdmi->hclk_vio)) {
1417*4882a593Smuzhiyun 		dev_err(hdmi->dev, "failed to get hclk_vio clock\n");
1418*4882a593Smuzhiyun 		return PTR_ERR(hdmi->hclk_vio);
1419*4882a593Smuzhiyun 	}
1420*4882a593Smuzhiyun 
1421*4882a593Smuzhiyun 	hdmi->hclk_vop = devm_clk_get(hdmi->dev, "hclk");
1422*4882a593Smuzhiyun 	if (PTR_ERR(hdmi->hclk_vop) == -ENOENT) {
1423*4882a593Smuzhiyun 		hdmi->hclk_vop = NULL;
1424*4882a593Smuzhiyun 	} else if (PTR_ERR(hdmi->hclk_vop) == -EPROBE_DEFER) {
1425*4882a593Smuzhiyun 		return -EPROBE_DEFER;
1426*4882a593Smuzhiyun 	} else if (IS_ERR(hdmi->hclk_vop)) {
1427*4882a593Smuzhiyun 		dev_err(hdmi->dev, "failed to get hclk_vop clock\n");
1428*4882a593Smuzhiyun 		return PTR_ERR(hdmi->hclk_vop);
1429*4882a593Smuzhiyun 	}
1430*4882a593Smuzhiyun 
1431*4882a593Smuzhiyun 	hdmi->aud_clk = devm_clk_get_optional(hdmi->dev, "aud");
1432*4882a593Smuzhiyun 	if (IS_ERR(hdmi->aud_clk)) {
1433*4882a593Smuzhiyun 		dev_err_probe(hdmi->dev, PTR_ERR(hdmi->aud_clk),
1434*4882a593Smuzhiyun 			      "failed to get aud_clk clock\n");
1435*4882a593Smuzhiyun 		return PTR_ERR(hdmi->aud_clk);
1436*4882a593Smuzhiyun 	}
1437*4882a593Smuzhiyun 
1438*4882a593Smuzhiyun 	hdmi->hpd_clk = devm_clk_get_optional(hdmi->dev, "hpd");
1439*4882a593Smuzhiyun 	if (IS_ERR(hdmi->hpd_clk)) {
1440*4882a593Smuzhiyun 		dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hpd_clk),
1441*4882a593Smuzhiyun 			      "failed to get hpd_clk clock\n");
1442*4882a593Smuzhiyun 		return PTR_ERR(hdmi->hpd_clk);
1443*4882a593Smuzhiyun 	}
1444*4882a593Smuzhiyun 
1445*4882a593Smuzhiyun 	hdmi->hclk_vo1 = devm_clk_get_optional(hdmi->dev, "hclk_vo1");
1446*4882a593Smuzhiyun 	if (IS_ERR(hdmi->hclk_vo1)) {
1447*4882a593Smuzhiyun 		dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hclk_vo1),
1448*4882a593Smuzhiyun 			      "failed to get hclk_vo1 clock\n");
1449*4882a593Smuzhiyun 		return PTR_ERR(hdmi->hclk_vo1);
1450*4882a593Smuzhiyun 	}
1451*4882a593Smuzhiyun 
1452*4882a593Smuzhiyun 	hdmi->earc_clk = devm_clk_get_optional(hdmi->dev, "earc");
1453*4882a593Smuzhiyun 	if (IS_ERR(hdmi->earc_clk)) {
1454*4882a593Smuzhiyun 		dev_err_probe(hdmi->dev, PTR_ERR(hdmi->earc_clk),
1455*4882a593Smuzhiyun 			      "failed to get earc_clk clock\n");
1456*4882a593Smuzhiyun 		return PTR_ERR(hdmi->earc_clk);
1457*4882a593Smuzhiyun 	}
1458*4882a593Smuzhiyun 
1459*4882a593Smuzhiyun 	hdmi->hdmitx_ref = devm_clk_get_optional(hdmi->dev, "hdmitx_ref");
1460*4882a593Smuzhiyun 	if (IS_ERR(hdmi->hdmitx_ref)) {
1461*4882a593Smuzhiyun 		dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hdmitx_ref),
1462*4882a593Smuzhiyun 			      "failed to get hdmitx_ref clock\n");
1463*4882a593Smuzhiyun 		return PTR_ERR(hdmi->hdmitx_ref);
1464*4882a593Smuzhiyun 	}
1465*4882a593Smuzhiyun 
1466*4882a593Smuzhiyun 	hdmi->pclk = devm_clk_get_optional(hdmi->dev, "pclk");
1467*4882a593Smuzhiyun 	if (IS_ERR(hdmi->pclk)) {
1468*4882a593Smuzhiyun 		dev_err_probe(hdmi->dev, PTR_ERR(hdmi->pclk),
1469*4882a593Smuzhiyun 			      "failed to get pclk clock\n");
1470*4882a593Smuzhiyun 		return PTR_ERR(hdmi->pclk);
1471*4882a593Smuzhiyun 	}
1472*4882a593Smuzhiyun 
1473*4882a593Smuzhiyun 	hdmi->link_clk = devm_clk_get_optional(hdmi->dev, "link_clk");
1474*4882a593Smuzhiyun 	if (IS_ERR(hdmi->link_clk)) {
1475*4882a593Smuzhiyun 		dev_err_probe(hdmi->dev, PTR_ERR(hdmi->link_clk),
1476*4882a593Smuzhiyun 			      "failed to get link_clk clock\n");
1477*4882a593Smuzhiyun 		return PTR_ERR(hdmi->link_clk);
1478*4882a593Smuzhiyun 	}
1479*4882a593Smuzhiyun 
1480*4882a593Smuzhiyun 	hdmi->enable_gpio = devm_gpiod_get_optional(hdmi->dev, "enable",
1481*4882a593Smuzhiyun 						    GPIOD_OUT_HIGH);
1482*4882a593Smuzhiyun 	if (IS_ERR(hdmi->enable_gpio)) {
1483*4882a593Smuzhiyun 		ret = PTR_ERR(hdmi->enable_gpio);
1484*4882a593Smuzhiyun 		dev_err(hdmi->dev, "failed to request enable GPIO: %d\n", ret);
1485*4882a593Smuzhiyun 		return ret;
1486*4882a593Smuzhiyun 	}
1487*4882a593Smuzhiyun 
1488*4882a593Smuzhiyun 	hdmi->skip_check_420_mode =
1489*4882a593Smuzhiyun 		of_property_read_bool(np, "skip-check-420-mode");
1490*4882a593Smuzhiyun 
1491*4882a593Smuzhiyun 	if (of_get_property(np, "rockchip,phy-table", &val)) {
1492*4882a593Smuzhiyun 		phy_config = kmalloc(val, GFP_KERNEL);
1493*4882a593Smuzhiyun 		if (!phy_config) {
1494*4882a593Smuzhiyun 			/* use default table when kmalloc failed. */
1495*4882a593Smuzhiyun 			dev_err(hdmi->dev, "kmalloc phy table failed\n");
1496*4882a593Smuzhiyun 
1497*4882a593Smuzhiyun 			return -ENOMEM;
1498*4882a593Smuzhiyun 		}
1499*4882a593Smuzhiyun 		phy_table_size = val / 16;
1500*4882a593Smuzhiyun 		of_property_read_u32_array(np, "rockchip,phy-table",
1501*4882a593Smuzhiyun 					   phy_config, val / sizeof(u32));
1502*4882a593Smuzhiyun 		ret = rockchip_hdmi_update_phy_table(hdmi, phy_config,
1503*4882a593Smuzhiyun 						     phy_table_size);
1504*4882a593Smuzhiyun 		if (ret) {
1505*4882a593Smuzhiyun 			kfree(phy_config);
1506*4882a593Smuzhiyun 			return ret;
1507*4882a593Smuzhiyun 		}
1508*4882a593Smuzhiyun 		kfree(phy_config);
1509*4882a593Smuzhiyun 	} else {
1510*4882a593Smuzhiyun 		dev_dbg(hdmi->dev, "use default hdmi phy table\n");
1511*4882a593Smuzhiyun 	}
1512*4882a593Smuzhiyun 
1513*4882a593Smuzhiyun 	hdmi->hpd_gpiod = devm_gpiod_get_optional(hdmi->dev, "hpd", GPIOD_IN);
1514*4882a593Smuzhiyun 
1515*4882a593Smuzhiyun 	if (IS_ERR(hdmi->hpd_gpiod)) {
1516*4882a593Smuzhiyun 		dev_err(hdmi->dev, "error getting HDP GPIO: %ld\n",
1517*4882a593Smuzhiyun 			PTR_ERR(hdmi->hpd_gpiod));
1518*4882a593Smuzhiyun 		return PTR_ERR(hdmi->hpd_gpiod);
1519*4882a593Smuzhiyun 	}
1520*4882a593Smuzhiyun 
1521*4882a593Smuzhiyun 	if (hdmi->hpd_gpiod) {
1522*4882a593Smuzhiyun 		struct resource *res;
1523*4882a593Smuzhiyun 		struct platform_device *pdev = to_platform_device(hdmi->dev);
1524*4882a593Smuzhiyun 
1525*4882a593Smuzhiyun 		/* gpio interrupt reflects hpd status */
1526*4882a593Smuzhiyun 		hdmi->hpd_irq = gpiod_to_irq(hdmi->hpd_gpiod);
1527*4882a593Smuzhiyun 		if (hdmi->hpd_irq < 0)
1528*4882a593Smuzhiyun 			return -EINVAL;
1529*4882a593Smuzhiyun 
1530*4882a593Smuzhiyun 		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
1531*4882a593Smuzhiyun 		if (!res) {
1532*4882a593Smuzhiyun 			DRM_DEV_ERROR(hdmi->dev, "failed to get gpio regs\n");
1533*4882a593Smuzhiyun 			return -EINVAL;
1534*4882a593Smuzhiyun 		}
1535*4882a593Smuzhiyun 
1536*4882a593Smuzhiyun 		hdmi->gpio_base = devm_ioremap(hdmi->dev, res->start, resource_size(res));
1537*4882a593Smuzhiyun 		if (IS_ERR(hdmi->gpio_base)) {
1538*4882a593Smuzhiyun 			DRM_DEV_ERROR(hdmi->dev, "Unable to get gpio ioregmap\n");
1539*4882a593Smuzhiyun 			return PTR_ERR(hdmi->gpio_base);
1540*4882a593Smuzhiyun 		}
1541*4882a593Smuzhiyun 
1542*4882a593Smuzhiyun 		dw_hdmi_rk3528_gpio_hpd_init(hdmi);
1543*4882a593Smuzhiyun 		ret = devm_request_threaded_irq(hdmi->dev, hdmi->hpd_irq, NULL,
1544*4882a593Smuzhiyun 						rockchip_hdmi_hpd_irq_handler,
1545*4882a593Smuzhiyun 						IRQF_TRIGGER_RISING |
1546*4882a593Smuzhiyun 						IRQF_TRIGGER_FALLING |
1547*4882a593Smuzhiyun 						IRQF_ONESHOT,
1548*4882a593Smuzhiyun 						"hdmi-hpd", hdmi);
1549*4882a593Smuzhiyun 		if (ret) {
1550*4882a593Smuzhiyun 			dev_err(hdmi->dev, "failed to request hpd IRQ: %d\n", ret);
1551*4882a593Smuzhiyun 			return ret;
1552*4882a593Smuzhiyun 		}
1553*4882a593Smuzhiyun 
1554*4882a593Smuzhiyun 		hdmi->hpd_wake_en = device_property_read_bool(hdmi->dev, "hpd-wake-up");
1555*4882a593Smuzhiyun 		if (hdmi->hpd_wake_en)
1556*4882a593Smuzhiyun 			enable_irq_wake(hdmi->hpd_irq);
1557*4882a593Smuzhiyun 	}
1558*4882a593Smuzhiyun 
1559*4882a593Smuzhiyun 	hdmi->p = devm_pinctrl_get(hdmi->dev);
1560*4882a593Smuzhiyun 	if (IS_ERR(hdmi->p)) {
1561*4882a593Smuzhiyun 		dev_err(hdmi->dev, "could not get pinctrl\n");
1562*4882a593Smuzhiyun 		return PTR_ERR(hdmi->p);
1563*4882a593Smuzhiyun 	}
1564*4882a593Smuzhiyun 
1565*4882a593Smuzhiyun 	hdmi->idle_state = pinctrl_lookup_state(hdmi->p, "idle");
1566*4882a593Smuzhiyun 	if (IS_ERR(hdmi->idle_state)) {
1567*4882a593Smuzhiyun 		dev_dbg(hdmi->dev, "idle state is not defined\n");
1568*4882a593Smuzhiyun 		return 0;
1569*4882a593Smuzhiyun 	}
1570*4882a593Smuzhiyun 
1571*4882a593Smuzhiyun 	hdmi->default_state = pinctrl_lookup_state(hdmi->p, "default");
1572*4882a593Smuzhiyun 	if (IS_ERR(hdmi->default_state)) {
1573*4882a593Smuzhiyun 		dev_err(hdmi->dev, "could not find default state\n");
1574*4882a593Smuzhiyun 		return PTR_ERR(hdmi->default_state);
1575*4882a593Smuzhiyun 	}
1576*4882a593Smuzhiyun 
1577*4882a593Smuzhiyun 	return 0;
1578*4882a593Smuzhiyun }
1579*4882a593Smuzhiyun 
1580*4882a593Smuzhiyun static enum drm_mode_status
dw_hdmi_rockchip_mode_valid(struct dw_hdmi * dw_hdmi,void * data,const struct drm_display_info * info,const struct drm_display_mode * mode)1581*4882a593Smuzhiyun dw_hdmi_rockchip_mode_valid(struct dw_hdmi *dw_hdmi, void *data,
1582*4882a593Smuzhiyun 			    const struct drm_display_info *info,
1583*4882a593Smuzhiyun 			    const struct drm_display_mode *mode)
1584*4882a593Smuzhiyun {
1585*4882a593Smuzhiyun 	struct drm_connector *connector = container_of(info, struct drm_connector, display_info);
1586*4882a593Smuzhiyun 	struct drm_encoder *encoder = connector->encoder;
1587*4882a593Smuzhiyun 	enum drm_mode_status status = MODE_OK;
1588*4882a593Smuzhiyun 	struct drm_device *dev = connector->dev;
1589*4882a593Smuzhiyun 	struct rockchip_drm_private *priv = dev->dev_private;
1590*4882a593Smuzhiyun 	struct drm_crtc *crtc;
1591*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi;
1592*4882a593Smuzhiyun 
1593*4882a593Smuzhiyun 	/*
1594*4882a593Smuzhiyun 	 * Pixel clocks we support are always < 2GHz and so fit in an
1595*4882a593Smuzhiyun 	 * int.  We should make sure source rate does too so we don't get
1596*4882a593Smuzhiyun 	 * overflow when we multiply by 1000.
1597*4882a593Smuzhiyun 	 */
1598*4882a593Smuzhiyun 	if (mode->clock > INT_MAX / 1000)
1599*4882a593Smuzhiyun 		return MODE_BAD;
1600*4882a593Smuzhiyun 
1601*4882a593Smuzhiyun 	if (!encoder) {
1602*4882a593Smuzhiyun 		const struct drm_connector_helper_funcs *funcs;
1603*4882a593Smuzhiyun 
1604*4882a593Smuzhiyun 		funcs = connector->helper_private;
1605*4882a593Smuzhiyun 		if (funcs->atomic_best_encoder)
1606*4882a593Smuzhiyun 			encoder = funcs->atomic_best_encoder(connector,
1607*4882a593Smuzhiyun 							     connector->state);
1608*4882a593Smuzhiyun 		else
1609*4882a593Smuzhiyun 			encoder = funcs->best_encoder(connector);
1610*4882a593Smuzhiyun 	}
1611*4882a593Smuzhiyun 
1612*4882a593Smuzhiyun 	if (!encoder || !encoder->possible_crtcs)
1613*4882a593Smuzhiyun 		return MODE_BAD;
1614*4882a593Smuzhiyun 
1615*4882a593Smuzhiyun 	hdmi = to_rockchip_hdmi(encoder);
1616*4882a593Smuzhiyun 
1617*4882a593Smuzhiyun 	/*
1618*4882a593Smuzhiyun 	 * If sink max TMDS clock < 340MHz, we should check the mode pixel
1619*4882a593Smuzhiyun 	 * clock > 340MHz is YCbCr420 or not and whether the platform supports
1620*4882a593Smuzhiyun 	 * YCbCr420.
1621*4882a593Smuzhiyun 	 */
1622*4882a593Smuzhiyun 	if (!hdmi->skip_check_420_mode) {
1623*4882a593Smuzhiyun 		if (mode->clock > 340000 &&
1624*4882a593Smuzhiyun 		    connector->display_info.max_tmds_clock < 340000 &&
1625*4882a593Smuzhiyun 		    (!drm_mode_is_420(&connector->display_info, mode) ||
1626*4882a593Smuzhiyun 		     !connector->ycbcr_420_allowed))
1627*4882a593Smuzhiyun 			return MODE_BAD;
1628*4882a593Smuzhiyun 
1629*4882a593Smuzhiyun 		if (hdmi->max_tmdsclk <= 340000 && mode->clock > 340000 &&
1630*4882a593Smuzhiyun 		    !drm_mode_is_420(&connector->display_info, mode))
1631*4882a593Smuzhiyun 			return MODE_BAD;
1632*4882a593Smuzhiyun 	};
1633*4882a593Smuzhiyun 
1634*4882a593Smuzhiyun 	if (hdmi->phy) {
1635*4882a593Smuzhiyun 		if (hdmi->is_hdmi_qp)
1636*4882a593Smuzhiyun 			phy_set_bus_width(hdmi->phy, mode->clock * 10);
1637*4882a593Smuzhiyun 		else
1638*4882a593Smuzhiyun 			phy_set_bus_width(hdmi->phy, 8);
1639*4882a593Smuzhiyun 	}
1640*4882a593Smuzhiyun 
1641*4882a593Smuzhiyun 	/*
1642*4882a593Smuzhiyun 	 * ensure all drm display mode can work, if someone want support more
1643*4882a593Smuzhiyun 	 * resolutions, please limit the possible_crtc, only connect to
1644*4882a593Smuzhiyun 	 * needed crtc.
1645*4882a593Smuzhiyun 	 */
1646*4882a593Smuzhiyun 	drm_for_each_crtc(crtc, connector->dev) {
1647*4882a593Smuzhiyun 		int pipe = drm_crtc_index(crtc);
1648*4882a593Smuzhiyun 		const struct rockchip_crtc_funcs *funcs =
1649*4882a593Smuzhiyun 						priv->crtc_funcs[pipe];
1650*4882a593Smuzhiyun 
1651*4882a593Smuzhiyun 		if (!(encoder->possible_crtcs & drm_crtc_mask(crtc)))
1652*4882a593Smuzhiyun 			continue;
1653*4882a593Smuzhiyun 		if (!funcs || !funcs->mode_valid)
1654*4882a593Smuzhiyun 			continue;
1655*4882a593Smuzhiyun 
1656*4882a593Smuzhiyun 		status = funcs->mode_valid(crtc, mode,
1657*4882a593Smuzhiyun 					   DRM_MODE_CONNECTOR_HDMIA);
1658*4882a593Smuzhiyun 		if (status != MODE_OK)
1659*4882a593Smuzhiyun 			return status;
1660*4882a593Smuzhiyun 	}
1661*4882a593Smuzhiyun 
1662*4882a593Smuzhiyun 	return status;
1663*4882a593Smuzhiyun }
1664*4882a593Smuzhiyun 
dw_hdmi_rockchip_encoder_disable(struct drm_encoder * encoder)1665*4882a593Smuzhiyun static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder)
1666*4882a593Smuzhiyun {
1667*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
1668*4882a593Smuzhiyun 	struct drm_crtc *crtc = encoder->crtc;
1669*4882a593Smuzhiyun 	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state);
1670*4882a593Smuzhiyun 
1671*4882a593Smuzhiyun 	if (WARN_ON(!crtc || !crtc->state))
1672*4882a593Smuzhiyun 		return;
1673*4882a593Smuzhiyun 
1674*4882a593Smuzhiyun 	if (crtc->state->active_changed) {
1675*4882a593Smuzhiyun 		if (hdmi->plat_data->split_mode) {
1676*4882a593Smuzhiyun 			s->output_if &= ~(VOP_OUTPUT_IF_HDMI0 | VOP_OUTPUT_IF_HDMI1);
1677*4882a593Smuzhiyun 		} else {
1678*4882a593Smuzhiyun 			if (!hdmi->id)
1679*4882a593Smuzhiyun 				s->output_if &= ~VOP_OUTPUT_IF_HDMI0;
1680*4882a593Smuzhiyun 			else
1681*4882a593Smuzhiyun 				s->output_if &= ~VOP_OUTPUT_IF_HDMI1;
1682*4882a593Smuzhiyun 		}
1683*4882a593Smuzhiyun 	}
1684*4882a593Smuzhiyun 	/*
1685*4882a593Smuzhiyun 	 * when plug out hdmi it will be switch cvbs and then phy bus width
1686*4882a593Smuzhiyun 	 * must be set as 8
1687*4882a593Smuzhiyun 	 */
1688*4882a593Smuzhiyun 	if (hdmi->phy)
1689*4882a593Smuzhiyun 		phy_set_bus_width(hdmi->phy, 8);
1690*4882a593Smuzhiyun }
1691*4882a593Smuzhiyun 
dw_hdmi_rockchip_encoder_enable(struct drm_encoder * encoder)1692*4882a593Smuzhiyun static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
1693*4882a593Smuzhiyun {
1694*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
1695*4882a593Smuzhiyun 	struct drm_crtc *crtc = encoder->crtc;
1696*4882a593Smuzhiyun 	u32 val;
1697*4882a593Smuzhiyun 	int mux;
1698*4882a593Smuzhiyun 	int ret;
1699*4882a593Smuzhiyun 
1700*4882a593Smuzhiyun 	if (WARN_ON(!crtc || !crtc->state))
1701*4882a593Smuzhiyun 		return;
1702*4882a593Smuzhiyun 
1703*4882a593Smuzhiyun 	if (hdmi->phy)
1704*4882a593Smuzhiyun 		phy_set_bus_width(hdmi->phy, hdmi->phy_bus_width);
1705*4882a593Smuzhiyun 
1706*4882a593Smuzhiyun 	clk_set_rate(hdmi->phyref_clk,
1707*4882a593Smuzhiyun 		     crtc->state->adjusted_mode.crtc_clock * 1000);
1708*4882a593Smuzhiyun 
1709*4882a593Smuzhiyun 	if (hdmi->is_hdmi_qp) {
1710*4882a593Smuzhiyun 		if (hdmi->link_cfg.frl_mode)
1711*4882a593Smuzhiyun 			gpiod_set_value(hdmi->enable_gpio, 0);
1712*4882a593Smuzhiyun 		else
1713*4882a593Smuzhiyun 			gpiod_set_value(hdmi->enable_gpio, 1);
1714*4882a593Smuzhiyun 	}
1715*4882a593Smuzhiyun 
1716*4882a593Smuzhiyun 	if (hdmi->chip_data->lcdsel_grf_reg < 0)
1717*4882a593Smuzhiyun 		return;
1718*4882a593Smuzhiyun 
1719*4882a593Smuzhiyun 	mux = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder);
1720*4882a593Smuzhiyun 	if (mux)
1721*4882a593Smuzhiyun 		val = hdmi->chip_data->lcdsel_lit;
1722*4882a593Smuzhiyun 	else
1723*4882a593Smuzhiyun 		val = hdmi->chip_data->lcdsel_big;
1724*4882a593Smuzhiyun 
1725*4882a593Smuzhiyun 	ret = clk_prepare_enable(hdmi->grf_clk);
1726*4882a593Smuzhiyun 	if (ret < 0) {
1727*4882a593Smuzhiyun 		DRM_DEV_ERROR(hdmi->dev, "failed to enable grfclk %d\n", ret);
1728*4882a593Smuzhiyun 		return;
1729*4882a593Smuzhiyun 	}
1730*4882a593Smuzhiyun 
1731*4882a593Smuzhiyun 	ret = regmap_write(hdmi->regmap, hdmi->chip_data->lcdsel_grf_reg, val);
1732*4882a593Smuzhiyun 	if (ret != 0)
1733*4882a593Smuzhiyun 		DRM_DEV_ERROR(hdmi->dev, "Could not write to GRF: %d\n", ret);
1734*4882a593Smuzhiyun 
1735*4882a593Smuzhiyun 	if (hdmi->chip_data->lcdsel_grf_reg == RK3288_GRF_SOC_CON6) {
1736*4882a593Smuzhiyun 		struct rockchip_crtc_state *s =
1737*4882a593Smuzhiyun 				to_rockchip_crtc_state(crtc->state);
1738*4882a593Smuzhiyun 		u32 mode_mask = mux ? RK3288_HDMI_LCDC1_YUV420 :
1739*4882a593Smuzhiyun 					RK3288_HDMI_LCDC0_YUV420;
1740*4882a593Smuzhiyun 
1741*4882a593Smuzhiyun 		if (s->output_mode == ROCKCHIP_OUT_MODE_YUV420)
1742*4882a593Smuzhiyun 			val = HIWORD_UPDATE(mode_mask, mode_mask);
1743*4882a593Smuzhiyun 		else
1744*4882a593Smuzhiyun 			val = HIWORD_UPDATE(0, mode_mask);
1745*4882a593Smuzhiyun 
1746*4882a593Smuzhiyun 		regmap_write(hdmi->regmap, RK3288_GRF_SOC_CON16, val);
1747*4882a593Smuzhiyun 	}
1748*4882a593Smuzhiyun 
1749*4882a593Smuzhiyun 	clk_disable_unprepare(hdmi->grf_clk);
1750*4882a593Smuzhiyun 	DRM_DEV_DEBUG(hdmi->dev, "vop %s output to hdmi\n",
1751*4882a593Smuzhiyun 		      ret ? "LIT" : "BIG");
1752*4882a593Smuzhiyun }
1753*4882a593Smuzhiyun 
_dw_hdmi_rockchip_encoder_loader_protect(struct rockchip_hdmi * hdmi,bool on)1754*4882a593Smuzhiyun static int _dw_hdmi_rockchip_encoder_loader_protect(struct rockchip_hdmi *hdmi, bool on)
1755*4882a593Smuzhiyun {
1756*4882a593Smuzhiyun 	int ret;
1757*4882a593Smuzhiyun 
1758*4882a593Smuzhiyun 	if (on) {
1759*4882a593Smuzhiyun 		if (hdmi->is_hdmi_qp) {
1760*4882a593Smuzhiyun 			ret = clk_prepare_enable(hdmi->link_clk);
1761*4882a593Smuzhiyun 			if (ret < 0) {
1762*4882a593Smuzhiyun 				DRM_DEV_ERROR(hdmi->dev, "failed to enable link_clk %d\n", ret);
1763*4882a593Smuzhiyun 				return ret;
1764*4882a593Smuzhiyun 			}
1765*4882a593Smuzhiyun 		}
1766*4882a593Smuzhiyun 
1767*4882a593Smuzhiyun 		hdmi->phy->power_count++;
1768*4882a593Smuzhiyun 	} else {
1769*4882a593Smuzhiyun 		clk_disable_unprepare(hdmi->link_clk);
1770*4882a593Smuzhiyun 		hdmi->phy->power_count--;
1771*4882a593Smuzhiyun 	}
1772*4882a593Smuzhiyun 
1773*4882a593Smuzhiyun 	return 0;
1774*4882a593Smuzhiyun }
1775*4882a593Smuzhiyun 
dw_hdmi_rockchip_encoder_loader_protect(struct drm_encoder * encoder,bool on)1776*4882a593Smuzhiyun static int dw_hdmi_rockchip_encoder_loader_protect(struct drm_encoder *encoder, bool on)
1777*4882a593Smuzhiyun {
1778*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
1779*4882a593Smuzhiyun 	struct rockchip_hdmi *secondary;
1780*4882a593Smuzhiyun 
1781*4882a593Smuzhiyun 	_dw_hdmi_rockchip_encoder_loader_protect(hdmi, on);
1782*4882a593Smuzhiyun 	if (hdmi->plat_data->right) {
1783*4882a593Smuzhiyun 		secondary = rockchip_hdmi_find_by_id(hdmi->dev->driver, !hdmi->id);
1784*4882a593Smuzhiyun 		_dw_hdmi_rockchip_encoder_loader_protect(secondary, on);
1785*4882a593Smuzhiyun 	}
1786*4882a593Smuzhiyun 
1787*4882a593Smuzhiyun 	return 0;
1788*4882a593Smuzhiyun }
1789*4882a593Smuzhiyun 
rk3588_set_link_mode(struct rockchip_hdmi * hdmi)1790*4882a593Smuzhiyun static void rk3588_set_link_mode(struct rockchip_hdmi *hdmi)
1791*4882a593Smuzhiyun {
1792*4882a593Smuzhiyun 	int val;
1793*4882a593Smuzhiyun 	bool is_hdmi0;
1794*4882a593Smuzhiyun 
1795*4882a593Smuzhiyun 	if (!hdmi->id)
1796*4882a593Smuzhiyun 		is_hdmi0 = true;
1797*4882a593Smuzhiyun 	else
1798*4882a593Smuzhiyun 		is_hdmi0 = false;
1799*4882a593Smuzhiyun 
1800*4882a593Smuzhiyun 	if (!hdmi->link_cfg.frl_mode) {
1801*4882a593Smuzhiyun 		val = HIWORD_UPDATE(0, RK3588_HDMI21_MASK);
1802*4882a593Smuzhiyun 		if (is_hdmi0)
1803*4882a593Smuzhiyun 			regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON4, val);
1804*4882a593Smuzhiyun 		else
1805*4882a593Smuzhiyun 			regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON7, val);
1806*4882a593Smuzhiyun 
1807*4882a593Smuzhiyun 		val = HIWORD_UPDATE(0, RK3588_COMPRESS_MODE_MASK | RK3588_COLOR_FORMAT_MASK);
1808*4882a593Smuzhiyun 		if (is_hdmi0)
1809*4882a593Smuzhiyun 			regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON3, val);
1810*4882a593Smuzhiyun 		else
1811*4882a593Smuzhiyun 			regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON6, val);
1812*4882a593Smuzhiyun 
1813*4882a593Smuzhiyun 		return;
1814*4882a593Smuzhiyun 	}
1815*4882a593Smuzhiyun 
1816*4882a593Smuzhiyun 	val = HIWORD_UPDATE(RK3588_HDMI21_MASK, RK3588_HDMI21_MASK);
1817*4882a593Smuzhiyun 	if (is_hdmi0)
1818*4882a593Smuzhiyun 		regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON4, val);
1819*4882a593Smuzhiyun 	else
1820*4882a593Smuzhiyun 		regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON7, val);
1821*4882a593Smuzhiyun 
1822*4882a593Smuzhiyun 	if (hdmi->link_cfg.dsc_mode) {
1823*4882a593Smuzhiyun 		val = HIWORD_UPDATE(RK3588_COMPRESS_MODE_MASK | RK3588_COMPRESSED_DATA,
1824*4882a593Smuzhiyun 				    RK3588_COMPRESS_MODE_MASK | RK3588_COLOR_FORMAT_MASK);
1825*4882a593Smuzhiyun 		if (is_hdmi0)
1826*4882a593Smuzhiyun 			regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON3, val);
1827*4882a593Smuzhiyun 		else
1828*4882a593Smuzhiyun 			regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON6, val);
1829*4882a593Smuzhiyun 	} else {
1830*4882a593Smuzhiyun 		val = HIWORD_UPDATE(0, RK3588_COMPRESS_MODE_MASK | RK3588_COLOR_FORMAT_MASK);
1831*4882a593Smuzhiyun 		if (is_hdmi0)
1832*4882a593Smuzhiyun 			regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON3, val);
1833*4882a593Smuzhiyun 		else
1834*4882a593Smuzhiyun 			regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON6, val);
1835*4882a593Smuzhiyun 	}
1836*4882a593Smuzhiyun }
1837*4882a593Smuzhiyun 
rk3588_set_color_format(struct rockchip_hdmi * hdmi,u64 bus_format,u32 depth)1838*4882a593Smuzhiyun static void rk3588_set_color_format(struct rockchip_hdmi *hdmi, u64 bus_format,
1839*4882a593Smuzhiyun 				    u32 depth)
1840*4882a593Smuzhiyun {
1841*4882a593Smuzhiyun 	u32 val = 0;
1842*4882a593Smuzhiyun 
1843*4882a593Smuzhiyun 	switch (bus_format) {
1844*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_RGB888_1X24:
1845*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_RGB101010_1X30:
1846*4882a593Smuzhiyun 		val = HIWORD_UPDATE(0, RK3588_COLOR_FORMAT_MASK);
1847*4882a593Smuzhiyun 		break;
1848*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
1849*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
1850*4882a593Smuzhiyun 		val = HIWORD_UPDATE(RK3588_YUV420, RK3588_COLOR_FORMAT_MASK);
1851*4882a593Smuzhiyun 		break;
1852*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUV8_1X24:
1853*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUV10_1X30:
1854*4882a593Smuzhiyun 		val = HIWORD_UPDATE(RK3588_YUV444, RK3588_COLOR_FORMAT_MASK);
1855*4882a593Smuzhiyun 		break;
1856*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUYV10_1X20:
1857*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUYV8_1X16:
1858*4882a593Smuzhiyun 		val = HIWORD_UPDATE(RK3588_YUV422, RK3588_COLOR_FORMAT_MASK);
1859*4882a593Smuzhiyun 		break;
1860*4882a593Smuzhiyun 	default:
1861*4882a593Smuzhiyun 		dev_err(hdmi->dev, "can't set correct color format\n");
1862*4882a593Smuzhiyun 		return;
1863*4882a593Smuzhiyun 	}
1864*4882a593Smuzhiyun 
1865*4882a593Smuzhiyun 	if (hdmi->link_cfg.dsc_mode)
1866*4882a593Smuzhiyun 		val = HIWORD_UPDATE(RK3588_COMPRESSED_DATA, RK3588_COLOR_FORMAT_MASK);
1867*4882a593Smuzhiyun 
1868*4882a593Smuzhiyun 	if (depth == 8 || bus_format == MEDIA_BUS_FMT_YUYV10_1X20)
1869*4882a593Smuzhiyun 		val |= HIWORD_UPDATE(RK3588_8BPC, RK3588_COLOR_DEPTH_MASK);
1870*4882a593Smuzhiyun 	else
1871*4882a593Smuzhiyun 		val |= HIWORD_UPDATE(RK3588_10BPC, RK3588_COLOR_DEPTH_MASK);
1872*4882a593Smuzhiyun 
1873*4882a593Smuzhiyun 	if (!hdmi->id)
1874*4882a593Smuzhiyun 		regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON3, val);
1875*4882a593Smuzhiyun 	else
1876*4882a593Smuzhiyun 		regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON6, val);
1877*4882a593Smuzhiyun }
1878*4882a593Smuzhiyun 
rk3588_set_grf_cfg(void * data)1879*4882a593Smuzhiyun static void rk3588_set_grf_cfg(void *data)
1880*4882a593Smuzhiyun {
1881*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
1882*4882a593Smuzhiyun 	int color_depth;
1883*4882a593Smuzhiyun 
1884*4882a593Smuzhiyun 	rk3588_set_link_mode(hdmi);
1885*4882a593Smuzhiyun 	color_depth = hdmi_bus_fmt_color_depth(hdmi->bus_format);
1886*4882a593Smuzhiyun 	rk3588_set_color_format(hdmi, hdmi->bus_format, color_depth);
1887*4882a593Smuzhiyun }
1888*4882a593Smuzhiyun 
rk3588_get_grf_color_fmt(void * data)1889*4882a593Smuzhiyun static u64 rk3588_get_grf_color_fmt(void *data)
1890*4882a593Smuzhiyun {
1891*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
1892*4882a593Smuzhiyun 	u32 val, depth;
1893*4882a593Smuzhiyun 	u64 bus_format;
1894*4882a593Smuzhiyun 
1895*4882a593Smuzhiyun 	if (!hdmi->id)
1896*4882a593Smuzhiyun 		regmap_read(hdmi->vo1_regmap, RK3588_GRF_VO1_CON3, &val);
1897*4882a593Smuzhiyun 	else
1898*4882a593Smuzhiyun 		regmap_read(hdmi->vo1_regmap, RK3588_GRF_VO1_CON6, &val);
1899*4882a593Smuzhiyun 
1900*4882a593Smuzhiyun 	depth = (val & RK3588_COLOR_DEPTH_MASK) >> 4;
1901*4882a593Smuzhiyun 
1902*4882a593Smuzhiyun 	switch (val & RK3588_COLOR_FORMAT_MASK) {
1903*4882a593Smuzhiyun 	case RK3588_YUV444:
1904*4882a593Smuzhiyun 		if (!depth)
1905*4882a593Smuzhiyun 			bus_format = MEDIA_BUS_FMT_YUV8_1X24;
1906*4882a593Smuzhiyun 		else
1907*4882a593Smuzhiyun 			bus_format = MEDIA_BUS_FMT_YUV10_1X30;
1908*4882a593Smuzhiyun 		break;
1909*4882a593Smuzhiyun 	case RK3588_YUV422:
1910*4882a593Smuzhiyun 		bus_format = MEDIA_BUS_FMT_YUYV10_1X20;
1911*4882a593Smuzhiyun 		break;
1912*4882a593Smuzhiyun 	case RK3588_YUV420:
1913*4882a593Smuzhiyun 		if (!depth)
1914*4882a593Smuzhiyun 			bus_format = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
1915*4882a593Smuzhiyun 		else
1916*4882a593Smuzhiyun 			bus_format = MEDIA_BUS_FMT_UYYVYY10_0_5X30;
1917*4882a593Smuzhiyun 		break;
1918*4882a593Smuzhiyun 	case RK3588_RGB:
1919*4882a593Smuzhiyun 		if (!depth)
1920*4882a593Smuzhiyun 			bus_format = MEDIA_BUS_FMT_RGB888_1X24;
1921*4882a593Smuzhiyun 		else
1922*4882a593Smuzhiyun 			bus_format = MEDIA_BUS_FMT_RGB101010_1X30;
1923*4882a593Smuzhiyun 		break;
1924*4882a593Smuzhiyun 	default:
1925*4882a593Smuzhiyun 		dev_err(hdmi->dev, "can't get correct color format\n");
1926*4882a593Smuzhiyun 		bus_format = MEDIA_BUS_FMT_YUV8_1X24;
1927*4882a593Smuzhiyun 		break;
1928*4882a593Smuzhiyun 	}
1929*4882a593Smuzhiyun 
1930*4882a593Smuzhiyun 	return bus_format;
1931*4882a593Smuzhiyun }
1932*4882a593Smuzhiyun 
1933*4882a593Smuzhiyun static void
dw_hdmi_rockchip_select_output(struct drm_connector_state * conn_state,struct drm_crtc_state * crtc_state,struct rockchip_hdmi * hdmi,unsigned int * color_format,unsigned int * output_mode,unsigned long * bus_format,unsigned int * bus_width,unsigned long * enc_out_encoding,unsigned int * eotf)1934*4882a593Smuzhiyun dw_hdmi_rockchip_select_output(struct drm_connector_state *conn_state,
1935*4882a593Smuzhiyun 			       struct drm_crtc_state *crtc_state,
1936*4882a593Smuzhiyun 			       struct rockchip_hdmi *hdmi,
1937*4882a593Smuzhiyun 			       unsigned int *color_format,
1938*4882a593Smuzhiyun 			       unsigned int *output_mode,
1939*4882a593Smuzhiyun 			       unsigned long *bus_format,
1940*4882a593Smuzhiyun 			       unsigned int *bus_width,
1941*4882a593Smuzhiyun 			       unsigned long *enc_out_encoding,
1942*4882a593Smuzhiyun 			       unsigned int *eotf)
1943*4882a593Smuzhiyun {
1944*4882a593Smuzhiyun 	struct drm_display_info *info = &conn_state->connector->display_info;
1945*4882a593Smuzhiyun 	struct drm_display_mode mode;
1946*4882a593Smuzhiyun 	struct hdr_output_metadata *hdr_metadata;
1947*4882a593Smuzhiyun 	u32 vic;
1948*4882a593Smuzhiyun 	unsigned long tmdsclock, pixclock;
1949*4882a593Smuzhiyun 	unsigned int color_depth;
1950*4882a593Smuzhiyun 	bool support_dc = false;
1951*4882a593Smuzhiyun 	bool sink_is_hdmi = true;
1952*4882a593Smuzhiyun 	bool yuv422_out = false;
1953*4882a593Smuzhiyun 	u32 max_tmds_clock = info->max_tmds_clock;
1954*4882a593Smuzhiyun 	int output_eotf;
1955*4882a593Smuzhiyun 
1956*4882a593Smuzhiyun 	drm_mode_copy(&mode, &crtc_state->mode);
1957*4882a593Smuzhiyun 	pixclock = mode.crtc_clock;
1958*4882a593Smuzhiyun 	if (hdmi->plat_data->split_mode) {
1959*4882a593Smuzhiyun 		drm_mode_convert_to_origin_mode(&mode);
1960*4882a593Smuzhiyun 		pixclock /= 2;
1961*4882a593Smuzhiyun 	}
1962*4882a593Smuzhiyun 
1963*4882a593Smuzhiyun 	vic = drm_match_cea_mode(&mode);
1964*4882a593Smuzhiyun 
1965*4882a593Smuzhiyun 	if (!hdmi->is_hdmi_qp)
1966*4882a593Smuzhiyun 		sink_is_hdmi = dw_hdmi_get_output_whether_hdmi(hdmi->hdmi);
1967*4882a593Smuzhiyun 	else
1968*4882a593Smuzhiyun 		sink_is_hdmi = dw_hdmi_qp_get_output_whether_hdmi(hdmi->hdmi_qp);
1969*4882a593Smuzhiyun 
1970*4882a593Smuzhiyun 	*color_format = RK_IF_FORMAT_RGB;
1971*4882a593Smuzhiyun 
1972*4882a593Smuzhiyun 	switch (hdmi->hdmi_output) {
1973*4882a593Smuzhiyun 	case RK_IF_FORMAT_YCBCR_HQ:
1974*4882a593Smuzhiyun 		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
1975*4882a593Smuzhiyun 			*color_format = RK_IF_FORMAT_YCBCR444;
1976*4882a593Smuzhiyun 		else if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
1977*4882a593Smuzhiyun 			*color_format = RK_IF_FORMAT_YCBCR422;
1978*4882a593Smuzhiyun 		else if (conn_state->connector->ycbcr_420_allowed &&
1979*4882a593Smuzhiyun 			 drm_mode_is_420(info, &mode) &&
1980*4882a593Smuzhiyun 			 (pixclock >= 594000 && !hdmi->is_hdmi_qp))
1981*4882a593Smuzhiyun 			*color_format = RK_IF_FORMAT_YCBCR420;
1982*4882a593Smuzhiyun 		break;
1983*4882a593Smuzhiyun 	case RK_IF_FORMAT_YCBCR_LQ:
1984*4882a593Smuzhiyun 		if (conn_state->connector->ycbcr_420_allowed &&
1985*4882a593Smuzhiyun 		    drm_mode_is_420(info, &mode) && pixclock >= 594000)
1986*4882a593Smuzhiyun 			*color_format = RK_IF_FORMAT_YCBCR420;
1987*4882a593Smuzhiyun 		else if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
1988*4882a593Smuzhiyun 			*color_format = RK_IF_FORMAT_YCBCR422;
1989*4882a593Smuzhiyun 		else if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
1990*4882a593Smuzhiyun 			*color_format = RK_IF_FORMAT_YCBCR444;
1991*4882a593Smuzhiyun 		break;
1992*4882a593Smuzhiyun 	case RK_IF_FORMAT_YCBCR420:
1993*4882a593Smuzhiyun 		if (conn_state->connector->ycbcr_420_allowed &&
1994*4882a593Smuzhiyun 		    drm_mode_is_420(info, &mode) && pixclock >= 594000)
1995*4882a593Smuzhiyun 			*color_format = RK_IF_FORMAT_YCBCR420;
1996*4882a593Smuzhiyun 		break;
1997*4882a593Smuzhiyun 	case RK_IF_FORMAT_YCBCR422:
1998*4882a593Smuzhiyun 		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
1999*4882a593Smuzhiyun 			*color_format = RK_IF_FORMAT_YCBCR422;
2000*4882a593Smuzhiyun 		break;
2001*4882a593Smuzhiyun 	case RK_IF_FORMAT_YCBCR444:
2002*4882a593Smuzhiyun 		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
2003*4882a593Smuzhiyun 			*color_format = RK_IF_FORMAT_YCBCR444;
2004*4882a593Smuzhiyun 		break;
2005*4882a593Smuzhiyun 	case RK_IF_FORMAT_RGB:
2006*4882a593Smuzhiyun 	default:
2007*4882a593Smuzhiyun 		break;
2008*4882a593Smuzhiyun 	}
2009*4882a593Smuzhiyun 
2010*4882a593Smuzhiyun 	if (*color_format == RK_IF_FORMAT_RGB &&
2011*4882a593Smuzhiyun 	    info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30)
2012*4882a593Smuzhiyun 		support_dc = true;
2013*4882a593Smuzhiyun 	if (*color_format == RK_IF_FORMAT_YCBCR444 &&
2014*4882a593Smuzhiyun 	    info->edid_hdmi_dc_modes &
2015*4882a593Smuzhiyun 	    (DRM_EDID_HDMI_DC_Y444 | DRM_EDID_HDMI_DC_30))
2016*4882a593Smuzhiyun 		support_dc = true;
2017*4882a593Smuzhiyun 	if (*color_format == RK_IF_FORMAT_YCBCR422)
2018*4882a593Smuzhiyun 		support_dc = true;
2019*4882a593Smuzhiyun 	if (*color_format == RK_IF_FORMAT_YCBCR420 &&
2020*4882a593Smuzhiyun 	    info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30)
2021*4882a593Smuzhiyun 		support_dc = true;
2022*4882a593Smuzhiyun 
2023*4882a593Smuzhiyun 	if (hdmi->colordepth > 8 && support_dc)
2024*4882a593Smuzhiyun 		color_depth = 10;
2025*4882a593Smuzhiyun 	else
2026*4882a593Smuzhiyun 		color_depth = 8;
2027*4882a593Smuzhiyun 
2028*4882a593Smuzhiyun 	if (!sink_is_hdmi) {
2029*4882a593Smuzhiyun 		*color_format = RK_IF_FORMAT_RGB;
2030*4882a593Smuzhiyun 		color_depth = 8;
2031*4882a593Smuzhiyun 	}
2032*4882a593Smuzhiyun 
2033*4882a593Smuzhiyun 	*eotf = HDMI_EOTF_TRADITIONAL_GAMMA_SDR;
2034*4882a593Smuzhiyun 	if (conn_state->hdr_output_metadata) {
2035*4882a593Smuzhiyun 		hdr_metadata = (struct hdr_output_metadata *)
2036*4882a593Smuzhiyun 			conn_state->hdr_output_metadata->data;
2037*4882a593Smuzhiyun 		output_eotf = hdr_metadata->hdmi_metadata_type1.eotf;
2038*4882a593Smuzhiyun 		if (output_eotf > HDMI_EOTF_TRADITIONAL_GAMMA_SDR &&
2039*4882a593Smuzhiyun 		    output_eotf <= HDMI_EOTF_BT_2100_HLG)
2040*4882a593Smuzhiyun 			*eotf = output_eotf;
2041*4882a593Smuzhiyun 	}
2042*4882a593Smuzhiyun 
2043*4882a593Smuzhiyun 	hdmi->colorimetry = conn_state->colorspace;
2044*4882a593Smuzhiyun 
2045*4882a593Smuzhiyun 	/* bt2020 sdr/hdr output */
2046*4882a593Smuzhiyun 	if ((hdmi->colorimetry >= DRM_MODE_COLORIMETRY_BT2020_CYCC) &&
2047*4882a593Smuzhiyun 	    (hdmi->colorimetry <= DRM_MODE_COLORIMETRY_BT2020_YCC) &&
2048*4882a593Smuzhiyun 	    hdmi->edid_colorimetry & (BIT(6) | BIT(7))) {
2049*4882a593Smuzhiyun 		*enc_out_encoding = V4L2_YCBCR_ENC_BT2020;
2050*4882a593Smuzhiyun 		yuv422_out = true;
2051*4882a593Smuzhiyun 	/* bt709 hdr output */
2052*4882a593Smuzhiyun 	} else if ((hdmi->colorimetry <= DRM_MODE_COLORIMETRY_BT2020_CYCC) &&
2053*4882a593Smuzhiyun 		   (hdmi->colorimetry >= DRM_MODE_COLORIMETRY_BT2020_YCC) &&
2054*4882a593Smuzhiyun 		   (conn_state->connector->hdr_sink_metadata.hdmi_type1.eotf & BIT(*eotf) &&
2055*4882a593Smuzhiyun 		    *eotf > HDMI_EOTF_TRADITIONAL_GAMMA_SDR)) {
2056*4882a593Smuzhiyun 		*enc_out_encoding = V4L2_YCBCR_ENC_709;
2057*4882a593Smuzhiyun 		yuv422_out = true;
2058*4882a593Smuzhiyun 	} else if ((vic == 6) || (vic == 7) || (vic == 21) || (vic == 22) ||
2059*4882a593Smuzhiyun 		   (vic == 2) || (vic == 3) || (vic == 17) || (vic == 18)) {
2060*4882a593Smuzhiyun 		*enc_out_encoding = V4L2_YCBCR_ENC_601;
2061*4882a593Smuzhiyun 	} else {
2062*4882a593Smuzhiyun 		*enc_out_encoding = V4L2_YCBCR_ENC_709;
2063*4882a593Smuzhiyun 	}
2064*4882a593Smuzhiyun 
2065*4882a593Smuzhiyun 	if ((yuv422_out || hdmi->hdmi_output == RK_IF_FORMAT_YCBCR_HQ) && color_depth == 10 &&
2066*4882a593Smuzhiyun 	    (hdmi_bus_fmt_color_depth(hdmi->prev_bus_format) == 8 ||
2067*4882a593Smuzhiyun 	     hdmi_bus_fmt_to_color_format(hdmi->prev_bus_format) == RK_IF_FORMAT_YCBCR422)) {
2068*4882a593Smuzhiyun 		/* We prefer use YCbCr422 to send hdr 10bit */
2069*4882a593Smuzhiyun 		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
2070*4882a593Smuzhiyun 			*color_format = RK_IF_FORMAT_YCBCR422;
2071*4882a593Smuzhiyun 	}
2072*4882a593Smuzhiyun 
2073*4882a593Smuzhiyun 	if (mode.flags & DRM_MODE_FLAG_DBLCLK)
2074*4882a593Smuzhiyun 		pixclock *= 2;
2075*4882a593Smuzhiyun 	if ((mode.flags & DRM_MODE_FLAG_3D_MASK) ==
2076*4882a593Smuzhiyun 		DRM_MODE_FLAG_3D_FRAME_PACKING)
2077*4882a593Smuzhiyun 		pixclock *= 2;
2078*4882a593Smuzhiyun 
2079*4882a593Smuzhiyun 	if (hdmi->is_hdmi_qp && mode.clock >= 600000)
2080*4882a593Smuzhiyun 		*color_format = RK_IF_FORMAT_YCBCR420;
2081*4882a593Smuzhiyun 
2082*4882a593Smuzhiyun 	if (*color_format == RK_IF_FORMAT_YCBCR422 || color_depth == 8)
2083*4882a593Smuzhiyun 		tmdsclock = pixclock;
2084*4882a593Smuzhiyun 	else
2085*4882a593Smuzhiyun 		tmdsclock = pixclock * (color_depth) / 8;
2086*4882a593Smuzhiyun 
2087*4882a593Smuzhiyun 	if (*color_format == RK_IF_FORMAT_YCBCR420)
2088*4882a593Smuzhiyun 		tmdsclock /= 2;
2089*4882a593Smuzhiyun 
2090*4882a593Smuzhiyun 	/* XXX: max_tmds_clock of some sink is 0, we think it is 340MHz. */
2091*4882a593Smuzhiyun 	if (!max_tmds_clock)
2092*4882a593Smuzhiyun 		max_tmds_clock = 340000;
2093*4882a593Smuzhiyun 
2094*4882a593Smuzhiyun 	max_tmds_clock = min(max_tmds_clock, hdmi->max_tmdsclk);
2095*4882a593Smuzhiyun 
2096*4882a593Smuzhiyun 	if (hdmi->is_hdmi_qp && hdmi->link_cfg.rate_per_lane && mode.clock > 600000)
2097*4882a593Smuzhiyun 		max_tmds_clock =
2098*4882a593Smuzhiyun 			hdmi->link_cfg.frl_lanes * hdmi->link_cfg.rate_per_lane * 1000000;
2099*4882a593Smuzhiyun 
2100*4882a593Smuzhiyun 	if (tmdsclock > max_tmds_clock) {
2101*4882a593Smuzhiyun 		if (max_tmds_clock >= 594000) {
2102*4882a593Smuzhiyun 			color_depth = 8;
2103*4882a593Smuzhiyun 		} else if (max_tmds_clock > 340000) {
2104*4882a593Smuzhiyun 			if (drm_mode_is_420(info, &mode) || tmdsclock >= 594000)
2105*4882a593Smuzhiyun 				*color_format = RK_IF_FORMAT_YCBCR420;
2106*4882a593Smuzhiyun 		} else {
2107*4882a593Smuzhiyun 			color_depth = 8;
2108*4882a593Smuzhiyun 			if (drm_mode_is_420(info, &mode) || tmdsclock >= 594000)
2109*4882a593Smuzhiyun 				*color_format = RK_IF_FORMAT_YCBCR420;
2110*4882a593Smuzhiyun 		}
2111*4882a593Smuzhiyun 	}
2112*4882a593Smuzhiyun 
2113*4882a593Smuzhiyun 	if (*color_format == RK_IF_FORMAT_YCBCR420) {
2114*4882a593Smuzhiyun 		*output_mode = ROCKCHIP_OUT_MODE_YUV420;
2115*4882a593Smuzhiyun 		if (color_depth > 8)
2116*4882a593Smuzhiyun 			*bus_format = MEDIA_BUS_FMT_UYYVYY10_0_5X30;
2117*4882a593Smuzhiyun 		else
2118*4882a593Smuzhiyun 			*bus_format = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
2119*4882a593Smuzhiyun 		*bus_width = color_depth / 2;
2120*4882a593Smuzhiyun 	} else {
2121*4882a593Smuzhiyun 		*output_mode = ROCKCHIP_OUT_MODE_AAAA;
2122*4882a593Smuzhiyun 		if (color_depth > 8) {
2123*4882a593Smuzhiyun 			if (*color_format != RK_IF_FORMAT_RGB &&
2124*4882a593Smuzhiyun 			    !hdmi->unsupported_yuv_input)
2125*4882a593Smuzhiyun 				*bus_format = MEDIA_BUS_FMT_YUV10_1X30;
2126*4882a593Smuzhiyun 			else
2127*4882a593Smuzhiyun 				*bus_format = MEDIA_BUS_FMT_RGB101010_1X30;
2128*4882a593Smuzhiyun 		} else {
2129*4882a593Smuzhiyun 			if (*color_format != RK_IF_FORMAT_RGB &&
2130*4882a593Smuzhiyun 			    !hdmi->unsupported_yuv_input)
2131*4882a593Smuzhiyun 				*bus_format = MEDIA_BUS_FMT_YUV8_1X24;
2132*4882a593Smuzhiyun 			else
2133*4882a593Smuzhiyun 				*bus_format = MEDIA_BUS_FMT_RGB888_1X24;
2134*4882a593Smuzhiyun 		}
2135*4882a593Smuzhiyun 		if (*color_format == RK_IF_FORMAT_YCBCR422)
2136*4882a593Smuzhiyun 			*bus_width = 8;
2137*4882a593Smuzhiyun 		else
2138*4882a593Smuzhiyun 			*bus_width = color_depth;
2139*4882a593Smuzhiyun 	}
2140*4882a593Smuzhiyun 
2141*4882a593Smuzhiyun 	hdmi->bus_format = *bus_format;
2142*4882a593Smuzhiyun 
2143*4882a593Smuzhiyun 	if (*color_format == RK_IF_FORMAT_YCBCR422) {
2144*4882a593Smuzhiyun 		if (hdmi->is_hdmi_qp) {
2145*4882a593Smuzhiyun 			if (color_depth == 12)
2146*4882a593Smuzhiyun 				hdmi->output_bus_format = MEDIA_BUS_FMT_YUYV12_1X24;
2147*4882a593Smuzhiyun 			else if (color_depth == 10)
2148*4882a593Smuzhiyun 				hdmi->output_bus_format = MEDIA_BUS_FMT_YUYV10_1X20;
2149*4882a593Smuzhiyun 			else
2150*4882a593Smuzhiyun 				hdmi->output_bus_format = MEDIA_BUS_FMT_YUYV8_1X16;
2151*4882a593Smuzhiyun 
2152*4882a593Smuzhiyun 			*bus_format = hdmi->output_bus_format;
2153*4882a593Smuzhiyun 			hdmi->bus_format = *bus_format;
2154*4882a593Smuzhiyun 			*output_mode = ROCKCHIP_OUT_MODE_YUV422;
2155*4882a593Smuzhiyun 		} else {
2156*4882a593Smuzhiyun 			if (color_depth == 12)
2157*4882a593Smuzhiyun 				hdmi->output_bus_format = MEDIA_BUS_FMT_UYVY12_1X24;
2158*4882a593Smuzhiyun 			else if (color_depth == 10)
2159*4882a593Smuzhiyun 				hdmi->output_bus_format = MEDIA_BUS_FMT_UYVY10_1X20;
2160*4882a593Smuzhiyun 			else
2161*4882a593Smuzhiyun 				hdmi->output_bus_format = MEDIA_BUS_FMT_UYVY8_1X16;
2162*4882a593Smuzhiyun 		}
2163*4882a593Smuzhiyun 	} else {
2164*4882a593Smuzhiyun 		hdmi->output_bus_format = *bus_format;
2165*4882a593Smuzhiyun 	}
2166*4882a593Smuzhiyun }
2167*4882a593Smuzhiyun 
2168*4882a593Smuzhiyun static bool
dw_hdmi_rockchip_check_color(struct drm_connector_state * conn_state,struct rockchip_hdmi * hdmi)2169*4882a593Smuzhiyun dw_hdmi_rockchip_check_color(struct drm_connector_state *conn_state,
2170*4882a593Smuzhiyun 			     struct rockchip_hdmi *hdmi)
2171*4882a593Smuzhiyun {
2172*4882a593Smuzhiyun 	struct drm_crtc_state *crtc_state = conn_state->crtc->state;
2173*4882a593Smuzhiyun 	unsigned int colorformat;
2174*4882a593Smuzhiyun 	unsigned long bus_format;
2175*4882a593Smuzhiyun 	unsigned long output_bus_format = hdmi->output_bus_format;
2176*4882a593Smuzhiyun 	unsigned long enc_out_encoding = hdmi->enc_out_encoding;
2177*4882a593Smuzhiyun 	unsigned int eotf, bus_width;
2178*4882a593Smuzhiyun 	unsigned int output_mode;
2179*4882a593Smuzhiyun 
2180*4882a593Smuzhiyun 	dw_hdmi_rockchip_select_output(conn_state, crtc_state, hdmi,
2181*4882a593Smuzhiyun 				       &colorformat,
2182*4882a593Smuzhiyun 				       &output_mode, &bus_format, &bus_width,
2183*4882a593Smuzhiyun 				       &hdmi->enc_out_encoding, &eotf);
2184*4882a593Smuzhiyun 
2185*4882a593Smuzhiyun 	if (output_bus_format != hdmi->output_bus_format ||
2186*4882a593Smuzhiyun 	    enc_out_encoding != hdmi->enc_out_encoding)
2187*4882a593Smuzhiyun 		return true;
2188*4882a593Smuzhiyun 	else
2189*4882a593Smuzhiyun 		return false;
2190*4882a593Smuzhiyun }
2191*4882a593Smuzhiyun 
2192*4882a593Smuzhiyun static int
dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder * encoder,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state)2193*4882a593Smuzhiyun dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
2194*4882a593Smuzhiyun 				      struct drm_crtc_state *crtc_state,
2195*4882a593Smuzhiyun 				      struct drm_connector_state *conn_state)
2196*4882a593Smuzhiyun {
2197*4882a593Smuzhiyun 	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
2198*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
2199*4882a593Smuzhiyun 	unsigned int colorformat, bus_width, tmdsclk;
2200*4882a593Smuzhiyun 	struct drm_display_mode mode;
2201*4882a593Smuzhiyun 	unsigned int output_mode;
2202*4882a593Smuzhiyun 	unsigned long bus_format;
2203*4882a593Smuzhiyun 	int color_depth;
2204*4882a593Smuzhiyun 	bool secondary = false;
2205*4882a593Smuzhiyun 
2206*4882a593Smuzhiyun 	/*
2207*4882a593Smuzhiyun 	 * There are two hdmi but only one encoder in split mode,
2208*4882a593Smuzhiyun 	 * so we need to check twice.
2209*4882a593Smuzhiyun 	 */
2210*4882a593Smuzhiyun secondary:
2211*4882a593Smuzhiyun 	drm_mode_copy(&mode, &crtc_state->mode);
2212*4882a593Smuzhiyun 
2213*4882a593Smuzhiyun 	if (hdmi->plat_data->split_mode)
2214*4882a593Smuzhiyun 		drm_mode_convert_to_origin_mode(&mode);
2215*4882a593Smuzhiyun 
2216*4882a593Smuzhiyun 	dw_hdmi_rockchip_select_output(conn_state, crtc_state, hdmi,
2217*4882a593Smuzhiyun 				       &colorformat,
2218*4882a593Smuzhiyun 				       &output_mode, &bus_format, &bus_width,
2219*4882a593Smuzhiyun 				       &hdmi->enc_out_encoding, &s->eotf);
2220*4882a593Smuzhiyun 
2221*4882a593Smuzhiyun 	s->bus_format = bus_format;
2222*4882a593Smuzhiyun 	if (hdmi->is_hdmi_qp) {
2223*4882a593Smuzhiyun 		color_depth = hdmi_bus_fmt_color_depth(bus_format);
2224*4882a593Smuzhiyun 		tmdsclk = hdmi_get_tmdsclock(hdmi, crtc_state->mode.clock);
2225*4882a593Smuzhiyun 		if (hdmi_bus_fmt_is_yuv420(hdmi->output_bus_format))
2226*4882a593Smuzhiyun 			tmdsclk /= 2;
2227*4882a593Smuzhiyun 		hdmi_select_link_config(hdmi, crtc_state, tmdsclk);
2228*4882a593Smuzhiyun 
2229*4882a593Smuzhiyun 		if (hdmi->link_cfg.frl_mode) {
2230*4882a593Smuzhiyun 			/* in the current version, support max 40G frl */
2231*4882a593Smuzhiyun 			if (hdmi->link_cfg.rate_per_lane >= 10) {
2232*4882a593Smuzhiyun 				hdmi->link_cfg.frl_lanes = 4;
2233*4882a593Smuzhiyun 				hdmi->link_cfg.rate_per_lane = 10;
2234*4882a593Smuzhiyun 			}
2235*4882a593Smuzhiyun 			bus_width = hdmi->link_cfg.frl_lanes *
2236*4882a593Smuzhiyun 				hdmi->link_cfg.rate_per_lane * 1000000;
2237*4882a593Smuzhiyun 			/* 10 bit color depth and frl mode */
2238*4882a593Smuzhiyun 			if (color_depth == 10)
2239*4882a593Smuzhiyun 				bus_width |=
2240*4882a593Smuzhiyun 					COLOR_DEPTH_10BIT | HDMI_FRL_MODE;
2241*4882a593Smuzhiyun 			else
2242*4882a593Smuzhiyun 				bus_width |= HDMI_FRL_MODE;
2243*4882a593Smuzhiyun 		} else {
2244*4882a593Smuzhiyun 			bus_width = hdmi_get_tmdsclock(hdmi, mode.clock * 10);
2245*4882a593Smuzhiyun 			if (hdmi_bus_fmt_is_yuv420(hdmi->output_bus_format))
2246*4882a593Smuzhiyun 				bus_width /= 2;
2247*4882a593Smuzhiyun 
2248*4882a593Smuzhiyun 			if (color_depth == 10 && !hdmi_bus_fmt_is_yuv422(hdmi->output_bus_format))
2249*4882a593Smuzhiyun 				bus_width |= COLOR_DEPTH_10BIT;
2250*4882a593Smuzhiyun 		}
2251*4882a593Smuzhiyun 	}
2252*4882a593Smuzhiyun 
2253*4882a593Smuzhiyun 	hdmi->phy_bus_width = bus_width;
2254*4882a593Smuzhiyun 
2255*4882a593Smuzhiyun 	if (hdmi->phy)
2256*4882a593Smuzhiyun 		phy_set_bus_width(hdmi->phy, bus_width);
2257*4882a593Smuzhiyun 
2258*4882a593Smuzhiyun 	s->output_type = DRM_MODE_CONNECTOR_HDMIA;
2259*4882a593Smuzhiyun 	s->tv_state = &conn_state->tv;
2260*4882a593Smuzhiyun 
2261*4882a593Smuzhiyun 	if (hdmi->plat_data->split_mode) {
2262*4882a593Smuzhiyun 		s->output_flags |= ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE;
2263*4882a593Smuzhiyun 		if (hdmi->plat_data->right && hdmi->id)
2264*4882a593Smuzhiyun 			s->output_flags |= ROCKCHIP_OUTPUT_DATA_SWAP;
2265*4882a593Smuzhiyun 		s->output_if |= VOP_OUTPUT_IF_HDMI0 | VOP_OUTPUT_IF_HDMI1;
2266*4882a593Smuzhiyun 	} else {
2267*4882a593Smuzhiyun 		if (!hdmi->id)
2268*4882a593Smuzhiyun 			s->output_if |= VOP_OUTPUT_IF_HDMI0;
2269*4882a593Smuzhiyun 		else
2270*4882a593Smuzhiyun 			s->output_if |= VOP_OUTPUT_IF_HDMI1;
2271*4882a593Smuzhiyun 	}
2272*4882a593Smuzhiyun 
2273*4882a593Smuzhiyun 	s->output_mode = output_mode;
2274*4882a593Smuzhiyun 	hdmi->bus_format = s->bus_format;
2275*4882a593Smuzhiyun 
2276*4882a593Smuzhiyun 	if (hdmi->enc_out_encoding == V4L2_YCBCR_ENC_BT2020)
2277*4882a593Smuzhiyun 		s->color_space = V4L2_COLORSPACE_BT2020;
2278*4882a593Smuzhiyun 	else if (colorformat == RK_IF_FORMAT_RGB)
2279*4882a593Smuzhiyun 		s->color_space = V4L2_COLORSPACE_DEFAULT;
2280*4882a593Smuzhiyun 	else if (hdmi->enc_out_encoding == V4L2_YCBCR_ENC_709)
2281*4882a593Smuzhiyun 		s->color_space = V4L2_COLORSPACE_REC709;
2282*4882a593Smuzhiyun 	else
2283*4882a593Smuzhiyun 		s->color_space = V4L2_COLORSPACE_SMPTE170M;
2284*4882a593Smuzhiyun 
2285*4882a593Smuzhiyun 	if (hdmi->plat_data->split_mode && !secondary) {
2286*4882a593Smuzhiyun 		hdmi = rockchip_hdmi_find_by_id(hdmi->dev->driver, !hdmi->id);
2287*4882a593Smuzhiyun 		secondary = true;
2288*4882a593Smuzhiyun 		goto secondary;
2289*4882a593Smuzhiyun 	}
2290*4882a593Smuzhiyun 
2291*4882a593Smuzhiyun 	return 0;
2292*4882a593Smuzhiyun }
2293*4882a593Smuzhiyun 
2294*4882a593Smuzhiyun 
2295*4882a593Smuzhiyun static unsigned long
dw_hdmi_rockchip_get_input_bus_format(void * data)2296*4882a593Smuzhiyun dw_hdmi_rockchip_get_input_bus_format(void *data)
2297*4882a593Smuzhiyun {
2298*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2299*4882a593Smuzhiyun 
2300*4882a593Smuzhiyun 	return hdmi->bus_format;
2301*4882a593Smuzhiyun }
2302*4882a593Smuzhiyun 
2303*4882a593Smuzhiyun static unsigned long
dw_hdmi_rockchip_get_output_bus_format(void * data)2304*4882a593Smuzhiyun dw_hdmi_rockchip_get_output_bus_format(void *data)
2305*4882a593Smuzhiyun {
2306*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2307*4882a593Smuzhiyun 
2308*4882a593Smuzhiyun 	return hdmi->output_bus_format;
2309*4882a593Smuzhiyun }
2310*4882a593Smuzhiyun 
2311*4882a593Smuzhiyun static unsigned long
dw_hdmi_rockchip_get_enc_in_encoding(void * data)2312*4882a593Smuzhiyun dw_hdmi_rockchip_get_enc_in_encoding(void *data)
2313*4882a593Smuzhiyun {
2314*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2315*4882a593Smuzhiyun 
2316*4882a593Smuzhiyun 	return hdmi->enc_out_encoding;
2317*4882a593Smuzhiyun }
2318*4882a593Smuzhiyun 
2319*4882a593Smuzhiyun static unsigned long
dw_hdmi_rockchip_get_enc_out_encoding(void * data)2320*4882a593Smuzhiyun dw_hdmi_rockchip_get_enc_out_encoding(void *data)
2321*4882a593Smuzhiyun {
2322*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2323*4882a593Smuzhiyun 
2324*4882a593Smuzhiyun 	return hdmi->enc_out_encoding;
2325*4882a593Smuzhiyun }
2326*4882a593Smuzhiyun 
2327*4882a593Smuzhiyun static unsigned long
dw_hdmi_rockchip_get_quant_range(void * data)2328*4882a593Smuzhiyun dw_hdmi_rockchip_get_quant_range(void *data)
2329*4882a593Smuzhiyun {
2330*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2331*4882a593Smuzhiyun 
2332*4882a593Smuzhiyun 	return hdmi->hdmi_quant_range;
2333*4882a593Smuzhiyun }
2334*4882a593Smuzhiyun 
2335*4882a593Smuzhiyun static struct drm_property *
dw_hdmi_rockchip_get_hdr_property(void * data)2336*4882a593Smuzhiyun dw_hdmi_rockchip_get_hdr_property(void *data)
2337*4882a593Smuzhiyun {
2338*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2339*4882a593Smuzhiyun 
2340*4882a593Smuzhiyun 	return hdmi->hdr_panel_metadata_property;
2341*4882a593Smuzhiyun }
2342*4882a593Smuzhiyun 
2343*4882a593Smuzhiyun static struct drm_property_blob *
dw_hdmi_rockchip_get_hdr_blob(void * data)2344*4882a593Smuzhiyun dw_hdmi_rockchip_get_hdr_blob(void *data)
2345*4882a593Smuzhiyun {
2346*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2347*4882a593Smuzhiyun 
2348*4882a593Smuzhiyun 	return hdmi->hdr_panel_blob_ptr;
2349*4882a593Smuzhiyun }
2350*4882a593Smuzhiyun 
dw_hdmi_rockchip_update_color_format(struct drm_connector_state * conn_state,void * data)2351*4882a593Smuzhiyun static void dw_hdmi_rockchip_update_color_format(struct drm_connector_state *conn_state,
2352*4882a593Smuzhiyun 						 void *data)
2353*4882a593Smuzhiyun {
2354*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2355*4882a593Smuzhiyun 
2356*4882a593Smuzhiyun 	dw_hdmi_rockchip_check_color(conn_state, hdmi);
2357*4882a593Smuzhiyun }
2358*4882a593Smuzhiyun 
2359*4882a593Smuzhiyun static bool
dw_hdmi_rockchip_get_color_changed(void * data)2360*4882a593Smuzhiyun dw_hdmi_rockchip_get_color_changed(void *data)
2361*4882a593Smuzhiyun {
2362*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2363*4882a593Smuzhiyun 	bool ret = false;
2364*4882a593Smuzhiyun 
2365*4882a593Smuzhiyun 	if (hdmi->color_changed)
2366*4882a593Smuzhiyun 		ret = true;
2367*4882a593Smuzhiyun 	hdmi->color_changed = 0;
2368*4882a593Smuzhiyun 
2369*4882a593Smuzhiyun 	return ret;
2370*4882a593Smuzhiyun }
2371*4882a593Smuzhiyun 
2372*4882a593Smuzhiyun static int
dw_hdmi_rockchip_get_yuv422_format(struct drm_connector * connector,struct edid * edid)2373*4882a593Smuzhiyun dw_hdmi_rockchip_get_yuv422_format(struct drm_connector *connector,
2374*4882a593Smuzhiyun 				   struct edid *edid)
2375*4882a593Smuzhiyun {
2376*4882a593Smuzhiyun 	if (!connector || !edid)
2377*4882a593Smuzhiyun 		return -EINVAL;
2378*4882a593Smuzhiyun 
2379*4882a593Smuzhiyun 	return rockchip_drm_get_yuv422_format(connector, edid);
2380*4882a593Smuzhiyun }
2381*4882a593Smuzhiyun 
2382*4882a593Smuzhiyun static int
dw_hdmi_rockchip_get_edid_dsc_info(void * data,struct edid * edid)2383*4882a593Smuzhiyun dw_hdmi_rockchip_get_edid_dsc_info(void *data, struct edid *edid)
2384*4882a593Smuzhiyun {
2385*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2386*4882a593Smuzhiyun 
2387*4882a593Smuzhiyun 	if (!edid)
2388*4882a593Smuzhiyun 		return -EINVAL;
2389*4882a593Smuzhiyun 
2390*4882a593Smuzhiyun 	memset(&hdmi->dsc_cap, 0, sizeof(hdmi->dsc_cap));
2391*4882a593Smuzhiyun 	hdmi->max_frl_rate_per_lane = 0;
2392*4882a593Smuzhiyun 	hdmi->max_lanes = 0;
2393*4882a593Smuzhiyun 	hdmi->add_func = 0;
2394*4882a593Smuzhiyun 
2395*4882a593Smuzhiyun 	return rockchip_drm_parse_cea_ext(&hdmi->dsc_cap,
2396*4882a593Smuzhiyun 					  &hdmi->max_frl_rate_per_lane,
2397*4882a593Smuzhiyun 					  &hdmi->max_lanes, &hdmi->add_func, edid);
2398*4882a593Smuzhiyun }
2399*4882a593Smuzhiyun 
2400*4882a593Smuzhiyun static int
dw_hdmi_rockchip_get_next_hdr_data(void * data,struct edid * edid,struct drm_connector * connector)2401*4882a593Smuzhiyun dw_hdmi_rockchip_get_next_hdr_data(void *data, struct edid *edid,
2402*4882a593Smuzhiyun 				   struct drm_connector *connector)
2403*4882a593Smuzhiyun {
2404*4882a593Smuzhiyun 	int ret;
2405*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2406*4882a593Smuzhiyun 	struct next_hdr_sink_data *sink_data = &hdmi->next_hdr_data;
2407*4882a593Smuzhiyun 	size_t size = sizeof(*sink_data);
2408*4882a593Smuzhiyun 	struct drm_property *property = hdmi->next_hdr_sink_data_property;
2409*4882a593Smuzhiyun 	struct drm_property_blob *blob = hdmi->hdr_panel_blob_ptr;
2410*4882a593Smuzhiyun 
2411*4882a593Smuzhiyun 	if (!edid)
2412*4882a593Smuzhiyun 		return -EINVAL;
2413*4882a593Smuzhiyun 
2414*4882a593Smuzhiyun 	rockchip_drm_parse_next_hdr(sink_data, edid);
2415*4882a593Smuzhiyun 
2416*4882a593Smuzhiyun 	ret = drm_property_replace_global_blob(connector->dev, &blob, size, sink_data,
2417*4882a593Smuzhiyun 					       &connector->base, property);
2418*4882a593Smuzhiyun 
2419*4882a593Smuzhiyun 	return ret;
2420*4882a593Smuzhiyun };
2421*4882a593Smuzhiyun 
dw_hdmi_rockchip_get_colorimetry(void * data,struct edid * edid)2422*4882a593Smuzhiyun static int dw_hdmi_rockchip_get_colorimetry(void *data, struct edid *edid)
2423*4882a593Smuzhiyun {
2424*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2425*4882a593Smuzhiyun 
2426*4882a593Smuzhiyun 	return rockchip_drm_parse_colorimetry_data_block(&hdmi->edid_colorimetry, edid);
2427*4882a593Smuzhiyun }
2428*4882a593Smuzhiyun 
2429*4882a593Smuzhiyun static
dw_hdmi_rockchip_get_link_cfg(void * data)2430*4882a593Smuzhiyun struct dw_hdmi_link_config *dw_hdmi_rockchip_get_link_cfg(void *data)
2431*4882a593Smuzhiyun {
2432*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2433*4882a593Smuzhiyun 
2434*4882a593Smuzhiyun 	return &hdmi->link_cfg;
2435*4882a593Smuzhiyun }
2436*4882a593Smuzhiyun 
dw_hdmi_rockchip_get_vp_id(struct drm_crtc_state * crtc_state)2437*4882a593Smuzhiyun static int dw_hdmi_rockchip_get_vp_id(struct drm_crtc_state *crtc_state)
2438*4882a593Smuzhiyun {
2439*4882a593Smuzhiyun 	struct rockchip_crtc_state *s;
2440*4882a593Smuzhiyun 
2441*4882a593Smuzhiyun 	s = to_rockchip_crtc_state(crtc_state);
2442*4882a593Smuzhiyun 
2443*4882a593Smuzhiyun 	return s->vp_id;
2444*4882a593Smuzhiyun }
2445*4882a593Smuzhiyun 
dw_hdmi_dclk_set(void * data,bool enable,int vp_id)2446*4882a593Smuzhiyun static int dw_hdmi_dclk_set(void *data, bool enable, int vp_id)
2447*4882a593Smuzhiyun {
2448*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2449*4882a593Smuzhiyun 	char clk_name[16];
2450*4882a593Smuzhiyun 	struct clk *dclk;
2451*4882a593Smuzhiyun 	int ret;
2452*4882a593Smuzhiyun 
2453*4882a593Smuzhiyun 	snprintf(clk_name, sizeof(clk_name), "dclk_vp%d", vp_id);
2454*4882a593Smuzhiyun 
2455*4882a593Smuzhiyun 	dclk = devm_clk_get_optional(hdmi->dev, clk_name);
2456*4882a593Smuzhiyun 	if (IS_ERR(dclk)) {
2457*4882a593Smuzhiyun 		DRM_DEV_ERROR(hdmi->dev, "failed to get %s\n", clk_name);
2458*4882a593Smuzhiyun 		return PTR_ERR(dclk);
2459*4882a593Smuzhiyun 	} else if (!dclk) {
2460*4882a593Smuzhiyun 		if (hdmi->is_hdmi_qp) {
2461*4882a593Smuzhiyun 			DRM_DEV_ERROR(hdmi->dev, "failed to get %s\n", clk_name);
2462*4882a593Smuzhiyun 			return -ENOENT;
2463*4882a593Smuzhiyun 		}
2464*4882a593Smuzhiyun 
2465*4882a593Smuzhiyun 		return 0;
2466*4882a593Smuzhiyun 	}
2467*4882a593Smuzhiyun 
2468*4882a593Smuzhiyun 	if (enable) {
2469*4882a593Smuzhiyun 		ret = clk_prepare_enable(dclk);
2470*4882a593Smuzhiyun 		if (ret < 0)
2471*4882a593Smuzhiyun 			DRM_DEV_ERROR(hdmi->dev, "failed to enable dclk for video port%d - %d\n",
2472*4882a593Smuzhiyun 				      vp_id, ret);
2473*4882a593Smuzhiyun 	} else {
2474*4882a593Smuzhiyun 		clk_disable_unprepare(dclk);
2475*4882a593Smuzhiyun 	}
2476*4882a593Smuzhiyun 
2477*4882a593Smuzhiyun 	return 0;
2478*4882a593Smuzhiyun }
2479*4882a593Smuzhiyun 
dw_hdmi_link_clk_set(void * data,bool enable)2480*4882a593Smuzhiyun static int dw_hdmi_link_clk_set(void *data, bool enable)
2481*4882a593Smuzhiyun {
2482*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2483*4882a593Smuzhiyun 	u64 phy_clk = hdmi->phy_bus_width;
2484*4882a593Smuzhiyun 	int ret;
2485*4882a593Smuzhiyun 
2486*4882a593Smuzhiyun 	if (enable) {
2487*4882a593Smuzhiyun 		ret = clk_prepare_enable(hdmi->link_clk);
2488*4882a593Smuzhiyun 		if (ret < 0) {
2489*4882a593Smuzhiyun 			DRM_DEV_ERROR(hdmi->dev, "failed to enable link_clk %d\n", ret);
2490*4882a593Smuzhiyun 			return ret;
2491*4882a593Smuzhiyun 		}
2492*4882a593Smuzhiyun 
2493*4882a593Smuzhiyun 		if (((phy_clk & DATA_RATE_MASK) <= 6000000) &&
2494*4882a593Smuzhiyun 		    (phy_clk & COLOR_DEPTH_10BIT))
2495*4882a593Smuzhiyun 			phy_clk = (phy_clk & DATA_RATE_MASK) * 10 * 8;
2496*4882a593Smuzhiyun 		else
2497*4882a593Smuzhiyun 			phy_clk = (phy_clk & DATA_RATE_MASK) * 100;
2498*4882a593Smuzhiyun 
2499*4882a593Smuzhiyun 		/*
2500*4882a593Smuzhiyun 		 * To be compatible with vop dclk usage scenarios, hdmi phy pll clk
2501*4882a593Smuzhiyun 		 * is set according to dclk rate.
2502*4882a593Smuzhiyun 		 * But phy pll actual frequency will varies according to the color depth.
2503*4882a593Smuzhiyun 		 * So we should get the actual frequency or clk_set_rate may not change
2504*4882a593Smuzhiyun 		 * pll frequency when 8/10 bit switch.
2505*4882a593Smuzhiyun 		 */
2506*4882a593Smuzhiyun 		clk_get_rate(hdmi->link_clk);
2507*4882a593Smuzhiyun 		clk_set_rate(hdmi->link_clk, phy_clk);
2508*4882a593Smuzhiyun 	} else {
2509*4882a593Smuzhiyun 		clk_disable_unprepare(hdmi->link_clk);
2510*4882a593Smuzhiyun 	}
2511*4882a593Smuzhiyun 	return 0;
2512*4882a593Smuzhiyun }
2513*4882a593Smuzhiyun 
2514*4882a593Smuzhiyun static bool
dw_hdmi_rockchip_check_hdr_color_change(struct drm_connector_state * conn_state,void * data)2515*4882a593Smuzhiyun dw_hdmi_rockchip_check_hdr_color_change(struct drm_connector_state *conn_state,
2516*4882a593Smuzhiyun 					void *data)
2517*4882a593Smuzhiyun {
2518*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2519*4882a593Smuzhiyun 
2520*4882a593Smuzhiyun 	if (!conn_state || !data)
2521*4882a593Smuzhiyun 		return false;
2522*4882a593Smuzhiyun 
2523*4882a593Smuzhiyun 	if (dw_hdmi_rockchip_check_color(conn_state, hdmi))
2524*4882a593Smuzhiyun 		return true;
2525*4882a593Smuzhiyun 
2526*4882a593Smuzhiyun 	return false;
2527*4882a593Smuzhiyun }
2528*4882a593Smuzhiyun 
dw_hdmi_rockchip_set_prev_bus_format(void * data,unsigned long bus_format)2529*4882a593Smuzhiyun static void dw_hdmi_rockchip_set_prev_bus_format(void *data, unsigned long bus_format)
2530*4882a593Smuzhiyun {
2531*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2532*4882a593Smuzhiyun 
2533*4882a593Smuzhiyun 	hdmi->prev_bus_format = bus_format;
2534*4882a593Smuzhiyun }
2535*4882a593Smuzhiyun 
dw_hdmi_rockchip_set_ddc_io(void * data,bool enable)2536*4882a593Smuzhiyun static void dw_hdmi_rockchip_set_ddc_io(void *data, bool enable)
2537*4882a593Smuzhiyun {
2538*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2539*4882a593Smuzhiyun 
2540*4882a593Smuzhiyun 	if (!hdmi->p || !hdmi->idle_state || !hdmi->default_state)
2541*4882a593Smuzhiyun 		return;
2542*4882a593Smuzhiyun 
2543*4882a593Smuzhiyun 	if (!enable) {
2544*4882a593Smuzhiyun 		if (pinctrl_select_state(hdmi->p, hdmi->idle_state))
2545*4882a593Smuzhiyun 			dev_err(hdmi->dev, "could not select idle state\n");
2546*4882a593Smuzhiyun 	} else {
2547*4882a593Smuzhiyun 		if (pinctrl_select_state(hdmi->p, hdmi->default_state))
2548*4882a593Smuzhiyun 			dev_err(hdmi->dev, "could not select default state\n");
2549*4882a593Smuzhiyun 	}
2550*4882a593Smuzhiyun }
2551*4882a593Smuzhiyun 
2552*4882a593Smuzhiyun static const struct drm_prop_enum_list color_depth_enum_list[] = {
2553*4882a593Smuzhiyun 	{ 0, "Automatic" }, /* Prefer highest color depth */
2554*4882a593Smuzhiyun 	{ 8, "24bit" },
2555*4882a593Smuzhiyun 	{ 10, "30bit" },
2556*4882a593Smuzhiyun };
2557*4882a593Smuzhiyun 
2558*4882a593Smuzhiyun static const struct drm_prop_enum_list drm_hdmi_output_enum_list[] = {
2559*4882a593Smuzhiyun 	{ RK_IF_FORMAT_RGB, "rgb" },
2560*4882a593Smuzhiyun 	{ RK_IF_FORMAT_YCBCR444, "ycbcr444" },
2561*4882a593Smuzhiyun 	{ RK_IF_FORMAT_YCBCR422, "ycbcr422" },
2562*4882a593Smuzhiyun 	{ RK_IF_FORMAT_YCBCR420, "ycbcr420" },
2563*4882a593Smuzhiyun 	{ RK_IF_FORMAT_YCBCR_HQ, "ycbcr_high_subsampling" },
2564*4882a593Smuzhiyun 	{ RK_IF_FORMAT_YCBCR_LQ, "ycbcr_low_subsampling" },
2565*4882a593Smuzhiyun 	{ RK_IF_FORMAT_MAX, "invalid_output" },
2566*4882a593Smuzhiyun };
2567*4882a593Smuzhiyun 
2568*4882a593Smuzhiyun static const struct drm_prop_enum_list quant_range_enum_list[] = {
2569*4882a593Smuzhiyun 	{ HDMI_QUANTIZATION_RANGE_DEFAULT, "default" },
2570*4882a593Smuzhiyun 	{ HDMI_QUANTIZATION_RANGE_LIMITED, "limit" },
2571*4882a593Smuzhiyun 	{ HDMI_QUANTIZATION_RANGE_FULL, "full" },
2572*4882a593Smuzhiyun };
2573*4882a593Smuzhiyun 
2574*4882a593Smuzhiyun static const struct drm_prop_enum_list output_hdmi_dvi_enum_list[] = {
2575*4882a593Smuzhiyun 	{ 0, "auto" },
2576*4882a593Smuzhiyun 	{ 1, "force_hdmi" },
2577*4882a593Smuzhiyun 	{ 2, "force_dvi" },
2578*4882a593Smuzhiyun };
2579*4882a593Smuzhiyun 
2580*4882a593Smuzhiyun static const struct drm_prop_enum_list output_type_cap_list[] = {
2581*4882a593Smuzhiyun 	{ 0, "DVI" },
2582*4882a593Smuzhiyun 	{ 1, "HDMI" },
2583*4882a593Smuzhiyun };
2584*4882a593Smuzhiyun 
2585*4882a593Smuzhiyun static const struct drm_prop_enum_list allm_enable_list[] = {
2586*4882a593Smuzhiyun 	{ 0, "disable" },
2587*4882a593Smuzhiyun 	{ 1, "enable" },
2588*4882a593Smuzhiyun };
2589*4882a593Smuzhiyun 
2590*4882a593Smuzhiyun static void
dw_hdmi_rockchip_attach_properties(struct drm_connector * connector,unsigned int color,int version,void * data,bool allm_en)2591*4882a593Smuzhiyun dw_hdmi_rockchip_attach_properties(struct drm_connector *connector,
2592*4882a593Smuzhiyun 				   unsigned int color, int version,
2593*4882a593Smuzhiyun 				   void *data, bool allm_en)
2594*4882a593Smuzhiyun {
2595*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2596*4882a593Smuzhiyun 	struct drm_property *prop;
2597*4882a593Smuzhiyun 	struct rockchip_drm_private *private = connector->dev->dev_private;
2598*4882a593Smuzhiyun 
2599*4882a593Smuzhiyun 	switch (color) {
2600*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_RGB101010_1X30:
2601*4882a593Smuzhiyun 		hdmi->hdmi_output = RK_IF_FORMAT_RGB;
2602*4882a593Smuzhiyun 		hdmi->colordepth = 10;
2603*4882a593Smuzhiyun 		break;
2604*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUV8_1X24:
2605*4882a593Smuzhiyun 		hdmi->hdmi_output = RK_IF_FORMAT_YCBCR444;
2606*4882a593Smuzhiyun 		hdmi->colordepth = 8;
2607*4882a593Smuzhiyun 		break;
2608*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUV10_1X30:
2609*4882a593Smuzhiyun 		hdmi->hdmi_output = RK_IF_FORMAT_YCBCR444;
2610*4882a593Smuzhiyun 		hdmi->colordepth = 10;
2611*4882a593Smuzhiyun 		break;
2612*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYVY10_1X20:
2613*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUYV10_1X20:
2614*4882a593Smuzhiyun 		hdmi->hdmi_output = RK_IF_FORMAT_YCBCR422;
2615*4882a593Smuzhiyun 		hdmi->colordepth = 10;
2616*4882a593Smuzhiyun 		break;
2617*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYVY8_1X16:
2618*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUYV8_1X16:
2619*4882a593Smuzhiyun 		hdmi->hdmi_output = RK_IF_FORMAT_YCBCR422;
2620*4882a593Smuzhiyun 		hdmi->colordepth = 8;
2621*4882a593Smuzhiyun 		break;
2622*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
2623*4882a593Smuzhiyun 		hdmi->hdmi_output = RK_IF_FORMAT_YCBCR420;
2624*4882a593Smuzhiyun 		hdmi->colordepth = 8;
2625*4882a593Smuzhiyun 		break;
2626*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
2627*4882a593Smuzhiyun 		hdmi->hdmi_output = RK_IF_FORMAT_YCBCR420;
2628*4882a593Smuzhiyun 		hdmi->colordepth = 10;
2629*4882a593Smuzhiyun 		break;
2630*4882a593Smuzhiyun 	default:
2631*4882a593Smuzhiyun 		hdmi->hdmi_output = RK_IF_FORMAT_RGB;
2632*4882a593Smuzhiyun 		hdmi->colordepth = 8;
2633*4882a593Smuzhiyun 	}
2634*4882a593Smuzhiyun 
2635*4882a593Smuzhiyun 	hdmi->bus_format = color;
2636*4882a593Smuzhiyun 	hdmi->prev_bus_format = color;
2637*4882a593Smuzhiyun 
2638*4882a593Smuzhiyun 	if (hdmi->hdmi_output == RK_IF_FORMAT_YCBCR422) {
2639*4882a593Smuzhiyun 		if (hdmi->is_hdmi_qp) {
2640*4882a593Smuzhiyun 			if (hdmi->colordepth == 12)
2641*4882a593Smuzhiyun 				hdmi->output_bus_format = MEDIA_BUS_FMT_YUYV12_1X24;
2642*4882a593Smuzhiyun 			else if (hdmi->colordepth == 10)
2643*4882a593Smuzhiyun 				hdmi->output_bus_format = MEDIA_BUS_FMT_YUYV10_1X20;
2644*4882a593Smuzhiyun 			else
2645*4882a593Smuzhiyun 				hdmi->output_bus_format = MEDIA_BUS_FMT_YUYV8_1X16;
2646*4882a593Smuzhiyun 		} else {
2647*4882a593Smuzhiyun 			if (hdmi->colordepth == 12)
2648*4882a593Smuzhiyun 				hdmi->output_bus_format = MEDIA_BUS_FMT_UYVY12_1X24;
2649*4882a593Smuzhiyun 			else if (hdmi->colordepth == 10)
2650*4882a593Smuzhiyun 				hdmi->output_bus_format = MEDIA_BUS_FMT_UYVY10_1X20;
2651*4882a593Smuzhiyun 			else
2652*4882a593Smuzhiyun 				hdmi->output_bus_format = MEDIA_BUS_FMT_UYVY8_1X16;
2653*4882a593Smuzhiyun 		}
2654*4882a593Smuzhiyun 	} else {
2655*4882a593Smuzhiyun 		hdmi->output_bus_format = hdmi->bus_format;
2656*4882a593Smuzhiyun 	}
2657*4882a593Smuzhiyun 
2658*4882a593Smuzhiyun 	/* RK3368 does not support deep color mode */
2659*4882a593Smuzhiyun 	if (!hdmi->color_depth_property && !hdmi->unsupported_deep_color) {
2660*4882a593Smuzhiyun 		prop = drm_property_create_enum(connector->dev, 0,
2661*4882a593Smuzhiyun 						RK_IF_PROP_COLOR_DEPTH,
2662*4882a593Smuzhiyun 						color_depth_enum_list,
2663*4882a593Smuzhiyun 						ARRAY_SIZE(color_depth_enum_list));
2664*4882a593Smuzhiyun 		if (prop) {
2665*4882a593Smuzhiyun 			hdmi->color_depth_property = prop;
2666*4882a593Smuzhiyun 			drm_object_attach_property(&connector->base, prop, 0);
2667*4882a593Smuzhiyun 		}
2668*4882a593Smuzhiyun 	}
2669*4882a593Smuzhiyun 
2670*4882a593Smuzhiyun 	prop = drm_property_create_enum(connector->dev, 0, RK_IF_PROP_COLOR_FORMAT,
2671*4882a593Smuzhiyun 					drm_hdmi_output_enum_list,
2672*4882a593Smuzhiyun 					ARRAY_SIZE(drm_hdmi_output_enum_list));
2673*4882a593Smuzhiyun 	if (prop) {
2674*4882a593Smuzhiyun 		hdmi->hdmi_output_property = prop;
2675*4882a593Smuzhiyun 		drm_object_attach_property(&connector->base, prop, 0);
2676*4882a593Smuzhiyun 	}
2677*4882a593Smuzhiyun 
2678*4882a593Smuzhiyun 	prop = drm_property_create_range(connector->dev, 0,
2679*4882a593Smuzhiyun 					 RK_IF_PROP_COLOR_DEPTH_CAPS,
2680*4882a593Smuzhiyun 					 0, 0xff);
2681*4882a593Smuzhiyun 	if (prop) {
2682*4882a593Smuzhiyun 		hdmi->colordepth_capacity = prop;
2683*4882a593Smuzhiyun 		drm_object_attach_property(&connector->base, prop, 0);
2684*4882a593Smuzhiyun 	}
2685*4882a593Smuzhiyun 
2686*4882a593Smuzhiyun 	prop = drm_property_create_range(connector->dev, 0,
2687*4882a593Smuzhiyun 					 RK_IF_PROP_COLOR_FORMAT_CAPS,
2688*4882a593Smuzhiyun 					 0, 0xf);
2689*4882a593Smuzhiyun 	if (prop) {
2690*4882a593Smuzhiyun 		hdmi->outputmode_capacity = prop;
2691*4882a593Smuzhiyun 		drm_object_attach_property(&connector->base, prop, 0);
2692*4882a593Smuzhiyun 	}
2693*4882a593Smuzhiyun 
2694*4882a593Smuzhiyun 	prop = drm_property_create(connector->dev,
2695*4882a593Smuzhiyun 				   DRM_MODE_PROP_BLOB |
2696*4882a593Smuzhiyun 				   DRM_MODE_PROP_IMMUTABLE,
2697*4882a593Smuzhiyun 				   "HDR_PANEL_METADATA", 0);
2698*4882a593Smuzhiyun 	if (prop) {
2699*4882a593Smuzhiyun 		hdmi->hdr_panel_metadata_property = prop;
2700*4882a593Smuzhiyun 		drm_object_attach_property(&connector->base, prop, 0);
2701*4882a593Smuzhiyun 	}
2702*4882a593Smuzhiyun 
2703*4882a593Smuzhiyun 	prop = drm_property_create(connector->dev,
2704*4882a593Smuzhiyun 				   DRM_MODE_PROP_BLOB |
2705*4882a593Smuzhiyun 				   DRM_MODE_PROP_IMMUTABLE,
2706*4882a593Smuzhiyun 				   "NEXT_HDR_SINK_DATA", 0);
2707*4882a593Smuzhiyun 	if (prop) {
2708*4882a593Smuzhiyun 		hdmi->next_hdr_sink_data_property = prop;
2709*4882a593Smuzhiyun 		drm_object_attach_property(&connector->base, prop, 0);
2710*4882a593Smuzhiyun 	}
2711*4882a593Smuzhiyun 
2712*4882a593Smuzhiyun 	prop = drm_property_create_bool(connector->dev, 0, "allm_capacity");
2713*4882a593Smuzhiyun 	if (prop) {
2714*4882a593Smuzhiyun 		hdmi->allm_capacity = prop;
2715*4882a593Smuzhiyun 		drm_object_attach_property(&connector->base, prop,
2716*4882a593Smuzhiyun 					   !!(hdmi->add_func & SUPPORT_HDMI_ALLM));
2717*4882a593Smuzhiyun 	}
2718*4882a593Smuzhiyun 
2719*4882a593Smuzhiyun 	prop = drm_property_create_enum(connector->dev, 0,
2720*4882a593Smuzhiyun 					"allm_enable",
2721*4882a593Smuzhiyun 					allm_enable_list,
2722*4882a593Smuzhiyun 					ARRAY_SIZE(allm_enable_list));
2723*4882a593Smuzhiyun 	if (prop) {
2724*4882a593Smuzhiyun 		hdmi->allm_enable = prop;
2725*4882a593Smuzhiyun 		drm_object_attach_property(&connector->base, prop, 0);
2726*4882a593Smuzhiyun 	}
2727*4882a593Smuzhiyun 	hdmi->enable_allm = allm_en;
2728*4882a593Smuzhiyun 
2729*4882a593Smuzhiyun 	prop = drm_property_create_enum(connector->dev, 0,
2730*4882a593Smuzhiyun 					"output_hdmi_dvi",
2731*4882a593Smuzhiyun 					output_hdmi_dvi_enum_list,
2732*4882a593Smuzhiyun 					ARRAY_SIZE(output_hdmi_dvi_enum_list));
2733*4882a593Smuzhiyun 	if (prop) {
2734*4882a593Smuzhiyun 		hdmi->output_hdmi_dvi = prop;
2735*4882a593Smuzhiyun 		drm_object_attach_property(&connector->base, prop, 0);
2736*4882a593Smuzhiyun 	}
2737*4882a593Smuzhiyun 
2738*4882a593Smuzhiyun 	prop = drm_property_create_enum(connector->dev, 0,
2739*4882a593Smuzhiyun 					"output_type_capacity",
2740*4882a593Smuzhiyun 					output_type_cap_list,
2741*4882a593Smuzhiyun 					ARRAY_SIZE(output_type_cap_list));
2742*4882a593Smuzhiyun 	if (prop) {
2743*4882a593Smuzhiyun 		hdmi->output_type_capacity = prop;
2744*4882a593Smuzhiyun 		drm_object_attach_property(&connector->base, prop, 0);
2745*4882a593Smuzhiyun 	}
2746*4882a593Smuzhiyun 
2747*4882a593Smuzhiyun 	if (!hdmi->is_hdmi_qp) {
2748*4882a593Smuzhiyun 		prop = drm_property_create_enum(connector->dev, 0,
2749*4882a593Smuzhiyun 						"hdmi_quant_range",
2750*4882a593Smuzhiyun 						quant_range_enum_list,
2751*4882a593Smuzhiyun 						ARRAY_SIZE(quant_range_enum_list));
2752*4882a593Smuzhiyun 		if (prop) {
2753*4882a593Smuzhiyun 			hdmi->quant_range = prop;
2754*4882a593Smuzhiyun 			drm_object_attach_property(&connector->base, prop, 0);
2755*4882a593Smuzhiyun 		}
2756*4882a593Smuzhiyun 	}
2757*4882a593Smuzhiyun 
2758*4882a593Smuzhiyun 	prop = connector->dev->mode_config.hdr_output_metadata_property;
2759*4882a593Smuzhiyun 	if (hdmi->is_hdmi_qp)
2760*4882a593Smuzhiyun 		drm_object_attach_property(&connector->base, prop, 0);
2761*4882a593Smuzhiyun 
2762*4882a593Smuzhiyun 	if (!drm_mode_create_hdmi_colorspace_property(connector))
2763*4882a593Smuzhiyun 		drm_object_attach_property(&connector->base,
2764*4882a593Smuzhiyun 					   connector->colorspace_property, 0);
2765*4882a593Smuzhiyun 	drm_object_attach_property(&connector->base, private->connector_id_prop, hdmi->id);
2766*4882a593Smuzhiyun }
2767*4882a593Smuzhiyun 
2768*4882a593Smuzhiyun static void
dw_hdmi_rockchip_destroy_properties(struct drm_connector * connector,void * data)2769*4882a593Smuzhiyun dw_hdmi_rockchip_destroy_properties(struct drm_connector *connector,
2770*4882a593Smuzhiyun 				    void *data)
2771*4882a593Smuzhiyun {
2772*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2773*4882a593Smuzhiyun 
2774*4882a593Smuzhiyun 	if (hdmi->color_depth_property) {
2775*4882a593Smuzhiyun 		drm_property_destroy(connector->dev,
2776*4882a593Smuzhiyun 				     hdmi->color_depth_property);
2777*4882a593Smuzhiyun 		hdmi->color_depth_property = NULL;
2778*4882a593Smuzhiyun 	}
2779*4882a593Smuzhiyun 
2780*4882a593Smuzhiyun 	if (hdmi->hdmi_output_property) {
2781*4882a593Smuzhiyun 		drm_property_destroy(connector->dev,
2782*4882a593Smuzhiyun 				     hdmi->hdmi_output_property);
2783*4882a593Smuzhiyun 		hdmi->hdmi_output_property = NULL;
2784*4882a593Smuzhiyun 	}
2785*4882a593Smuzhiyun 
2786*4882a593Smuzhiyun 	if (hdmi->colordepth_capacity) {
2787*4882a593Smuzhiyun 		drm_property_destroy(connector->dev,
2788*4882a593Smuzhiyun 				     hdmi->colordepth_capacity);
2789*4882a593Smuzhiyun 		hdmi->colordepth_capacity = NULL;
2790*4882a593Smuzhiyun 	}
2791*4882a593Smuzhiyun 
2792*4882a593Smuzhiyun 	if (hdmi->outputmode_capacity) {
2793*4882a593Smuzhiyun 		drm_property_destroy(connector->dev,
2794*4882a593Smuzhiyun 				     hdmi->outputmode_capacity);
2795*4882a593Smuzhiyun 		hdmi->outputmode_capacity = NULL;
2796*4882a593Smuzhiyun 	}
2797*4882a593Smuzhiyun 
2798*4882a593Smuzhiyun 	if (hdmi->quant_range) {
2799*4882a593Smuzhiyun 		drm_property_destroy(connector->dev,
2800*4882a593Smuzhiyun 				     hdmi->quant_range);
2801*4882a593Smuzhiyun 		hdmi->quant_range = NULL;
2802*4882a593Smuzhiyun 	}
2803*4882a593Smuzhiyun 
2804*4882a593Smuzhiyun 	if (hdmi->hdr_panel_metadata_property) {
2805*4882a593Smuzhiyun 		drm_property_destroy(connector->dev,
2806*4882a593Smuzhiyun 				     hdmi->hdr_panel_metadata_property);
2807*4882a593Smuzhiyun 		hdmi->hdr_panel_metadata_property = NULL;
2808*4882a593Smuzhiyun 	}
2809*4882a593Smuzhiyun 
2810*4882a593Smuzhiyun 	if (hdmi->next_hdr_sink_data_property) {
2811*4882a593Smuzhiyun 		drm_property_destroy(connector->dev,
2812*4882a593Smuzhiyun 				     hdmi->next_hdr_sink_data_property);
2813*4882a593Smuzhiyun 		hdmi->next_hdr_sink_data_property = NULL;
2814*4882a593Smuzhiyun 	}
2815*4882a593Smuzhiyun 
2816*4882a593Smuzhiyun 	if (hdmi->output_hdmi_dvi) {
2817*4882a593Smuzhiyun 		drm_property_destroy(connector->dev,
2818*4882a593Smuzhiyun 				     hdmi->output_hdmi_dvi);
2819*4882a593Smuzhiyun 		hdmi->output_hdmi_dvi = NULL;
2820*4882a593Smuzhiyun 	}
2821*4882a593Smuzhiyun 
2822*4882a593Smuzhiyun 	if (hdmi->output_type_capacity) {
2823*4882a593Smuzhiyun 		drm_property_destroy(connector->dev,
2824*4882a593Smuzhiyun 				     hdmi->output_type_capacity);
2825*4882a593Smuzhiyun 		hdmi->output_type_capacity = NULL;
2826*4882a593Smuzhiyun 	}
2827*4882a593Smuzhiyun 
2828*4882a593Smuzhiyun 	if (hdmi->allm_capacity) {
2829*4882a593Smuzhiyun 		drm_property_destroy(connector->dev,
2830*4882a593Smuzhiyun 				     hdmi->allm_capacity);
2831*4882a593Smuzhiyun 		hdmi->allm_capacity = NULL;
2832*4882a593Smuzhiyun 	}
2833*4882a593Smuzhiyun 
2834*4882a593Smuzhiyun 	if (hdmi->allm_enable) {
2835*4882a593Smuzhiyun 		drm_property_destroy(connector->dev, hdmi->allm_enable);
2836*4882a593Smuzhiyun 		hdmi->allm_enable = NULL;
2837*4882a593Smuzhiyun 	}
2838*4882a593Smuzhiyun }
2839*4882a593Smuzhiyun 
2840*4882a593Smuzhiyun static int
dw_hdmi_rockchip_set_property(struct drm_connector * connector,struct drm_connector_state * state,struct drm_property * property,u64 val,void * data)2841*4882a593Smuzhiyun dw_hdmi_rockchip_set_property(struct drm_connector *connector,
2842*4882a593Smuzhiyun 			      struct drm_connector_state *state,
2843*4882a593Smuzhiyun 			      struct drm_property *property,
2844*4882a593Smuzhiyun 			      u64 val,
2845*4882a593Smuzhiyun 			      void *data)
2846*4882a593Smuzhiyun {
2847*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2848*4882a593Smuzhiyun 	struct drm_mode_config *config = &connector->dev->mode_config;
2849*4882a593Smuzhiyun 
2850*4882a593Smuzhiyun 	if (property == hdmi->color_depth_property) {
2851*4882a593Smuzhiyun 		hdmi->colordepth = val;
2852*4882a593Smuzhiyun 		/* If hdmi is disconnected, state->crtc is null */
2853*4882a593Smuzhiyun 		if (!state->crtc)
2854*4882a593Smuzhiyun 			return 0;
2855*4882a593Smuzhiyun 		if (dw_hdmi_rockchip_check_color(state, hdmi))
2856*4882a593Smuzhiyun 			hdmi->color_changed++;
2857*4882a593Smuzhiyun 		return 0;
2858*4882a593Smuzhiyun 	} else if (property == hdmi->hdmi_output_property) {
2859*4882a593Smuzhiyun 		hdmi->hdmi_output = val;
2860*4882a593Smuzhiyun 		if (!state->crtc)
2861*4882a593Smuzhiyun 			return 0;
2862*4882a593Smuzhiyun 		if (dw_hdmi_rockchip_check_color(state, hdmi))
2863*4882a593Smuzhiyun 			hdmi->color_changed++;
2864*4882a593Smuzhiyun 		return 0;
2865*4882a593Smuzhiyun 	} else if (property == hdmi->quant_range) {
2866*4882a593Smuzhiyun 		u64 quant_range = hdmi->hdmi_quant_range;
2867*4882a593Smuzhiyun 
2868*4882a593Smuzhiyun 		hdmi->hdmi_quant_range = val;
2869*4882a593Smuzhiyun 		if (quant_range != hdmi->hdmi_quant_range)
2870*4882a593Smuzhiyun 			dw_hdmi_set_quant_range(hdmi->hdmi);
2871*4882a593Smuzhiyun 		return 0;
2872*4882a593Smuzhiyun 	} else if (property == config->hdr_output_metadata_property) {
2873*4882a593Smuzhiyun 		return 0;
2874*4882a593Smuzhiyun 	} else if (property == hdmi->output_hdmi_dvi) {
2875*4882a593Smuzhiyun 		if (!hdmi->is_hdmi_qp) {
2876*4882a593Smuzhiyun 			if (hdmi->force_output != val)
2877*4882a593Smuzhiyun 				hdmi->color_changed++;
2878*4882a593Smuzhiyun 			hdmi->force_output = val;
2879*4882a593Smuzhiyun 			dw_hdmi_set_output_type(hdmi->hdmi, val);
2880*4882a593Smuzhiyun 		} else {
2881*4882a593Smuzhiyun 			hdmi->force_output = val;
2882*4882a593Smuzhiyun 			dw_hdmi_qp_set_output_type(hdmi->hdmi_qp, val);
2883*4882a593Smuzhiyun 		}
2884*4882a593Smuzhiyun 		return 0;
2885*4882a593Smuzhiyun 	} else if (property == hdmi->colordepth_capacity) {
2886*4882a593Smuzhiyun 		return 0;
2887*4882a593Smuzhiyun 	} else if (property == hdmi->outputmode_capacity) {
2888*4882a593Smuzhiyun 		return 0;
2889*4882a593Smuzhiyun 	} else if (property == hdmi->output_type_capacity) {
2890*4882a593Smuzhiyun 		return 0;
2891*4882a593Smuzhiyun 	} else if (property == hdmi->allm_capacity) {
2892*4882a593Smuzhiyun 		return 0;
2893*4882a593Smuzhiyun 	} else if (property == hdmi->allm_enable) {
2894*4882a593Smuzhiyun 		u64 allm_enable = hdmi->enable_allm;
2895*4882a593Smuzhiyun 
2896*4882a593Smuzhiyun 		hdmi->enable_allm = val;
2897*4882a593Smuzhiyun 		if (allm_enable != hdmi->enable_allm)
2898*4882a593Smuzhiyun 			dw_hdmi_qp_set_allm_enable(hdmi->hdmi_qp, hdmi->enable_allm);
2899*4882a593Smuzhiyun 		return 0;
2900*4882a593Smuzhiyun 	}
2901*4882a593Smuzhiyun 
2902*4882a593Smuzhiyun 	DRM_ERROR("Unknown property [PROP:%d:%s]\n",
2903*4882a593Smuzhiyun 		  property->base.id, property->name);
2904*4882a593Smuzhiyun 
2905*4882a593Smuzhiyun 	return -EINVAL;
2906*4882a593Smuzhiyun }
2907*4882a593Smuzhiyun 
2908*4882a593Smuzhiyun static int
dw_hdmi_rockchip_get_property(struct drm_connector * connector,const struct drm_connector_state * state,struct drm_property * property,u64 * val,void * data)2909*4882a593Smuzhiyun dw_hdmi_rockchip_get_property(struct drm_connector *connector,
2910*4882a593Smuzhiyun 			      const struct drm_connector_state *state,
2911*4882a593Smuzhiyun 			      struct drm_property *property,
2912*4882a593Smuzhiyun 			      u64 *val,
2913*4882a593Smuzhiyun 			      void *data)
2914*4882a593Smuzhiyun {
2915*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
2916*4882a593Smuzhiyun 	struct drm_display_info *info = &connector->display_info;
2917*4882a593Smuzhiyun 	struct drm_mode_config *config = &connector->dev->mode_config;
2918*4882a593Smuzhiyun 
2919*4882a593Smuzhiyun 	if (property == hdmi->color_depth_property) {
2920*4882a593Smuzhiyun 		*val = hdmi->colordepth;
2921*4882a593Smuzhiyun 		return 0;
2922*4882a593Smuzhiyun 	} else if (property == hdmi->hdmi_output_property) {
2923*4882a593Smuzhiyun 		*val = hdmi->hdmi_output;
2924*4882a593Smuzhiyun 		return 0;
2925*4882a593Smuzhiyun 	} else if (property == hdmi->colordepth_capacity) {
2926*4882a593Smuzhiyun 		*val = BIT(RK_IF_DEPTH_8);
2927*4882a593Smuzhiyun 		/* RK3368 only support 8bit */
2928*4882a593Smuzhiyun 		if (hdmi->unsupported_deep_color)
2929*4882a593Smuzhiyun 			return 0;
2930*4882a593Smuzhiyun 		if (info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30)
2931*4882a593Smuzhiyun 			*val |= BIT(RK_IF_DEPTH_10);
2932*4882a593Smuzhiyun 		if (info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_36)
2933*4882a593Smuzhiyun 			*val |= BIT(RK_IF_DEPTH_12);
2934*4882a593Smuzhiyun 		if (info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_48)
2935*4882a593Smuzhiyun 			*val |= BIT(RK_IF_DEPTH_16);
2936*4882a593Smuzhiyun 		if (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30)
2937*4882a593Smuzhiyun 			*val |= BIT(RK_IF_DEPTH_420_10);
2938*4882a593Smuzhiyun 		if (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36)
2939*4882a593Smuzhiyun 			*val |= BIT(RK_IF_DEPTH_420_12);
2940*4882a593Smuzhiyun 		if (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48)
2941*4882a593Smuzhiyun 			*val |= BIT(RK_IF_DEPTH_420_16);
2942*4882a593Smuzhiyun 		return 0;
2943*4882a593Smuzhiyun 	} else if (property == hdmi->outputmode_capacity) {
2944*4882a593Smuzhiyun 		*val = BIT(RK_IF_FORMAT_RGB);
2945*4882a593Smuzhiyun 		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
2946*4882a593Smuzhiyun 			*val |= BIT(RK_IF_FORMAT_YCBCR444);
2947*4882a593Smuzhiyun 		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
2948*4882a593Smuzhiyun 			*val |= BIT(RK_IF_FORMAT_YCBCR422);
2949*4882a593Smuzhiyun 		if (connector->ycbcr_420_allowed &&
2950*4882a593Smuzhiyun 		    info->color_formats & DRM_COLOR_FORMAT_YCRCB420)
2951*4882a593Smuzhiyun 			*val |= BIT(RK_IF_FORMAT_YCBCR420);
2952*4882a593Smuzhiyun 		return 0;
2953*4882a593Smuzhiyun 	} else if (property == hdmi->quant_range) {
2954*4882a593Smuzhiyun 		*val = hdmi->hdmi_quant_range;
2955*4882a593Smuzhiyun 		return 0;
2956*4882a593Smuzhiyun 	} else if (property == config->hdr_output_metadata_property) {
2957*4882a593Smuzhiyun 		*val = state->hdr_output_metadata ?
2958*4882a593Smuzhiyun 			state->hdr_output_metadata->base.id : 0;
2959*4882a593Smuzhiyun 		return 0;
2960*4882a593Smuzhiyun 	} else if (property == hdmi->output_hdmi_dvi) {
2961*4882a593Smuzhiyun 		*val = hdmi->force_output;
2962*4882a593Smuzhiyun 		return 0;
2963*4882a593Smuzhiyun 	} else if (property == hdmi->output_type_capacity) {
2964*4882a593Smuzhiyun 		if (!hdmi->is_hdmi_qp)
2965*4882a593Smuzhiyun 			*val = dw_hdmi_get_output_type_cap(hdmi->hdmi);
2966*4882a593Smuzhiyun 		else
2967*4882a593Smuzhiyun 			*val = dw_hdmi_qp_get_output_type_cap(hdmi->hdmi_qp);
2968*4882a593Smuzhiyun 		return 0;
2969*4882a593Smuzhiyun 	} else if (property == hdmi->allm_capacity) {
2970*4882a593Smuzhiyun 		*val = !!(hdmi->add_func & SUPPORT_HDMI_ALLM);
2971*4882a593Smuzhiyun 		return 0;
2972*4882a593Smuzhiyun 	} else if (property == hdmi->allm_enable) {
2973*4882a593Smuzhiyun 		*val = hdmi->enable_allm;
2974*4882a593Smuzhiyun 		return 0;
2975*4882a593Smuzhiyun 	}
2976*4882a593Smuzhiyun 
2977*4882a593Smuzhiyun 	DRM_ERROR("Unknown property [PROP:%d:%s]\n",
2978*4882a593Smuzhiyun 		  property->base.id, property->name);
2979*4882a593Smuzhiyun 
2980*4882a593Smuzhiyun 	return -EINVAL;
2981*4882a593Smuzhiyun }
2982*4882a593Smuzhiyun 
2983*4882a593Smuzhiyun static const struct dw_hdmi_property_ops dw_hdmi_rockchip_property_ops = {
2984*4882a593Smuzhiyun 	.attach_properties	= dw_hdmi_rockchip_attach_properties,
2985*4882a593Smuzhiyun 	.destroy_properties	= dw_hdmi_rockchip_destroy_properties,
2986*4882a593Smuzhiyun 	.set_property		= dw_hdmi_rockchip_set_property,
2987*4882a593Smuzhiyun 	.get_property		= dw_hdmi_rockchip_get_property,
2988*4882a593Smuzhiyun };
2989*4882a593Smuzhiyun 
dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder * encoder,struct drm_display_mode * mode,struct drm_display_mode * adj)2990*4882a593Smuzhiyun static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,
2991*4882a593Smuzhiyun 					      struct drm_display_mode *mode,
2992*4882a593Smuzhiyun 					      struct drm_display_mode *adj)
2993*4882a593Smuzhiyun {
2994*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
2995*4882a593Smuzhiyun 	struct drm_crtc *crtc;
2996*4882a593Smuzhiyun 	struct rockchip_crtc_state *s;
2997*4882a593Smuzhiyun 
2998*4882a593Smuzhiyun 	if (!encoder->crtc)
2999*4882a593Smuzhiyun 		return;
3000*4882a593Smuzhiyun 	crtc = encoder->crtc;
3001*4882a593Smuzhiyun 
3002*4882a593Smuzhiyun 	if (!crtc->state)
3003*4882a593Smuzhiyun 		return;
3004*4882a593Smuzhiyun 	s = to_rockchip_crtc_state(crtc->state);
3005*4882a593Smuzhiyun 
3006*4882a593Smuzhiyun 	if (!s)
3007*4882a593Smuzhiyun 		return;
3008*4882a593Smuzhiyun 
3009*4882a593Smuzhiyun 	if (hdmi->is_hdmi_qp) {
3010*4882a593Smuzhiyun 		s->dsc_enable = 0;
3011*4882a593Smuzhiyun 		if (hdmi->link_cfg.dsc_mode)
3012*4882a593Smuzhiyun 			dw_hdmi_qp_dsc_configure(hdmi, s, crtc->state);
3013*4882a593Smuzhiyun 
3014*4882a593Smuzhiyun 		phy_set_bus_width(hdmi->phy, hdmi->phy_bus_width);
3015*4882a593Smuzhiyun 	}
3016*4882a593Smuzhiyun 
3017*4882a593Smuzhiyun 	clk_set_rate(hdmi->phyref_clk, adj->crtc_clock * 1000);
3018*4882a593Smuzhiyun }
3019*4882a593Smuzhiyun 
3020*4882a593Smuzhiyun static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {
3021*4882a593Smuzhiyun 	.enable     = dw_hdmi_rockchip_encoder_enable,
3022*4882a593Smuzhiyun 	.disable    = dw_hdmi_rockchip_encoder_disable,
3023*4882a593Smuzhiyun 	.atomic_check = dw_hdmi_rockchip_encoder_atomic_check,
3024*4882a593Smuzhiyun 	.mode_set = dw_hdmi_rockchip_encoder_mode_set,
3025*4882a593Smuzhiyun };
3026*4882a593Smuzhiyun 
3027*4882a593Smuzhiyun static void
dw_hdmi_rockchip_genphy_disable(struct dw_hdmi * dw_hdmi,void * data)3028*4882a593Smuzhiyun dw_hdmi_rockchip_genphy_disable(struct dw_hdmi *dw_hdmi, void *data)
3029*4882a593Smuzhiyun {
3030*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
3031*4882a593Smuzhiyun 
3032*4882a593Smuzhiyun 	while (hdmi->phy->power_count > 0)
3033*4882a593Smuzhiyun 		phy_power_off(hdmi->phy);
3034*4882a593Smuzhiyun }
3035*4882a593Smuzhiyun 
3036*4882a593Smuzhiyun static int
dw_hdmi_rockchip_genphy_init(struct dw_hdmi * dw_hdmi,void * data,const struct drm_display_info * display,const struct drm_display_mode * mode)3037*4882a593Smuzhiyun dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data,
3038*4882a593Smuzhiyun 			     const struct drm_display_info *display,
3039*4882a593Smuzhiyun 			     const struct drm_display_mode *mode)
3040*4882a593Smuzhiyun {
3041*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
3042*4882a593Smuzhiyun 
3043*4882a593Smuzhiyun 	dw_hdmi_rockchip_genphy_disable(dw_hdmi, data);
3044*4882a593Smuzhiyun 	dw_hdmi_set_high_tmds_clock_ratio(dw_hdmi, display);
3045*4882a593Smuzhiyun 	return phy_power_on(hdmi->phy);
3046*4882a593Smuzhiyun }
3047*4882a593Smuzhiyun 
dw_hdmi_rk3228_setup_hpd(struct dw_hdmi * dw_hdmi,void * data)3048*4882a593Smuzhiyun static void dw_hdmi_rk3228_setup_hpd(struct dw_hdmi *dw_hdmi, void *data)
3049*4882a593Smuzhiyun {
3050*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
3051*4882a593Smuzhiyun 
3052*4882a593Smuzhiyun 	dw_hdmi_phy_setup_hpd(dw_hdmi, data);
3053*4882a593Smuzhiyun 
3054*4882a593Smuzhiyun 	regmap_write(hdmi->regmap,
3055*4882a593Smuzhiyun 		RK3228_GRF_SOC_CON6,
3056*4882a593Smuzhiyun 		HIWORD_UPDATE(RK3228_HDMI_HPD_VSEL | RK3228_HDMI_SDA_VSEL |
3057*4882a593Smuzhiyun 			      RK3228_HDMI_SCL_VSEL,
3058*4882a593Smuzhiyun 			      RK3228_HDMI_HPD_VSEL | RK3228_HDMI_SDA_VSEL |
3059*4882a593Smuzhiyun 			      RK3228_HDMI_SCL_VSEL));
3060*4882a593Smuzhiyun 
3061*4882a593Smuzhiyun 	regmap_write(hdmi->regmap,
3062*4882a593Smuzhiyun 		RK3228_GRF_SOC_CON2,
3063*4882a593Smuzhiyun 		HIWORD_UPDATE(RK3228_HDMI_SDAIN_MSK | RK3228_HDMI_SCLIN_MSK,
3064*4882a593Smuzhiyun 			      RK3228_HDMI_SDAIN_MSK | RK3228_HDMI_SCLIN_MSK));
3065*4882a593Smuzhiyun }
3066*4882a593Smuzhiyun 
3067*4882a593Smuzhiyun static enum drm_connector_status
dw_hdmi_rk3328_read_hpd(struct dw_hdmi * dw_hdmi,void * data)3068*4882a593Smuzhiyun dw_hdmi_rk3328_read_hpd(struct dw_hdmi *dw_hdmi, void *data)
3069*4882a593Smuzhiyun {
3070*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
3071*4882a593Smuzhiyun 	enum drm_connector_status status;
3072*4882a593Smuzhiyun 
3073*4882a593Smuzhiyun 	status = dw_hdmi_phy_read_hpd(dw_hdmi, data);
3074*4882a593Smuzhiyun 
3075*4882a593Smuzhiyun 	if (status == connector_status_connected)
3076*4882a593Smuzhiyun 		regmap_write(hdmi->regmap,
3077*4882a593Smuzhiyun 			RK3328_GRF_SOC_CON4,
3078*4882a593Smuzhiyun 			HIWORD_UPDATE(RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V,
3079*4882a593Smuzhiyun 				      RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V));
3080*4882a593Smuzhiyun 	else
3081*4882a593Smuzhiyun 		regmap_write(hdmi->regmap,
3082*4882a593Smuzhiyun 			RK3328_GRF_SOC_CON4,
3083*4882a593Smuzhiyun 			HIWORD_UPDATE(0, RK3328_HDMI_SDA_5V |
3084*4882a593Smuzhiyun 					 RK3328_HDMI_SCL_5V));
3085*4882a593Smuzhiyun 	return status;
3086*4882a593Smuzhiyun }
3087*4882a593Smuzhiyun 
dw_hdmi_rk3328_setup_hpd(struct dw_hdmi * dw_hdmi,void * data)3088*4882a593Smuzhiyun static void dw_hdmi_rk3328_setup_hpd(struct dw_hdmi *dw_hdmi, void *data)
3089*4882a593Smuzhiyun {
3090*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
3091*4882a593Smuzhiyun 
3092*4882a593Smuzhiyun 	dw_hdmi_phy_setup_hpd(dw_hdmi, data);
3093*4882a593Smuzhiyun 
3094*4882a593Smuzhiyun 	/* Enable and map pins to 3V grf-controlled io-voltage */
3095*4882a593Smuzhiyun 	regmap_write(hdmi->regmap,
3096*4882a593Smuzhiyun 		RK3328_GRF_SOC_CON4,
3097*4882a593Smuzhiyun 		HIWORD_UPDATE(0, RK3328_HDMI_HPD_SARADC | RK3328_HDMI_CEC_5V |
3098*4882a593Smuzhiyun 				 RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V |
3099*4882a593Smuzhiyun 				 RK3328_HDMI_HPD_5V));
3100*4882a593Smuzhiyun 	regmap_write(hdmi->regmap,
3101*4882a593Smuzhiyun 		RK3328_GRF_SOC_CON3,
3102*4882a593Smuzhiyun 		HIWORD_UPDATE(0, RK3328_HDMI_SDA5V_GRF | RK3328_HDMI_SCL5V_GRF |
3103*4882a593Smuzhiyun 				 RK3328_HDMI_HPD5V_GRF |
3104*4882a593Smuzhiyun 				 RK3328_HDMI_CEC5V_GRF));
3105*4882a593Smuzhiyun 	regmap_write(hdmi->regmap,
3106*4882a593Smuzhiyun 		RK3328_GRF_SOC_CON2,
3107*4882a593Smuzhiyun 		HIWORD_UPDATE(RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK,
3108*4882a593Smuzhiyun 			      RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK |
3109*4882a593Smuzhiyun 			      RK3328_HDMI_HPD_IOE));
3110*4882a593Smuzhiyun }
3111*4882a593Smuzhiyun 
dw_hdmi_qp_rockchip_phy_disable(struct dw_hdmi_qp * dw_hdmi,void * data)3112*4882a593Smuzhiyun static void dw_hdmi_qp_rockchip_phy_disable(struct dw_hdmi_qp *dw_hdmi,
3113*4882a593Smuzhiyun 					    void *data)
3114*4882a593Smuzhiyun {
3115*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
3116*4882a593Smuzhiyun 
3117*4882a593Smuzhiyun 	while (hdmi->phy->power_count > 0)
3118*4882a593Smuzhiyun 		phy_power_off(hdmi->phy);
3119*4882a593Smuzhiyun }
3120*4882a593Smuzhiyun 
dw_hdmi_qp_rockchip_genphy_init(struct dw_hdmi_qp * dw_hdmi,void * data,struct drm_display_mode * mode)3121*4882a593Smuzhiyun static int dw_hdmi_qp_rockchip_genphy_init(struct dw_hdmi_qp *dw_hdmi, void *data,
3122*4882a593Smuzhiyun 					   struct drm_display_mode *mode)
3123*4882a593Smuzhiyun {
3124*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
3125*4882a593Smuzhiyun 
3126*4882a593Smuzhiyun 	dw_hdmi_qp_rockchip_phy_disable(dw_hdmi, data);
3127*4882a593Smuzhiyun 
3128*4882a593Smuzhiyun 	return phy_power_on(hdmi->phy);
3129*4882a593Smuzhiyun }
3130*4882a593Smuzhiyun 
3131*4882a593Smuzhiyun static enum drm_connector_status
dw_hdmi_rk3588_read_hpd(struct dw_hdmi_qp * dw_hdmi,void * data)3132*4882a593Smuzhiyun dw_hdmi_rk3588_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
3133*4882a593Smuzhiyun {
3134*4882a593Smuzhiyun 	u32 val;
3135*4882a593Smuzhiyun 	int ret;
3136*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
3137*4882a593Smuzhiyun 
3138*4882a593Smuzhiyun 	regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &val);
3139*4882a593Smuzhiyun 
3140*4882a593Smuzhiyun 	if (!hdmi->id) {
3141*4882a593Smuzhiyun 		if (val & RK3588_HDMI0_LEVEL_INT) {
3142*4882a593Smuzhiyun 			hdmi->hpd_stat = true;
3143*4882a593Smuzhiyun 			ret = connector_status_connected;
3144*4882a593Smuzhiyun 		} else {
3145*4882a593Smuzhiyun 			hdmi->hpd_stat = false;
3146*4882a593Smuzhiyun 			ret = connector_status_disconnected;
3147*4882a593Smuzhiyun 		}
3148*4882a593Smuzhiyun 	} else {
3149*4882a593Smuzhiyun 		if (val & RK3588_HDMI1_LEVEL_INT) {
3150*4882a593Smuzhiyun 			hdmi->hpd_stat = true;
3151*4882a593Smuzhiyun 			ret = connector_status_connected;
3152*4882a593Smuzhiyun 		} else {
3153*4882a593Smuzhiyun 			hdmi->hpd_stat = false;
3154*4882a593Smuzhiyun 			ret = connector_status_disconnected;
3155*4882a593Smuzhiyun 		}
3156*4882a593Smuzhiyun 	}
3157*4882a593Smuzhiyun 
3158*4882a593Smuzhiyun 	return ret;
3159*4882a593Smuzhiyun }
3160*4882a593Smuzhiyun 
dw_hdmi_rk3588_setup_hpd(struct dw_hdmi_qp * dw_hdmi,void * data)3161*4882a593Smuzhiyun static void dw_hdmi_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
3162*4882a593Smuzhiyun {
3163*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
3164*4882a593Smuzhiyun 	u32 val;
3165*4882a593Smuzhiyun 
3166*4882a593Smuzhiyun 	if (!hdmi->id) {
3167*4882a593Smuzhiyun 		val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR,
3168*4882a593Smuzhiyun 				    RK3588_HDMI0_HPD_INT_CLR) |
3169*4882a593Smuzhiyun 		      HIWORD_UPDATE(0, RK3588_HDMI0_HPD_INT_MSK);
3170*4882a593Smuzhiyun 	} else {
3171*4882a593Smuzhiyun 		val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_CLR,
3172*4882a593Smuzhiyun 				    RK3588_HDMI1_HPD_INT_CLR) |
3173*4882a593Smuzhiyun 		      HIWORD_UPDATE(0, RK3588_HDMI1_HPD_INT_MSK);
3174*4882a593Smuzhiyun 	}
3175*4882a593Smuzhiyun 
3176*4882a593Smuzhiyun 	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
3177*4882a593Smuzhiyun }
3178*4882a593Smuzhiyun 
dw_hdmi_rk3588_phy_set_mode(struct dw_hdmi_qp * dw_hdmi,void * data,u32 mode_mask,bool enable)3179*4882a593Smuzhiyun static void dw_hdmi_rk3588_phy_set_mode(struct dw_hdmi_qp *dw_hdmi, void *data,
3180*4882a593Smuzhiyun 					u32 mode_mask, bool enable)
3181*4882a593Smuzhiyun {
3182*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
3183*4882a593Smuzhiyun 
3184*4882a593Smuzhiyun 	if (!hdmi->phy)
3185*4882a593Smuzhiyun 		return;
3186*4882a593Smuzhiyun 
3187*4882a593Smuzhiyun 	/* set phy earc/frl mode */
3188*4882a593Smuzhiyun 	if (enable)
3189*4882a593Smuzhiyun 		hdmi->phy_bus_width |= mode_mask;
3190*4882a593Smuzhiyun 	else
3191*4882a593Smuzhiyun 		hdmi->phy_bus_width &= ~mode_mask;
3192*4882a593Smuzhiyun 
3193*4882a593Smuzhiyun 	phy_set_bus_width(hdmi->phy, hdmi->phy_bus_width);
3194*4882a593Smuzhiyun }
3195*4882a593Smuzhiyun 
3196*4882a593Smuzhiyun static const struct dw_hdmi_phy_ops rk3228_hdmi_phy_ops = {
3197*4882a593Smuzhiyun 	.init		= dw_hdmi_rockchip_genphy_init,
3198*4882a593Smuzhiyun 	.disable	= dw_hdmi_rockchip_genphy_disable,
3199*4882a593Smuzhiyun 	.read_hpd	= dw_hdmi_phy_read_hpd,
3200*4882a593Smuzhiyun 	.update_hpd	= dw_hdmi_phy_update_hpd,
3201*4882a593Smuzhiyun 	.setup_hpd	= dw_hdmi_rk3228_setup_hpd,
3202*4882a593Smuzhiyun };
3203*4882a593Smuzhiyun 
3204*4882a593Smuzhiyun static struct rockchip_hdmi_chip_data rk3228_chip_data = {
3205*4882a593Smuzhiyun 	.lcdsel_grf_reg = -1,
3206*4882a593Smuzhiyun };
3207*4882a593Smuzhiyun 
3208*4882a593Smuzhiyun static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = {
3209*4882a593Smuzhiyun 	.mode_valid = dw_hdmi_rockchip_mode_valid,
3210*4882a593Smuzhiyun 	.mpll_cfg = rockchip_mpll_cfg,
3211*4882a593Smuzhiyun 	.cur_ctr = rockchip_cur_ctr,
3212*4882a593Smuzhiyun 	.phy_config = rockchip_phy_config,
3213*4882a593Smuzhiyun 	.phy_data = &rk3228_chip_data,
3214*4882a593Smuzhiyun 	.phy_ops = &rk3228_hdmi_phy_ops,
3215*4882a593Smuzhiyun 	.phy_name = "inno_dw_hdmi_phy2",
3216*4882a593Smuzhiyun 	.phy_force_vendor = true,
3217*4882a593Smuzhiyun 	.max_tmdsclk = 371250,
3218*4882a593Smuzhiyun 	.ycbcr_420_allowed = true,
3219*4882a593Smuzhiyun };
3220*4882a593Smuzhiyun 
3221*4882a593Smuzhiyun static struct rockchip_hdmi_chip_data rk3288_chip_data = {
3222*4882a593Smuzhiyun 	.lcdsel_grf_reg = RK3288_GRF_SOC_CON6,
3223*4882a593Smuzhiyun 	.lcdsel_big = HIWORD_UPDATE(0, RK3288_HDMI_LCDC_SEL),
3224*4882a593Smuzhiyun 	.lcdsel_lit = HIWORD_UPDATE(RK3288_HDMI_LCDC_SEL, RK3288_HDMI_LCDC_SEL),
3225*4882a593Smuzhiyun };
3226*4882a593Smuzhiyun 
3227*4882a593Smuzhiyun static const struct dw_hdmi_plat_data rk3288_hdmi_drv_data = {
3228*4882a593Smuzhiyun 	.mode_valid = dw_hdmi_rockchip_mode_valid,
3229*4882a593Smuzhiyun 	.mpll_cfg   = rockchip_mpll_cfg,
3230*4882a593Smuzhiyun 	.mpll_cfg_420 = rockchip_rk3288w_mpll_cfg_420,
3231*4882a593Smuzhiyun 	.cur_ctr    = rockchip_cur_ctr,
3232*4882a593Smuzhiyun 	.phy_config = rockchip_phy_config,
3233*4882a593Smuzhiyun 	.phy_data = &rk3288_chip_data,
3234*4882a593Smuzhiyun 	.tmds_n_table = rockchip_werid_tmds_n_table,
3235*4882a593Smuzhiyun 	.unsupported_yuv_input = true,
3236*4882a593Smuzhiyun 	.ycbcr_420_allowed = true,
3237*4882a593Smuzhiyun };
3238*4882a593Smuzhiyun 
3239*4882a593Smuzhiyun static const struct dw_hdmi_phy_ops rk3328_hdmi_phy_ops = {
3240*4882a593Smuzhiyun 	.init		= dw_hdmi_rockchip_genphy_init,
3241*4882a593Smuzhiyun 	.disable	= dw_hdmi_rockchip_genphy_disable,
3242*4882a593Smuzhiyun 	.read_hpd	= dw_hdmi_rk3328_read_hpd,
3243*4882a593Smuzhiyun 	.update_hpd	= dw_hdmi_phy_update_hpd,
3244*4882a593Smuzhiyun 	.setup_hpd	= dw_hdmi_rk3328_setup_hpd,
3245*4882a593Smuzhiyun };
3246*4882a593Smuzhiyun 
3247*4882a593Smuzhiyun static enum drm_connector_status
dw_hdmi_rk3528_read_hpd(struct dw_hdmi * dw_hdmi,void * data)3248*4882a593Smuzhiyun dw_hdmi_rk3528_read_hpd(struct dw_hdmi *dw_hdmi, void *data)
3249*4882a593Smuzhiyun {
3250*4882a593Smuzhiyun 	return dw_hdmi_phy_read_hpd(dw_hdmi, data);
3251*4882a593Smuzhiyun }
3252*4882a593Smuzhiyun 
3253*4882a593Smuzhiyun static const struct dw_hdmi_phy_ops rk3528_hdmi_phy_ops = {
3254*4882a593Smuzhiyun 	.init		= dw_hdmi_rockchip_genphy_init,
3255*4882a593Smuzhiyun 	.disable	= dw_hdmi_rockchip_genphy_disable,
3256*4882a593Smuzhiyun 	.read_hpd	= dw_hdmi_rk3528_read_hpd,
3257*4882a593Smuzhiyun 	.update_hpd	= dw_hdmi_phy_update_hpd,
3258*4882a593Smuzhiyun 	.setup_hpd	= dw_hdmi_phy_setup_hpd,
3259*4882a593Smuzhiyun };
3260*4882a593Smuzhiyun 
3261*4882a593Smuzhiyun static struct rockchip_hdmi_chip_data rk3328_chip_data = {
3262*4882a593Smuzhiyun 	.lcdsel_grf_reg = -1,
3263*4882a593Smuzhiyun };
3264*4882a593Smuzhiyun 
3265*4882a593Smuzhiyun static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = {
3266*4882a593Smuzhiyun 	.mode_valid = dw_hdmi_rockchip_mode_valid,
3267*4882a593Smuzhiyun 	.mpll_cfg = rockchip_mpll_cfg,
3268*4882a593Smuzhiyun 	.cur_ctr = rockchip_cur_ctr,
3269*4882a593Smuzhiyun 	.phy_config = rockchip_phy_config,
3270*4882a593Smuzhiyun 	.phy_data = &rk3328_chip_data,
3271*4882a593Smuzhiyun 	.phy_ops = &rk3328_hdmi_phy_ops,
3272*4882a593Smuzhiyun 	.phy_name = "inno_dw_hdmi_phy2",
3273*4882a593Smuzhiyun 	.phy_force_vendor = true,
3274*4882a593Smuzhiyun 	.use_drm_infoframe = true,
3275*4882a593Smuzhiyun 	.max_tmdsclk = 371250,
3276*4882a593Smuzhiyun 	.ycbcr_420_allowed = true,
3277*4882a593Smuzhiyun };
3278*4882a593Smuzhiyun 
3279*4882a593Smuzhiyun static struct rockchip_hdmi_chip_data rk3368_chip_data = {
3280*4882a593Smuzhiyun 	.lcdsel_grf_reg = -1,
3281*4882a593Smuzhiyun };
3282*4882a593Smuzhiyun 
3283*4882a593Smuzhiyun static const struct dw_hdmi_plat_data rk3368_hdmi_drv_data = {
3284*4882a593Smuzhiyun 	.mode_valid = dw_hdmi_rockchip_mode_valid,
3285*4882a593Smuzhiyun 	.mpll_cfg   = rockchip_mpll_cfg,
3286*4882a593Smuzhiyun 	.mpll_cfg_420 = rockchip_mpll_cfg_420,
3287*4882a593Smuzhiyun 	.cur_ctr    = rockchip_cur_ctr,
3288*4882a593Smuzhiyun 	.phy_config = rockchip_phy_config,
3289*4882a593Smuzhiyun 	.phy_data = &rk3368_chip_data,
3290*4882a593Smuzhiyun 	.unsupported_deep_color = true,
3291*4882a593Smuzhiyun 	.max_tmdsclk = 340000,
3292*4882a593Smuzhiyun 	.ycbcr_420_allowed = true,
3293*4882a593Smuzhiyun };
3294*4882a593Smuzhiyun 
3295*4882a593Smuzhiyun static struct rockchip_hdmi_chip_data rk3399_chip_data = {
3296*4882a593Smuzhiyun 	.lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
3297*4882a593Smuzhiyun 	.lcdsel_big = HIWORD_UPDATE(0, RK3399_HDMI_LCDC_SEL),
3298*4882a593Smuzhiyun 	.lcdsel_lit = HIWORD_UPDATE(RK3399_HDMI_LCDC_SEL, RK3399_HDMI_LCDC_SEL),
3299*4882a593Smuzhiyun };
3300*4882a593Smuzhiyun 
3301*4882a593Smuzhiyun static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = {
3302*4882a593Smuzhiyun 	.mode_valid = dw_hdmi_rockchip_mode_valid,
3303*4882a593Smuzhiyun 	.mpll_cfg   = rockchip_mpll_cfg,
3304*4882a593Smuzhiyun 	.mpll_cfg_420 = rockchip_mpll_cfg_420,
3305*4882a593Smuzhiyun 	.cur_ctr    = rockchip_cur_ctr,
3306*4882a593Smuzhiyun 	.phy_config = rockchip_phy_config,
3307*4882a593Smuzhiyun 	.phy_data = &rk3399_chip_data,
3308*4882a593Smuzhiyun 	.use_drm_infoframe = true,
3309*4882a593Smuzhiyun 	.ycbcr_420_allowed = true,
3310*4882a593Smuzhiyun };
3311*4882a593Smuzhiyun 
3312*4882a593Smuzhiyun static struct rockchip_hdmi_chip_data rk3528_chip_data = {
3313*4882a593Smuzhiyun 	.lcdsel_grf_reg = -1,
3314*4882a593Smuzhiyun };
3315*4882a593Smuzhiyun 
3316*4882a593Smuzhiyun static const struct dw_hdmi_plat_data rk3528_hdmi_drv_data = {
3317*4882a593Smuzhiyun 	.mode_valid = dw_hdmi_rockchip_mode_valid,
3318*4882a593Smuzhiyun 	.mpll_cfg = rockchip_mpll_cfg,
3319*4882a593Smuzhiyun 	.cur_ctr = rockchip_cur_ctr,
3320*4882a593Smuzhiyun 	.phy_config = rockchip_phy_config,
3321*4882a593Smuzhiyun 	.phy_data = &rk3528_chip_data,
3322*4882a593Smuzhiyun 	.phy_ops = &rk3528_hdmi_phy_ops,
3323*4882a593Smuzhiyun 	.phy_name = "inno_dw_hdmi_phy2",
3324*4882a593Smuzhiyun 	.phy_force_vendor = true,
3325*4882a593Smuzhiyun 	.use_drm_infoframe = true,
3326*4882a593Smuzhiyun 	.ycbcr_420_allowed = true,
3327*4882a593Smuzhiyun };
3328*4882a593Smuzhiyun 
3329*4882a593Smuzhiyun static struct rockchip_hdmi_chip_data rk3568_chip_data = {
3330*4882a593Smuzhiyun 	.lcdsel_grf_reg = -1,
3331*4882a593Smuzhiyun 	.ddc_en_reg = RK3568_GRF_VO_CON1,
3332*4882a593Smuzhiyun };
3333*4882a593Smuzhiyun 
3334*4882a593Smuzhiyun static const struct dw_hdmi_plat_data rk3568_hdmi_drv_data = {
3335*4882a593Smuzhiyun 	.mode_valid = dw_hdmi_rockchip_mode_valid,
3336*4882a593Smuzhiyun 	.mpll_cfg   = rockchip_mpll_cfg,
3337*4882a593Smuzhiyun 	.mpll_cfg_420 = rockchip_mpll_cfg_420,
3338*4882a593Smuzhiyun 	.cur_ctr    = rockchip_cur_ctr,
3339*4882a593Smuzhiyun 	.phy_config = rockchip_phy_config,
3340*4882a593Smuzhiyun 	.phy_data = &rk3568_chip_data,
3341*4882a593Smuzhiyun 	.ycbcr_420_allowed = true,
3342*4882a593Smuzhiyun 	.use_drm_infoframe = true,
3343*4882a593Smuzhiyun };
3344*4882a593Smuzhiyun 
3345*4882a593Smuzhiyun static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = {
3346*4882a593Smuzhiyun 	.init		= dw_hdmi_qp_rockchip_genphy_init,
3347*4882a593Smuzhiyun 	.disable	= dw_hdmi_qp_rockchip_phy_disable,
3348*4882a593Smuzhiyun 	.read_hpd	= dw_hdmi_rk3588_read_hpd,
3349*4882a593Smuzhiyun 	.setup_hpd	= dw_hdmi_rk3588_setup_hpd,
3350*4882a593Smuzhiyun 	.set_mode       = dw_hdmi_rk3588_phy_set_mode,
3351*4882a593Smuzhiyun };
3352*4882a593Smuzhiyun 
3353*4882a593Smuzhiyun struct rockchip_hdmi_chip_data rk3588_hdmi_chip_data = {
3354*4882a593Smuzhiyun 	.lcdsel_grf_reg = -1,
3355*4882a593Smuzhiyun 	.ddc_en_reg = RK3588_GRF_VO1_CON3,
3356*4882a593Smuzhiyun 	.split_mode = true,
3357*4882a593Smuzhiyun };
3358*4882a593Smuzhiyun 
3359*4882a593Smuzhiyun static const struct dw_hdmi_plat_data rk3588_hdmi_drv_data = {
3360*4882a593Smuzhiyun 	.phy_data = &rk3588_hdmi_chip_data,
3361*4882a593Smuzhiyun 	.qp_phy_ops = &rk3588_hdmi_phy_ops,
3362*4882a593Smuzhiyun 	.phy_name = "samsung_hdptx_phy",
3363*4882a593Smuzhiyun 	.phy_force_vendor = true,
3364*4882a593Smuzhiyun 	.ycbcr_420_allowed = true,
3365*4882a593Smuzhiyun 	.is_hdmi_qp = true,
3366*4882a593Smuzhiyun 	.use_drm_infoframe = true,
3367*4882a593Smuzhiyun };
3368*4882a593Smuzhiyun 
3369*4882a593Smuzhiyun static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
3370*4882a593Smuzhiyun 	{ .compatible = "rockchip,rk3228-dw-hdmi",
3371*4882a593Smuzhiyun 	  .data = &rk3228_hdmi_drv_data
3372*4882a593Smuzhiyun 	},
3373*4882a593Smuzhiyun 	{ .compatible = "rockchip,rk3288-dw-hdmi",
3374*4882a593Smuzhiyun 	  .data = &rk3288_hdmi_drv_data
3375*4882a593Smuzhiyun 	},
3376*4882a593Smuzhiyun 	{ .compatible = "rockchip,rk3328-dw-hdmi",
3377*4882a593Smuzhiyun 	  .data = &rk3328_hdmi_drv_data
3378*4882a593Smuzhiyun 	},
3379*4882a593Smuzhiyun 	{
3380*4882a593Smuzhiyun 	 .compatible = "rockchip,rk3368-dw-hdmi",
3381*4882a593Smuzhiyun 	 .data = &rk3368_hdmi_drv_data
3382*4882a593Smuzhiyun 	},
3383*4882a593Smuzhiyun 	{ .compatible = "rockchip,rk3399-dw-hdmi",
3384*4882a593Smuzhiyun 	  .data = &rk3399_hdmi_drv_data
3385*4882a593Smuzhiyun 	},
3386*4882a593Smuzhiyun 	{ .compatible = "rockchip,rk3528-dw-hdmi",
3387*4882a593Smuzhiyun 	  .data = &rk3528_hdmi_drv_data
3388*4882a593Smuzhiyun 	},
3389*4882a593Smuzhiyun 	{ .compatible = "rockchip,rk3568-dw-hdmi",
3390*4882a593Smuzhiyun 	  .data = &rk3568_hdmi_drv_data
3391*4882a593Smuzhiyun 	},
3392*4882a593Smuzhiyun 	{ .compatible = "rockchip,rk3588-dw-hdmi",
3393*4882a593Smuzhiyun 	  .data = &rk3588_hdmi_drv_data
3394*4882a593Smuzhiyun 	},
3395*4882a593Smuzhiyun 	{},
3396*4882a593Smuzhiyun };
3397*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, dw_hdmi_rockchip_dt_ids);
3398*4882a593Smuzhiyun 
dw_hdmi_rockchip_bind(struct device * dev,struct device * master,void * data)3399*4882a593Smuzhiyun static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
3400*4882a593Smuzhiyun 				 void *data)
3401*4882a593Smuzhiyun {
3402*4882a593Smuzhiyun 	struct platform_device *pdev = to_platform_device(dev);
3403*4882a593Smuzhiyun 	struct drm_device *drm = data;
3404*4882a593Smuzhiyun 	struct drm_encoder *encoder;
3405*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi;
3406*4882a593Smuzhiyun 	struct dw_hdmi_plat_data *plat_data;
3407*4882a593Smuzhiyun 	struct rockchip_hdmi *secondary;
3408*4882a593Smuzhiyun 	int ret;
3409*4882a593Smuzhiyun 	u32 val;
3410*4882a593Smuzhiyun 
3411*4882a593Smuzhiyun 	if (!pdev->dev.of_node)
3412*4882a593Smuzhiyun 		return -ENODEV;
3413*4882a593Smuzhiyun 
3414*4882a593Smuzhiyun 	hdmi = platform_get_drvdata(pdev);
3415*4882a593Smuzhiyun 	if (!hdmi)
3416*4882a593Smuzhiyun 		return -ENOMEM;
3417*4882a593Smuzhiyun 
3418*4882a593Smuzhiyun 	plat_data = hdmi->plat_data;
3419*4882a593Smuzhiyun 	hdmi->drm_dev = drm;
3420*4882a593Smuzhiyun 
3421*4882a593Smuzhiyun 	plat_data->phy_data = hdmi;
3422*4882a593Smuzhiyun 	plat_data->get_input_bus_format =
3423*4882a593Smuzhiyun 		dw_hdmi_rockchip_get_input_bus_format;
3424*4882a593Smuzhiyun 	plat_data->get_output_bus_format =
3425*4882a593Smuzhiyun 		dw_hdmi_rockchip_get_output_bus_format;
3426*4882a593Smuzhiyun 	plat_data->get_enc_in_encoding =
3427*4882a593Smuzhiyun 		dw_hdmi_rockchip_get_enc_in_encoding;
3428*4882a593Smuzhiyun 	plat_data->get_enc_out_encoding =
3429*4882a593Smuzhiyun 		dw_hdmi_rockchip_get_enc_out_encoding;
3430*4882a593Smuzhiyun 	plat_data->get_quant_range =
3431*4882a593Smuzhiyun 		dw_hdmi_rockchip_get_quant_range;
3432*4882a593Smuzhiyun 	plat_data->get_hdr_property =
3433*4882a593Smuzhiyun 		dw_hdmi_rockchip_get_hdr_property;
3434*4882a593Smuzhiyun 	plat_data->get_hdr_blob =
3435*4882a593Smuzhiyun 		dw_hdmi_rockchip_get_hdr_blob;
3436*4882a593Smuzhiyun 	plat_data->get_color_changed =
3437*4882a593Smuzhiyun 		dw_hdmi_rockchip_get_color_changed;
3438*4882a593Smuzhiyun 	plat_data->get_yuv422_format =
3439*4882a593Smuzhiyun 		dw_hdmi_rockchip_get_yuv422_format;
3440*4882a593Smuzhiyun 	plat_data->get_edid_dsc_info =
3441*4882a593Smuzhiyun 		dw_hdmi_rockchip_get_edid_dsc_info;
3442*4882a593Smuzhiyun 	plat_data->get_next_hdr_data =
3443*4882a593Smuzhiyun 		dw_hdmi_rockchip_get_next_hdr_data;
3444*4882a593Smuzhiyun 	plat_data->get_colorimetry =
3445*4882a593Smuzhiyun 		dw_hdmi_rockchip_get_colorimetry;
3446*4882a593Smuzhiyun 	plat_data->get_link_cfg = dw_hdmi_rockchip_get_link_cfg;
3447*4882a593Smuzhiyun 	plat_data->set_grf_cfg = rk3588_set_grf_cfg;
3448*4882a593Smuzhiyun 	plat_data->get_grf_color_fmt = rk3588_get_grf_color_fmt;
3449*4882a593Smuzhiyun 	plat_data->convert_to_split_mode = drm_mode_convert_to_split_mode;
3450*4882a593Smuzhiyun 	plat_data->convert_to_origin_mode = drm_mode_convert_to_origin_mode;
3451*4882a593Smuzhiyun 	plat_data->dclk_set = dw_hdmi_dclk_set;
3452*4882a593Smuzhiyun 	plat_data->link_clk_set = dw_hdmi_link_clk_set;
3453*4882a593Smuzhiyun 	plat_data->get_vp_id = dw_hdmi_rockchip_get_vp_id;
3454*4882a593Smuzhiyun 	plat_data->update_color_format =
3455*4882a593Smuzhiyun 		dw_hdmi_rockchip_update_color_format;
3456*4882a593Smuzhiyun 	plat_data->check_hdr_color_change =
3457*4882a593Smuzhiyun 		dw_hdmi_rockchip_check_hdr_color_change;
3458*4882a593Smuzhiyun 	plat_data->set_prev_bus_format =
3459*4882a593Smuzhiyun 		dw_hdmi_rockchip_set_prev_bus_format;
3460*4882a593Smuzhiyun 	plat_data->set_ddc_io =
3461*4882a593Smuzhiyun 		dw_hdmi_rockchip_set_ddc_io;
3462*4882a593Smuzhiyun 	plat_data->property_ops = &dw_hdmi_rockchip_property_ops;
3463*4882a593Smuzhiyun 
3464*4882a593Smuzhiyun 	secondary = rockchip_hdmi_find_by_id(dev->driver, !hdmi->id);
3465*4882a593Smuzhiyun 	/* If don't enable hdmi0 and hdmi1, we don't enable split mode */
3466*4882a593Smuzhiyun 	if (hdmi->chip_data->split_mode && secondary) {
3467*4882a593Smuzhiyun 
3468*4882a593Smuzhiyun 		/*
3469*4882a593Smuzhiyun 		 * hdmi can only attach bridge and init encoder/connector in the
3470*4882a593Smuzhiyun 		 * last bind hdmi in split mode, or hdmi->hdmi_qp will not be initialized
3471*4882a593Smuzhiyun 		 * and plat_data->left/right will be null pointer. we must check if split
3472*4882a593Smuzhiyun 		 * mode is on and determine the sequence of hdmi bind.
3473*4882a593Smuzhiyun 		 */
3474*4882a593Smuzhiyun 		if (device_property_read_bool(dev, "split-mode") ||
3475*4882a593Smuzhiyun 		    device_property_read_bool(secondary->dev, "split-mode")) {
3476*4882a593Smuzhiyun 			plat_data->split_mode = true;
3477*4882a593Smuzhiyun 			secondary->plat_data->split_mode = true;
3478*4882a593Smuzhiyun 			if (!secondary->plat_data->first_screen)
3479*4882a593Smuzhiyun 				plat_data->first_screen = true;
3480*4882a593Smuzhiyun 		}
3481*4882a593Smuzhiyun 	}
3482*4882a593Smuzhiyun 
3483*4882a593Smuzhiyun 	if (!plat_data->first_screen) {
3484*4882a593Smuzhiyun 		encoder = &hdmi->encoder;
3485*4882a593Smuzhiyun 		encoder->possible_crtcs = rockchip_drm_of_find_possible_crtcs(drm, dev->of_node);
3486*4882a593Smuzhiyun 		/*
3487*4882a593Smuzhiyun 		 * If we failed to find the CRTC(s) which this encoder is
3488*4882a593Smuzhiyun 		 * supposed to be connected to, it's because the CRTC has
3489*4882a593Smuzhiyun 		 * not been registered yet.  Defer probing, and hope that
3490*4882a593Smuzhiyun 		 * the required CRTC is added later.
3491*4882a593Smuzhiyun 		 */
3492*4882a593Smuzhiyun 		if (encoder->possible_crtcs == 0)
3493*4882a593Smuzhiyun 			return -EPROBE_DEFER;
3494*4882a593Smuzhiyun 
3495*4882a593Smuzhiyun 		drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
3496*4882a593Smuzhiyun 		drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
3497*4882a593Smuzhiyun 	}
3498*4882a593Smuzhiyun 
3499*4882a593Smuzhiyun 	if (!plat_data->max_tmdsclk)
3500*4882a593Smuzhiyun 		hdmi->max_tmdsclk = 594000;
3501*4882a593Smuzhiyun 	else
3502*4882a593Smuzhiyun 		hdmi->max_tmdsclk = plat_data->max_tmdsclk;
3503*4882a593Smuzhiyun 
3504*4882a593Smuzhiyun 	hdmi->is_hdmi_qp = plat_data->is_hdmi_qp;
3505*4882a593Smuzhiyun 
3506*4882a593Smuzhiyun 	hdmi->unsupported_yuv_input = plat_data->unsupported_yuv_input;
3507*4882a593Smuzhiyun 	hdmi->unsupported_deep_color = plat_data->unsupported_deep_color;
3508*4882a593Smuzhiyun 
3509*4882a593Smuzhiyun 	ret = rockchip_hdmi_parse_dt(hdmi);
3510*4882a593Smuzhiyun 	if (ret) {
3511*4882a593Smuzhiyun 		DRM_DEV_ERROR(hdmi->dev, "Unable to parse OF data\n");
3512*4882a593Smuzhiyun 		return ret;
3513*4882a593Smuzhiyun 	}
3514*4882a593Smuzhiyun 
3515*4882a593Smuzhiyun 	ret = clk_prepare_enable(hdmi->aud_clk);
3516*4882a593Smuzhiyun 	if (ret) {
3517*4882a593Smuzhiyun 		dev_err(hdmi->dev, "Failed to enable HDMI aud_clk: %d\n", ret);
3518*4882a593Smuzhiyun 		return ret;
3519*4882a593Smuzhiyun 	}
3520*4882a593Smuzhiyun 
3521*4882a593Smuzhiyun 	ret = clk_prepare_enable(hdmi->hpd_clk);
3522*4882a593Smuzhiyun 	if (ret) {
3523*4882a593Smuzhiyun 		dev_err(hdmi->dev, "Failed to enable HDMI hpd_clk: %d\n", ret);
3524*4882a593Smuzhiyun 		return ret;
3525*4882a593Smuzhiyun 	}
3526*4882a593Smuzhiyun 
3527*4882a593Smuzhiyun 	ret = clk_prepare_enable(hdmi->hclk_vo1);
3528*4882a593Smuzhiyun 	if (ret) {
3529*4882a593Smuzhiyun 		dev_err(hdmi->dev, "Failed to enable HDMI hclk_vo1: %d\n", ret);
3530*4882a593Smuzhiyun 		return ret;
3531*4882a593Smuzhiyun 	}
3532*4882a593Smuzhiyun 
3533*4882a593Smuzhiyun 	ret = clk_prepare_enable(hdmi->earc_clk);
3534*4882a593Smuzhiyun 	if (ret) {
3535*4882a593Smuzhiyun 		dev_err(hdmi->dev, "Failed to enable HDMI earc_clk: %d\n", ret);
3536*4882a593Smuzhiyun 		return ret;
3537*4882a593Smuzhiyun 	}
3538*4882a593Smuzhiyun 
3539*4882a593Smuzhiyun 	ret = clk_prepare_enable(hdmi->hdmitx_ref);
3540*4882a593Smuzhiyun 	if (ret) {
3541*4882a593Smuzhiyun 		dev_err(hdmi->dev, "Failed to enable HDMI hdmitx_ref: %d\n",
3542*4882a593Smuzhiyun 			ret);
3543*4882a593Smuzhiyun 		return ret;
3544*4882a593Smuzhiyun 	}
3545*4882a593Smuzhiyun 
3546*4882a593Smuzhiyun 	ret = clk_prepare_enable(hdmi->pclk);
3547*4882a593Smuzhiyun 	if (ret) {
3548*4882a593Smuzhiyun 		dev_err(hdmi->dev, "Failed to enable HDMI pclk: %d\n", ret);
3549*4882a593Smuzhiyun 		return ret;
3550*4882a593Smuzhiyun 	}
3551*4882a593Smuzhiyun 
3552*4882a593Smuzhiyun 	if (hdmi->chip_data->ddc_en_reg == RK3568_GRF_VO_CON1) {
3553*4882a593Smuzhiyun 		regmap_write(hdmi->regmap, RK3568_GRF_VO_CON1,
3554*4882a593Smuzhiyun 			     HIWORD_UPDATE(RK3568_HDMI_SDAIN_MSK |
3555*4882a593Smuzhiyun 					   RK3568_HDMI_SCLIN_MSK,
3556*4882a593Smuzhiyun 					   RK3568_HDMI_SDAIN_MSK |
3557*4882a593Smuzhiyun 					   RK3568_HDMI_SCLIN_MSK));
3558*4882a593Smuzhiyun 	}
3559*4882a593Smuzhiyun 
3560*4882a593Smuzhiyun 	if (hdmi->is_hdmi_qp) {
3561*4882a593Smuzhiyun 		if (!hdmi->id) {
3562*4882a593Smuzhiyun 			val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) |
3563*4882a593Smuzhiyun 			      HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) |
3564*4882a593Smuzhiyun 			      HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) |
3565*4882a593Smuzhiyun 			      HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK);
3566*4882a593Smuzhiyun 			regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON3, val);
3567*4882a593Smuzhiyun 
3568*4882a593Smuzhiyun 			val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK,
3569*4882a593Smuzhiyun 					    RK3588_SET_HPD_PATH_MASK);
3570*4882a593Smuzhiyun 			regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val);
3571*4882a593Smuzhiyun 
3572*4882a593Smuzhiyun 			val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL,
3573*4882a593Smuzhiyun 					    RK3588_HDMI0_GRANT_SEL);
3574*4882a593Smuzhiyun 			regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON9, val);
3575*4882a593Smuzhiyun 		} else {
3576*4882a593Smuzhiyun 			val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) |
3577*4882a593Smuzhiyun 			      HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) |
3578*4882a593Smuzhiyun 			      HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) |
3579*4882a593Smuzhiyun 			      HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK);
3580*4882a593Smuzhiyun 			regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON6, val);
3581*4882a593Smuzhiyun 
3582*4882a593Smuzhiyun 			val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK,
3583*4882a593Smuzhiyun 					    RK3588_SET_HPD_PATH_MASK);
3584*4882a593Smuzhiyun 			regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val);
3585*4882a593Smuzhiyun 
3586*4882a593Smuzhiyun 			val = HIWORD_UPDATE(RK3588_HDMI1_GRANT_SEL,
3587*4882a593Smuzhiyun 					    RK3588_HDMI1_GRANT_SEL);
3588*4882a593Smuzhiyun 			regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON9, val);
3589*4882a593Smuzhiyun 		}
3590*4882a593Smuzhiyun 		init_hpd_work(hdmi);
3591*4882a593Smuzhiyun 	}
3592*4882a593Smuzhiyun 
3593*4882a593Smuzhiyun 	ret = clk_prepare_enable(hdmi->phyref_clk);
3594*4882a593Smuzhiyun 	if (ret) {
3595*4882a593Smuzhiyun 		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
3596*4882a593Smuzhiyun 			      ret);
3597*4882a593Smuzhiyun 		return ret;
3598*4882a593Smuzhiyun 	}
3599*4882a593Smuzhiyun 
3600*4882a593Smuzhiyun 	ret = clk_prepare_enable(hdmi->hclk_vio);
3601*4882a593Smuzhiyun 	if (ret) {
3602*4882a593Smuzhiyun 		dev_err(hdmi->dev, "Failed to enable HDMI hclk_vio: %d\n",
3603*4882a593Smuzhiyun 			ret);
3604*4882a593Smuzhiyun 		return ret;
3605*4882a593Smuzhiyun 	}
3606*4882a593Smuzhiyun 
3607*4882a593Smuzhiyun 	ret = clk_prepare_enable(hdmi->hclk_vop);
3608*4882a593Smuzhiyun 	if (ret) {
3609*4882a593Smuzhiyun 		dev_err(hdmi->dev, "Failed to enable HDMI hclk_vop: %d\n",
3610*4882a593Smuzhiyun 			ret);
3611*4882a593Smuzhiyun 		return ret;
3612*4882a593Smuzhiyun 	}
3613*4882a593Smuzhiyun 
3614*4882a593Smuzhiyun 	if (hdmi->is_hdmi_qp) {
3615*4882a593Smuzhiyun 		if (!hdmi->id)
3616*4882a593Smuzhiyun 			val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK, RK3588_HDMI0_HPD_INT_MSK);
3617*4882a593Smuzhiyun 		else
3618*4882a593Smuzhiyun 			val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_MSK, RK3588_HDMI1_HPD_INT_MSK);
3619*4882a593Smuzhiyun 		regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
3620*4882a593Smuzhiyun 
3621*4882a593Smuzhiyun 		hdmi->hpd_irq = platform_get_irq(pdev, 4);
3622*4882a593Smuzhiyun 		if (hdmi->hpd_irq < 0)
3623*4882a593Smuzhiyun 			return hdmi->hpd_irq;
3624*4882a593Smuzhiyun 
3625*4882a593Smuzhiyun 		ret = devm_request_threaded_irq(hdmi->dev, hdmi->hpd_irq,
3626*4882a593Smuzhiyun 						rockchip_hdmi_hardirq,
3627*4882a593Smuzhiyun 						rockchip_hdmi_irq,
3628*4882a593Smuzhiyun 						IRQF_SHARED, "dw-hdmi-qp-hpd",
3629*4882a593Smuzhiyun 						hdmi);
3630*4882a593Smuzhiyun 		if (ret)
3631*4882a593Smuzhiyun 			return ret;
3632*4882a593Smuzhiyun 	}
3633*4882a593Smuzhiyun 
3634*4882a593Smuzhiyun 	hdmi->phy = devm_phy_optional_get(dev, "hdmi");
3635*4882a593Smuzhiyun 	if (IS_ERR(hdmi->phy)) {
3636*4882a593Smuzhiyun 		hdmi->phy = devm_phy_optional_get(dev, "hdmi_phy");
3637*4882a593Smuzhiyun 		if (IS_ERR(hdmi->phy)) {
3638*4882a593Smuzhiyun 			ret = PTR_ERR(hdmi->phy);
3639*4882a593Smuzhiyun 			if (ret != -EPROBE_DEFER)
3640*4882a593Smuzhiyun 				DRM_DEV_ERROR(hdmi->dev, "failed to get phy\n");
3641*4882a593Smuzhiyun 			return ret;
3642*4882a593Smuzhiyun 		}
3643*4882a593Smuzhiyun 	}
3644*4882a593Smuzhiyun 
3645*4882a593Smuzhiyun 	if (hdmi->is_hdmi_qp) {
3646*4882a593Smuzhiyun 		hdmi->hdmi_qp = dw_hdmi_qp_bind(pdev, &hdmi->encoder, plat_data);
3647*4882a593Smuzhiyun 
3648*4882a593Smuzhiyun 		if (IS_ERR(hdmi->hdmi_qp)) {
3649*4882a593Smuzhiyun 			ret = PTR_ERR(hdmi->hdmi_qp);
3650*4882a593Smuzhiyun 			drm_encoder_cleanup(&hdmi->encoder);
3651*4882a593Smuzhiyun 		}
3652*4882a593Smuzhiyun 
3653*4882a593Smuzhiyun 		if (plat_data->connector) {
3654*4882a593Smuzhiyun 			hdmi->sub_dev.connector = plat_data->connector;
3655*4882a593Smuzhiyun 			hdmi->sub_dev.loader_protect = dw_hdmi_rockchip_encoder_loader_protect;
3656*4882a593Smuzhiyun 			if (secondary && device_property_read_bool(secondary->dev, "split-mode"))
3657*4882a593Smuzhiyun 				hdmi->sub_dev.of_node = secondary->dev->of_node;
3658*4882a593Smuzhiyun 			else
3659*4882a593Smuzhiyun 				hdmi->sub_dev.of_node = hdmi->dev->of_node;
3660*4882a593Smuzhiyun 
3661*4882a593Smuzhiyun 			rockchip_drm_register_sub_dev(&hdmi->sub_dev);
3662*4882a593Smuzhiyun 		}
3663*4882a593Smuzhiyun 
3664*4882a593Smuzhiyun 		if (plat_data->split_mode && secondary) {
3665*4882a593Smuzhiyun 			if (device_property_read_bool(dev, "split-mode")) {
3666*4882a593Smuzhiyun 				plat_data->right = secondary->hdmi_qp;
3667*4882a593Smuzhiyun 				secondary->plat_data->left = hdmi->hdmi_qp;
3668*4882a593Smuzhiyun 			} else {
3669*4882a593Smuzhiyun 				plat_data->left = secondary->hdmi_qp;
3670*4882a593Smuzhiyun 				secondary->plat_data->right = hdmi->hdmi_qp;
3671*4882a593Smuzhiyun 			}
3672*4882a593Smuzhiyun 		}
3673*4882a593Smuzhiyun 
3674*4882a593Smuzhiyun 		return ret;
3675*4882a593Smuzhiyun 	}
3676*4882a593Smuzhiyun 
3677*4882a593Smuzhiyun 	hdmi->hdmi = dw_hdmi_bind(pdev, &hdmi->encoder, plat_data);
3678*4882a593Smuzhiyun 
3679*4882a593Smuzhiyun 	/*
3680*4882a593Smuzhiyun 	 * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
3681*4882a593Smuzhiyun 	 * which would have called the encoder cleanup.  Do it manually.
3682*4882a593Smuzhiyun 	 */
3683*4882a593Smuzhiyun 	if (IS_ERR(hdmi->hdmi)) {
3684*4882a593Smuzhiyun 		ret = PTR_ERR(hdmi->hdmi);
3685*4882a593Smuzhiyun 		drm_encoder_cleanup(&hdmi->encoder);
3686*4882a593Smuzhiyun 		clk_disable_unprepare(hdmi->aud_clk);
3687*4882a593Smuzhiyun 		clk_disable_unprepare(hdmi->phyref_clk);
3688*4882a593Smuzhiyun 		clk_disable_unprepare(hdmi->hclk_vop);
3689*4882a593Smuzhiyun 		clk_disable_unprepare(hdmi->hpd_clk);
3690*4882a593Smuzhiyun 		clk_disable_unprepare(hdmi->hclk_vo1);
3691*4882a593Smuzhiyun 		clk_disable_unprepare(hdmi->earc_clk);
3692*4882a593Smuzhiyun 		clk_disable_unprepare(hdmi->hdmitx_ref);
3693*4882a593Smuzhiyun 		clk_disable_unprepare(hdmi->pclk);
3694*4882a593Smuzhiyun 	}
3695*4882a593Smuzhiyun 
3696*4882a593Smuzhiyun 	if (plat_data->connector) {
3697*4882a593Smuzhiyun 		hdmi->sub_dev.connector = plat_data->connector;
3698*4882a593Smuzhiyun 		hdmi->sub_dev.of_node = dev->of_node;
3699*4882a593Smuzhiyun 		rockchip_drm_register_sub_dev(&hdmi->sub_dev);
3700*4882a593Smuzhiyun 	}
3701*4882a593Smuzhiyun 
3702*4882a593Smuzhiyun 	return ret;
3703*4882a593Smuzhiyun }
3704*4882a593Smuzhiyun 
dw_hdmi_rockchip_unbind(struct device * dev,struct device * master,void * data)3705*4882a593Smuzhiyun static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
3706*4882a593Smuzhiyun 				    void *data)
3707*4882a593Smuzhiyun {
3708*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
3709*4882a593Smuzhiyun 
3710*4882a593Smuzhiyun 	if (hdmi->is_hdmi_qp) {
3711*4882a593Smuzhiyun 		cancel_delayed_work(&hdmi->work);
3712*4882a593Smuzhiyun 		flush_workqueue(hdmi->workqueue);
3713*4882a593Smuzhiyun 		destroy_workqueue(hdmi->workqueue);
3714*4882a593Smuzhiyun 	}
3715*4882a593Smuzhiyun 
3716*4882a593Smuzhiyun 	if (hdmi->sub_dev.connector)
3717*4882a593Smuzhiyun 		rockchip_drm_unregister_sub_dev(&hdmi->sub_dev);
3718*4882a593Smuzhiyun 
3719*4882a593Smuzhiyun 	if (hdmi->is_hdmi_qp)
3720*4882a593Smuzhiyun 		dw_hdmi_qp_unbind(hdmi->hdmi_qp);
3721*4882a593Smuzhiyun 	else
3722*4882a593Smuzhiyun 		dw_hdmi_unbind(hdmi->hdmi);
3723*4882a593Smuzhiyun 	clk_disable_unprepare(hdmi->aud_clk);
3724*4882a593Smuzhiyun 	clk_disable_unprepare(hdmi->phyref_clk);
3725*4882a593Smuzhiyun 	clk_disable_unprepare(hdmi->hclk_vop);
3726*4882a593Smuzhiyun 	clk_disable_unprepare(hdmi->hpd_clk);
3727*4882a593Smuzhiyun 	clk_disable_unprepare(hdmi->hclk_vo1);
3728*4882a593Smuzhiyun 	clk_disable_unprepare(hdmi->earc_clk);
3729*4882a593Smuzhiyun 	clk_disable_unprepare(hdmi->hdmitx_ref);
3730*4882a593Smuzhiyun 	clk_disable_unprepare(hdmi->pclk);
3731*4882a593Smuzhiyun }
3732*4882a593Smuzhiyun 
3733*4882a593Smuzhiyun static const struct component_ops dw_hdmi_rockchip_ops = {
3734*4882a593Smuzhiyun 	.bind	= dw_hdmi_rockchip_bind,
3735*4882a593Smuzhiyun 	.unbind	= dw_hdmi_rockchip_unbind,
3736*4882a593Smuzhiyun };
3737*4882a593Smuzhiyun 
dw_hdmi_rockchip_probe(struct platform_device * pdev)3738*4882a593Smuzhiyun static int dw_hdmi_rockchip_probe(struct platform_device *pdev)
3739*4882a593Smuzhiyun {
3740*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi;
3741*4882a593Smuzhiyun 	const struct of_device_id *match;
3742*4882a593Smuzhiyun 	struct dw_hdmi_plat_data *plat_data;
3743*4882a593Smuzhiyun 	int id;
3744*4882a593Smuzhiyun 
3745*4882a593Smuzhiyun 	hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
3746*4882a593Smuzhiyun 	if (!hdmi)
3747*4882a593Smuzhiyun 		return -ENOMEM;
3748*4882a593Smuzhiyun 
3749*4882a593Smuzhiyun 	id = of_alias_get_id(pdev->dev.of_node, "hdmi");
3750*4882a593Smuzhiyun 	if (id < 0)
3751*4882a593Smuzhiyun 		id = 0;
3752*4882a593Smuzhiyun 
3753*4882a593Smuzhiyun 	hdmi->id = id;
3754*4882a593Smuzhiyun 	hdmi->dev = &pdev->dev;
3755*4882a593Smuzhiyun 
3756*4882a593Smuzhiyun 	match = of_match_node(dw_hdmi_rockchip_dt_ids, pdev->dev.of_node);
3757*4882a593Smuzhiyun 	plat_data = devm_kmemdup(&pdev->dev, match->data,
3758*4882a593Smuzhiyun 				 sizeof(*plat_data), GFP_KERNEL);
3759*4882a593Smuzhiyun 	if (!plat_data)
3760*4882a593Smuzhiyun 		return -ENOMEM;
3761*4882a593Smuzhiyun 
3762*4882a593Smuzhiyun 	plat_data->id = hdmi->id;
3763*4882a593Smuzhiyun 	hdmi->plat_data = plat_data;
3764*4882a593Smuzhiyun 	hdmi->chip_data = plat_data->phy_data;
3765*4882a593Smuzhiyun 
3766*4882a593Smuzhiyun 	platform_set_drvdata(pdev, hdmi);
3767*4882a593Smuzhiyun 	pm_runtime_enable(&pdev->dev);
3768*4882a593Smuzhiyun 	pm_runtime_get_sync(&pdev->dev);
3769*4882a593Smuzhiyun 
3770*4882a593Smuzhiyun 	return component_add(&pdev->dev, &dw_hdmi_rockchip_ops);
3771*4882a593Smuzhiyun }
3772*4882a593Smuzhiyun 
dw_hdmi_rockchip_shutdown(struct platform_device * pdev)3773*4882a593Smuzhiyun static void dw_hdmi_rockchip_shutdown(struct platform_device *pdev)
3774*4882a593Smuzhiyun {
3775*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = dev_get_drvdata(&pdev->dev);
3776*4882a593Smuzhiyun 
3777*4882a593Smuzhiyun 	if (!hdmi)
3778*4882a593Smuzhiyun 		return;
3779*4882a593Smuzhiyun 
3780*4882a593Smuzhiyun 	if (hdmi->is_hdmi_qp) {
3781*4882a593Smuzhiyun 		if (hdmi->hpd_irq)
3782*4882a593Smuzhiyun 			disable_irq(hdmi->hpd_irq);
3783*4882a593Smuzhiyun 		cancel_delayed_work(&hdmi->work);
3784*4882a593Smuzhiyun 		flush_workqueue(hdmi->workqueue);
3785*4882a593Smuzhiyun 		dw_hdmi_qp_suspend(hdmi->dev, hdmi->hdmi_qp);
3786*4882a593Smuzhiyun 	} else {
3787*4882a593Smuzhiyun 		if (hdmi->hpd_gpiod) {
3788*4882a593Smuzhiyun 			disable_irq(hdmi->hpd_irq);
3789*4882a593Smuzhiyun 			if (hdmi->hpd_wake_en)
3790*4882a593Smuzhiyun 				disable_irq_wake(hdmi->hpd_irq);
3791*4882a593Smuzhiyun 		}
3792*4882a593Smuzhiyun 		dw_hdmi_suspend(hdmi->hdmi);
3793*4882a593Smuzhiyun 	}
3794*4882a593Smuzhiyun 	pm_runtime_put_sync(&pdev->dev);
3795*4882a593Smuzhiyun }
3796*4882a593Smuzhiyun 
dw_hdmi_rockchip_remove(struct platform_device * pdev)3797*4882a593Smuzhiyun static int dw_hdmi_rockchip_remove(struct platform_device *pdev)
3798*4882a593Smuzhiyun {
3799*4882a593Smuzhiyun 	component_del(&pdev->dev, &dw_hdmi_rockchip_ops);
3800*4882a593Smuzhiyun 	pm_runtime_disable(&pdev->dev);
3801*4882a593Smuzhiyun 
3802*4882a593Smuzhiyun 	return 0;
3803*4882a593Smuzhiyun }
3804*4882a593Smuzhiyun 
dw_hdmi_rockchip_suspend(struct device * dev)3805*4882a593Smuzhiyun static int dw_hdmi_rockchip_suspend(struct device *dev)
3806*4882a593Smuzhiyun {
3807*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
3808*4882a593Smuzhiyun 
3809*4882a593Smuzhiyun 	if (hdmi->is_hdmi_qp) {
3810*4882a593Smuzhiyun 		if (hdmi->hpd_irq)
3811*4882a593Smuzhiyun 			disable_irq(hdmi->hpd_irq);
3812*4882a593Smuzhiyun 		dw_hdmi_qp_suspend(dev, hdmi->hdmi_qp);
3813*4882a593Smuzhiyun 	} else {
3814*4882a593Smuzhiyun 		if (hdmi->hpd_gpiod)
3815*4882a593Smuzhiyun 			disable_irq(hdmi->hpd_irq);
3816*4882a593Smuzhiyun 		dw_hdmi_suspend(hdmi->hdmi);
3817*4882a593Smuzhiyun 	}
3818*4882a593Smuzhiyun 	pm_runtime_put_sync(dev);
3819*4882a593Smuzhiyun 
3820*4882a593Smuzhiyun 	return 0;
3821*4882a593Smuzhiyun }
3822*4882a593Smuzhiyun 
dw_hdmi_rockchip_resume(struct device * dev)3823*4882a593Smuzhiyun static int dw_hdmi_rockchip_resume(struct device *dev)
3824*4882a593Smuzhiyun {
3825*4882a593Smuzhiyun 	struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
3826*4882a593Smuzhiyun 	u32 val;
3827*4882a593Smuzhiyun 
3828*4882a593Smuzhiyun 	if (hdmi->is_hdmi_qp) {
3829*4882a593Smuzhiyun 		if (!hdmi->id) {
3830*4882a593Smuzhiyun 			val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) |
3831*4882a593Smuzhiyun 			      HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) |
3832*4882a593Smuzhiyun 			      HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) |
3833*4882a593Smuzhiyun 			      HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK);
3834*4882a593Smuzhiyun 			regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON3, val);
3835*4882a593Smuzhiyun 
3836*4882a593Smuzhiyun 			val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK,
3837*4882a593Smuzhiyun 					    RK3588_SET_HPD_PATH_MASK);
3838*4882a593Smuzhiyun 			regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val);
3839*4882a593Smuzhiyun 
3840*4882a593Smuzhiyun 			val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL,
3841*4882a593Smuzhiyun 					    RK3588_HDMI0_GRANT_SEL);
3842*4882a593Smuzhiyun 			regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON9, val);
3843*4882a593Smuzhiyun 		} else {
3844*4882a593Smuzhiyun 			val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) |
3845*4882a593Smuzhiyun 			      HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) |
3846*4882a593Smuzhiyun 			      HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) |
3847*4882a593Smuzhiyun 			      HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK);
3848*4882a593Smuzhiyun 			regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON6, val);
3849*4882a593Smuzhiyun 
3850*4882a593Smuzhiyun 			val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK,
3851*4882a593Smuzhiyun 					    RK3588_SET_HPD_PATH_MASK);
3852*4882a593Smuzhiyun 			regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val);
3853*4882a593Smuzhiyun 
3854*4882a593Smuzhiyun 			val = HIWORD_UPDATE(RK3588_HDMI1_GRANT_SEL,
3855*4882a593Smuzhiyun 					    RK3588_HDMI1_GRANT_SEL);
3856*4882a593Smuzhiyun 			regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON9, val);
3857*4882a593Smuzhiyun 		}
3858*4882a593Smuzhiyun 
3859*4882a593Smuzhiyun 		dw_hdmi_qp_resume(dev, hdmi->hdmi_qp);
3860*4882a593Smuzhiyun 		if (hdmi->hpd_irq)
3861*4882a593Smuzhiyun 			enable_irq(hdmi->hpd_irq);
3862*4882a593Smuzhiyun 		drm_helper_hpd_irq_event(hdmi->drm_dev);
3863*4882a593Smuzhiyun 	} else {
3864*4882a593Smuzhiyun 		if (hdmi->hpd_gpiod) {
3865*4882a593Smuzhiyun 			dw_hdmi_rk3528_gpio_hpd_init(hdmi);
3866*4882a593Smuzhiyun 			enable_irq(hdmi->hpd_irq);
3867*4882a593Smuzhiyun 		}
3868*4882a593Smuzhiyun 		dw_hdmi_resume(hdmi->hdmi);
3869*4882a593Smuzhiyun 	}
3870*4882a593Smuzhiyun 	pm_runtime_get_sync(dev);
3871*4882a593Smuzhiyun 
3872*4882a593Smuzhiyun 	return 0;
3873*4882a593Smuzhiyun }
3874*4882a593Smuzhiyun 
3875*4882a593Smuzhiyun static const struct dev_pm_ops dw_hdmi_rockchip_pm = {
3876*4882a593Smuzhiyun 	SET_SYSTEM_SLEEP_PM_OPS(dw_hdmi_rockchip_suspend,
3877*4882a593Smuzhiyun 				dw_hdmi_rockchip_resume)
3878*4882a593Smuzhiyun };
3879*4882a593Smuzhiyun 
3880*4882a593Smuzhiyun struct platform_driver dw_hdmi_rockchip_pltfm_driver = {
3881*4882a593Smuzhiyun 	.probe  = dw_hdmi_rockchip_probe,
3882*4882a593Smuzhiyun 	.remove = dw_hdmi_rockchip_remove,
3883*4882a593Smuzhiyun 	.shutdown = dw_hdmi_rockchip_shutdown,
3884*4882a593Smuzhiyun 	.driver = {
3885*4882a593Smuzhiyun 		.name = "dwhdmi-rockchip",
3886*4882a593Smuzhiyun 		.pm = &dw_hdmi_rockchip_pm,
3887*4882a593Smuzhiyun 		.of_match_table = dw_hdmi_rockchip_dt_ids,
3888*4882a593Smuzhiyun 	},
3889*4882a593Smuzhiyun };
3890