xref: /linux/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c (revision 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2014, Rockchip Electronics Co., Ltd.
4  */
5 
6 #include <linux/clk.h>
7 #include <linux/hw_bitfield.h>
8 #include <linux/media-bus-format.h>
9 #include <linux/mfd/syscon.h>
10 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 #include <linux/phy/phy.h>
13 #include <linux/regmap.h>
14 #include <linux/regulator/consumer.h>
15 
16 #include <drm/bridge/dw_hdmi.h>
17 #include <drm/drm_edid.h>
18 #include <drm/drm_managed.h>
19 #include <drm/drm_of.h>
20 #include <drm/drm_probe_helper.h>
21 
22 #include "rockchip_drm_drv.h"
23 
24 #define RK3228_GRF_SOC_CON2		0x0408
25 #define RK3228_HDMI_SDAIN_MSK		BIT(14)
26 #define RK3228_HDMI_SCLIN_MSK		BIT(13)
27 #define RK3228_GRF_SOC_CON6		0x0418
28 #define RK3228_HDMI_HPD_VSEL		BIT(6)
29 #define RK3228_HDMI_SDA_VSEL		BIT(5)
30 #define RK3228_HDMI_SCL_VSEL		BIT(4)
31 
32 #define RK3288_GRF_SOC_CON6		0x025C
33 #define RK3288_HDMI_LCDC_SEL		BIT(4)
34 
35 #define RK3328_GRF_SOC_CON2		0x0408
36 #define RK3328_HDMI_SDAIN_MSK		BIT(11)
37 #define RK3328_HDMI_SCLIN_MSK		BIT(10)
38 #define RK3328_HDMI_HPD_IOE		BIT(2)
39 #define RK3328_GRF_SOC_CON3		0x040c
40 /* need to be unset if hdmi or i2c should control voltage */
41 #define RK3328_HDMI_SDA5V_GRF		BIT(15)
42 #define RK3328_HDMI_SCL5V_GRF		BIT(14)
43 #define RK3328_HDMI_HPD5V_GRF		BIT(13)
44 #define RK3328_HDMI_CEC5V_GRF		BIT(12)
45 #define RK3328_GRF_SOC_CON4		0x0410
46 #define RK3328_HDMI_HPD_SARADC		BIT(13)
47 #define RK3328_HDMI_CEC_5V		BIT(11)
48 #define RK3328_HDMI_SDA_5V		BIT(10)
49 #define RK3328_HDMI_SCL_5V		BIT(9)
50 #define RK3328_HDMI_HPD_5V		BIT(8)
51 
52 #define RK3399_GRF_SOC_CON20		0x6250
53 #define RK3399_HDMI_LCDC_SEL		BIT(6)
54 
55 #define RK3568_GRF_VO_CON1		0x0364
56 #define RK3568_HDMI_SDAIN_MSK		BIT(15)
57 #define RK3568_HDMI_SCLIN_MSK		BIT(14)
58 
59 /**
60  * struct rockchip_hdmi_chip_data - splite the grf setting of kind of chips
61  * @lcdsel_grf_reg: grf register offset of lcdc select
62  * @lcdsel_big: reg value of selecting vop big for HDMI
63  * @lcdsel_lit: reg value of selecting vop little for HDMI
64  * @max_tmds_clock: maximum TMDS clock rate supported
65  */
66 struct rockchip_hdmi_chip_data {
67 	int	lcdsel_grf_reg;
68 	u32	lcdsel_big;
69 	u32	lcdsel_lit;
70 	int	max_tmds_clock;
71 };
72 
73 struct rockchip_hdmi {
74 	struct device *dev;
75 	struct regmap *regmap;
76 	struct rockchip_encoder encoder;
77 	const struct rockchip_hdmi_chip_data *chip_data;
78 	const struct dw_hdmi_plat_data *plat_data;
79 	struct clk *hdmiphy_clk;
80 	struct clk *ref_clk;
81 	struct clk *grf_clk;
82 	struct drm_bridge *bridge;
83 	struct dw_hdmi *hdmi;
84 	struct phy *phy;
85 };
86 
87 static struct rockchip_hdmi *to_rockchip_hdmi(struct drm_encoder *encoder)
88 {
89 	struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
90 
91 	return container_of(rkencoder, struct rockchip_hdmi, encoder);
92 }
93 
94 static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
95 	{
96 		30666000, {
97 			{ 0x00b3, 0x0000 },
98 			{ 0x2153, 0x0000 },
99 			{ 0x40f3, 0x0000 },
100 		},
101 	}, {
102 		36800000, {
103 			{ 0x00b3, 0x0000 },
104 			{ 0x2153, 0x0000 },
105 			{ 0x40a2, 0x0001 },
106 		},
107 	}, {
108 		46000000, {
109 			{ 0x00b3, 0x0000 },
110 			{ 0x2142, 0x0001 },
111 			{ 0x40a2, 0x0001 },
112 		},
113 	}, {
114 		61333000, {
115 			{ 0x0072, 0x0001 },
116 			{ 0x2142, 0x0001 },
117 			{ 0x40a2, 0x0001 },
118 		},
119 	}, {
120 		73600000, {
121 			{ 0x0072, 0x0001 },
122 			{ 0x2142, 0x0001 },
123 			{ 0x4061, 0x0002 },
124 		},
125 	}, {
126 		92000000, {
127 			{ 0x0072, 0x0001 },
128 			{ 0x2145, 0x0002 },
129 			{ 0x4061, 0x0002 },
130 		},
131 	}, {
132 		122666000, {
133 			{ 0x0051, 0x0002 },
134 			{ 0x2145, 0x0002 },
135 			{ 0x4061, 0x0002 },
136 		},
137 	}, {
138 		147200000, {
139 			{ 0x0051, 0x0002 },
140 			{ 0x2145, 0x0002 },
141 			{ 0x4064, 0x0003 },
142 		},
143 	}, {
144 		184000000, {
145 			{ 0x0051, 0x0002 },
146 			{ 0x214c, 0x0003 },
147 			{ 0x4064, 0x0003 },
148 		},
149 	}, {
150 		226666000, {
151 			{ 0x0040, 0x0003 },
152 			{ 0x214c, 0x0003 },
153 			{ 0x4064, 0x0003 },
154 		},
155 	}, {
156 		272000000, {
157 			{ 0x0040, 0x0003 },
158 			{ 0x214c, 0x0003 },
159 			{ 0x5a64, 0x0003 },
160 		},
161 	}, {
162 		340000000, {
163 			{ 0x0040, 0x0003 },
164 			{ 0x3b4c, 0x0003 },
165 			{ 0x5a64, 0x0003 },
166 		},
167 	}, {
168 		600000000, {
169 			{ 0x1a40, 0x0003 },
170 			{ 0x3b4c, 0x0003 },
171 			{ 0x5a64, 0x0003 },
172 		},
173 	}, {
174 		~0UL, {
175 			{ 0x0000, 0x0000 },
176 			{ 0x0000, 0x0000 },
177 			{ 0x0000, 0x0000 },
178 		},
179 	}
180 };
181 
182 static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
183 	/*      pixelclk    bpp8    bpp10   bpp12 */
184 	{
185 		600000000, { 0x0000, 0x0000, 0x0000 },
186 	}, {
187 		~0UL,      { 0x0000, 0x0000, 0x0000 },
188 	}
189 };
190 
191 static const struct dw_hdmi_phy_config rockchip_phy_config[] = {
192 	/*pixelclk   symbol   term   vlev*/
193 	{ 74250000,  0x8009, 0x0004, 0x0272 },
194 	{ 165000000, 0x802b, 0x0004, 0x0209 },
195 	{ 297000000, 0x8039, 0x0005, 0x028d },
196 	{ 594000000, 0x8039, 0x0000, 0x019d },
197 	{ ~0UL,	     0x0000, 0x0000, 0x0000 },
198 };
199 
200 static enum drm_mode_status
201 dw_hdmi_rockchip_mode_valid(struct dw_hdmi *dw_hdmi, void *data,
202 			    const struct drm_display_info *info,
203 			    const struct drm_display_mode *mode)
204 {
205 	struct rockchip_hdmi *hdmi = data;
206 	int pclk = mode->clock * 1000;
207 
208 	if (hdmi->chip_data->max_tmds_clock &&
209 	    mode->clock > hdmi->chip_data->max_tmds_clock)
210 		return MODE_CLOCK_HIGH;
211 
212 	if (hdmi->ref_clk) {
213 		int rpclk = clk_round_rate(hdmi->ref_clk, pclk);
214 
215 		if (rpclk < 0 || abs(rpclk - pclk) > pclk / 1000)
216 			return MODE_NOCLOCK;
217 	}
218 
219 	if (hdmi->hdmiphy_clk) {
220 		int rpclk = clk_round_rate(hdmi->hdmiphy_clk, pclk);
221 
222 		if (rpclk < 0 || abs(rpclk - pclk) > pclk / 1000)
223 			return MODE_NOCLOCK;
224 	}
225 
226 	return MODE_OK;
227 }
228 
229 static void
230 dw_hdmi_rockchip_encoder_atomic_mode_set(struct drm_encoder *encoder,
231 					 struct drm_crtc_state *crtc_state,
232 					 struct drm_connector_state *conn_state)
233 {
234 	struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
235 	struct drm_display_mode *adj_mode = &crtc_state->adjusted_mode;
236 
237 	if (hdmi->phy && conn_state->hdmi.tmds_char_rate) {
238 		union phy_configure_opts opts = {};
239 
240 		opts.hdmi.bpc = conn_state->hdmi.output_bpc;
241 		opts.hdmi.tmds_char_rate = conn_state->hdmi.tmds_char_rate;
242 
243 		phy_configure(hdmi->phy, &opts);
244 	}
245 
246 	clk_set_rate(hdmi->ref_clk, adj_mode->clock * 1000);
247 }
248 
249 static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
250 {
251 	struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
252 	u32 val;
253 	int ret;
254 
255 	if (hdmi->chip_data->lcdsel_grf_reg < 0)
256 		return;
257 
258 	ret = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder);
259 	if (ret)
260 		val = hdmi->chip_data->lcdsel_lit;
261 	else
262 		val = hdmi->chip_data->lcdsel_big;
263 
264 	ret = clk_prepare_enable(hdmi->grf_clk);
265 	if (ret < 0) {
266 		dev_err(hdmi->dev, "failed to enable grfclk %d\n", ret);
267 		return;
268 	}
269 
270 	ret = regmap_write(hdmi->regmap, hdmi->chip_data->lcdsel_grf_reg, val);
271 	if (ret != 0)
272 		dev_err(hdmi->dev, "Could not write to GRF: %d\n", ret);
273 
274 	clk_disable_unprepare(hdmi->grf_clk);
275 	dev_dbg(hdmi->dev, "vop %s output to hdmi\n", ret ? "LIT" : "BIG");
276 }
277 
278 static u32 dw_hdmi_rockchip_get_bus_format(struct drm_encoder *encoder,
279 					   struct drm_connector_state *conn_state)
280 {
281 	struct drm_bridge *bridge __free(drm_bridge_put) = NULL;
282 	struct drm_bridge_state *bridge_state;
283 
284 	bridge = drm_bridge_chain_get_first_bridge(encoder);
285 	if (!bridge)
286 		return 0;
287 
288 	bridge_state = drm_atomic_get_bridge_state(conn_state->state, bridge);
289 	if (!bridge_state)
290 		return 0;
291 
292 	if (bridge_state->input_bus_cfg.format != MEDIA_BUS_FMT_FIXED)
293 		return bridge_state->input_bus_cfg.format;
294 
295 	return bridge_state->output_bus_cfg.format;
296 }
297 
298 static int
299 dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
300 				      struct drm_crtc_state *crtc_state,
301 				      struct drm_connector_state *conn_state)
302 {
303 	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
304 	struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
305 	union phy_configure_opts opts = {};
306 	u32 bus_format;
307 
308 	bus_format = dw_hdmi_rockchip_get_bus_format(encoder, conn_state);
309 
310 	switch (bus_format) {
311 	case MEDIA_BUS_FMT_FIXED:
312 		bus_format = MEDIA_BUS_FMT_RGB888_1X24;
313 		fallthrough;
314 	case MEDIA_BUS_FMT_RGB888_1X24:
315 	case MEDIA_BUS_FMT_RGB101010_1X30:
316 	case MEDIA_BUS_FMT_YUV8_1X24:
317 	case MEDIA_BUS_FMT_YUV10_1X30:
318 		s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
319 		break;
320 	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
321 	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
322 		s->output_mode = ROCKCHIP_OUT_MODE_YUV420;
323 		break;
324 	default:
325 		return -EINVAL;
326 	}
327 
328 	s->output_type = DRM_MODE_CONNECTOR_HDMIA;
329 	s->bus_format = bus_format;
330 
331 	if (!hdmi->phy || !conn_state->hdmi.tmds_char_rate)
332 		return 0;
333 
334 	opts.hdmi.bpc = conn_state->hdmi.output_bpc;
335 	opts.hdmi.tmds_char_rate = conn_state->hdmi.tmds_char_rate;
336 
337 	return phy_validate(hdmi->phy, PHY_MODE_HDMI, PHY_HDMI_MODE_TMDS, &opts);
338 }
339 
340 static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {
341 	.atomic_mode_set = dw_hdmi_rockchip_encoder_atomic_mode_set,
342 	.enable = dw_hdmi_rockchip_encoder_enable,
343 	.atomic_check = dw_hdmi_rockchip_encoder_atomic_check,
344 };
345 
346 static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data,
347 					const struct drm_display_info *display,
348 					const struct drm_display_mode *mode)
349 {
350 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
351 
352 	dw_hdmi_set_high_tmds_clock_ratio(dw_hdmi, display);
353 
354 	return phy_power_on(hdmi->phy);
355 }
356 
357 static void dw_hdmi_rockchip_genphy_disable(struct dw_hdmi *dw_hdmi, void *data)
358 {
359 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
360 
361 	phy_power_off(hdmi->phy);
362 }
363 
364 static void dw_hdmi_rk3228_setup_hpd(struct dw_hdmi *dw_hdmi, void *data)
365 {
366 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
367 
368 	dw_hdmi_phy_setup_hpd(dw_hdmi, data);
369 
370 	regmap_write(hdmi->regmap, RK3228_GRF_SOC_CON6,
371 		     FIELD_PREP_WM16(RK3228_HDMI_HPD_VSEL, 1) |
372 		     FIELD_PREP_WM16(RK3228_HDMI_SDA_VSEL, 1) |
373 		     FIELD_PREP_WM16(RK3228_HDMI_SCL_VSEL, 1));
374 
375 	regmap_write(hdmi->regmap, RK3228_GRF_SOC_CON2,
376 		     FIELD_PREP_WM16(RK3228_HDMI_SDAIN_MSK, 1) |
377 		     FIELD_PREP_WM16(RK3228_HDMI_SCLIN_MSK, 1));
378 }
379 
380 static enum drm_connector_status
381 dw_hdmi_rk3328_read_hpd(struct dw_hdmi *dw_hdmi, void *data)
382 {
383 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
384 	enum drm_connector_status status;
385 
386 	status = dw_hdmi_phy_read_hpd(dw_hdmi, data);
387 
388 	if (status == connector_status_connected)
389 		regmap_write(hdmi->regmap, RK3328_GRF_SOC_CON4,
390 			     FIELD_PREP_WM16(RK3328_HDMI_SDA_5V, 1) |
391 			     FIELD_PREP_WM16(RK3328_HDMI_SCL_5V, 1));
392 	else
393 		regmap_write(hdmi->regmap, RK3328_GRF_SOC_CON4,
394 			     FIELD_PREP_WM16(RK3328_HDMI_SDA_5V, 0) |
395 			     FIELD_PREP_WM16(RK3328_HDMI_SCL_5V, 0));
396 	return status;
397 }
398 
399 static void dw_hdmi_rk3328_setup_hpd(struct dw_hdmi *dw_hdmi, void *data)
400 {
401 	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
402 
403 	dw_hdmi_phy_setup_hpd(dw_hdmi, data);
404 
405 	/* Enable and map pins to 3V grf-controlled io-voltage */
406 	regmap_write(hdmi->regmap, RK3328_GRF_SOC_CON4,
407 		     FIELD_PREP_WM16(RK3328_HDMI_HPD_SARADC, 0) |
408 		     FIELD_PREP_WM16(RK3328_HDMI_CEC_5V, 0) |
409 		     FIELD_PREP_WM16(RK3328_HDMI_SDA_5V, 0) |
410 		     FIELD_PREP_WM16(RK3328_HDMI_SCL_5V, 0) |
411 		     FIELD_PREP_WM16(RK3328_HDMI_HPD_5V, 0));
412 	regmap_write(hdmi->regmap, RK3328_GRF_SOC_CON3,
413 		     FIELD_PREP_WM16(RK3328_HDMI_SDA5V_GRF, 0) |
414 		     FIELD_PREP_WM16(RK3328_HDMI_SCL5V_GRF, 0) |
415 		     FIELD_PREP_WM16(RK3328_HDMI_HPD5V_GRF, 0) |
416 		     FIELD_PREP_WM16(RK3328_HDMI_CEC5V_GRF, 0));
417 	regmap_write(hdmi->regmap, RK3328_GRF_SOC_CON2,
418 		     FIELD_PREP_WM16(RK3328_HDMI_SDAIN_MSK, 1) |
419 		     FIELD_PREP_WM16(RK3328_HDMI_SCLIN_MSK, 1) |
420 		     FIELD_PREP_WM16(RK3328_HDMI_HPD_IOE, 0));
421 
422 	dw_hdmi_rk3328_read_hpd(dw_hdmi, data);
423 }
424 
425 static const struct dw_hdmi_phy_ops rk3228_hdmi_phy_ops = {
426 	.init		= dw_hdmi_rockchip_genphy_init,
427 	.disable	= dw_hdmi_rockchip_genphy_disable,
428 	.read_hpd	= dw_hdmi_phy_read_hpd,
429 	.update_hpd	= dw_hdmi_phy_update_hpd,
430 	.setup_hpd	= dw_hdmi_rk3228_setup_hpd,
431 };
432 
433 static struct rockchip_hdmi_chip_data rk3228_chip_data = {
434 	.lcdsel_grf_reg = -1,
435 	.max_tmds_clock = 594000,
436 };
437 
438 static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = {
439 	.mode_valid = dw_hdmi_rockchip_mode_valid,
440 	.phy_data = &rk3228_chip_data,
441 	.phy_ops = &rk3228_hdmi_phy_ops,
442 	.phy_name = "inno_dw_hdmi_phy2",
443 	.phy_force_vendor = true,
444 };
445 
446 static struct rockchip_hdmi_chip_data rk3288_chip_data = {
447 	.lcdsel_grf_reg = RK3288_GRF_SOC_CON6,
448 	.lcdsel_big = FIELD_PREP_WM16_CONST(RK3288_HDMI_LCDC_SEL, 0),
449 	.lcdsel_lit = FIELD_PREP_WM16_CONST(RK3288_HDMI_LCDC_SEL, 1),
450 	.max_tmds_clock = 340000,
451 };
452 
453 static const struct dw_hdmi_plat_data rk3288_hdmi_drv_data = {
454 	.mode_valid = dw_hdmi_rockchip_mode_valid,
455 	.mpll_cfg   = rockchip_mpll_cfg,
456 	.cur_ctr    = rockchip_cur_ctr,
457 	.phy_config = rockchip_phy_config,
458 	.phy_data = &rk3288_chip_data,
459 };
460 
461 static const struct dw_hdmi_phy_ops rk3328_hdmi_phy_ops = {
462 	.init		= dw_hdmi_rockchip_genphy_init,
463 	.disable	= dw_hdmi_rockchip_genphy_disable,
464 	.read_hpd	= dw_hdmi_rk3328_read_hpd,
465 	.update_hpd	= dw_hdmi_phy_update_hpd,
466 	.setup_hpd	= dw_hdmi_rk3328_setup_hpd,
467 };
468 
469 static struct rockchip_hdmi_chip_data rk3328_chip_data = {
470 	.lcdsel_grf_reg = -1,
471 	.max_tmds_clock = 594000,
472 };
473 
474 static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = {
475 	.mode_valid = dw_hdmi_rockchip_mode_valid,
476 	.phy_data = &rk3328_chip_data,
477 	.phy_ops = &rk3328_hdmi_phy_ops,
478 	.phy_name = "inno_dw_hdmi_phy2",
479 	.phy_force_vendor = true,
480 	.use_drm_infoframe = true,
481 };
482 
483 static struct rockchip_hdmi_chip_data rk3368_chip_data = {
484 	.lcdsel_grf_reg = -1,
485 };
486 
487 static const struct dw_hdmi_plat_data rk3368_hdmi_drv_data = {
488 	.mode_valid = dw_hdmi_rockchip_mode_valid,
489 	.mpll_cfg   = rockchip_mpll_cfg,
490 	.cur_ctr    = rockchip_cur_ctr,
491 	.phy_config = rockchip_phy_config,
492 	.phy_data = &rk3368_chip_data,
493 	.use_drm_infoframe = true,
494 };
495 
496 static struct rockchip_hdmi_chip_data rk3399_chip_data = {
497 	.lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
498 	.lcdsel_big = FIELD_PREP_WM16_CONST(RK3399_HDMI_LCDC_SEL, 0),
499 	.lcdsel_lit = FIELD_PREP_WM16_CONST(RK3399_HDMI_LCDC_SEL, 1),
500 	.max_tmds_clock = 594000,
501 };
502 
503 static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = {
504 	.mode_valid = dw_hdmi_rockchip_mode_valid,
505 	.mpll_cfg   = rockchip_mpll_cfg,
506 	.cur_ctr    = rockchip_cur_ctr,
507 	.phy_config = rockchip_phy_config,
508 	.phy_data = &rk3399_chip_data,
509 	.use_drm_infoframe = true,
510 };
511 
512 static struct rockchip_hdmi_chip_data rk3568_chip_data = {
513 	.lcdsel_grf_reg = -1,
514 	.max_tmds_clock = 594000,
515 };
516 
517 static const struct dw_hdmi_plat_data rk3568_hdmi_drv_data = {
518 	.mode_valid = dw_hdmi_rockchip_mode_valid,
519 	.mpll_cfg   = rockchip_mpll_cfg,
520 	.cur_ctr    = rockchip_cur_ctr,
521 	.phy_config = rockchip_phy_config,
522 	.phy_data = &rk3568_chip_data,
523 	.use_drm_infoframe = true,
524 	.output_port = 1,
525 };
526 
527 static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
528 	{ .compatible = "rockchip,rk3228-dw-hdmi",
529 	  .data = &rk3228_hdmi_drv_data
530 	},
531 	{ .compatible = "rockchip,rk3288-dw-hdmi",
532 	  .data = &rk3288_hdmi_drv_data
533 	},
534 	{ .compatible = "rockchip,rk3328-dw-hdmi",
535 	  .data = &rk3328_hdmi_drv_data
536 	},
537 	{ .compatible = "rockchip,rk3368-dw-hdmi",
538 	 .data = &rk3368_hdmi_drv_data
539 	},
540 	{ .compatible = "rockchip,rk3399-dw-hdmi",
541 	  .data = &rk3399_hdmi_drv_data
542 	},
543 	{ .compatible = "rockchip,rk3568-dw-hdmi",
544 	  .data = &rk3568_hdmi_drv_data
545 	},
546 	{},
547 };
548 MODULE_DEVICE_TABLE(of, dw_hdmi_rockchip_dt_ids);
549 
550 static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
551 				 void *data)
552 {
553 	struct platform_device *pdev = to_platform_device(dev);
554 	struct device_node *np = dev_of_node(dev);
555 	const struct dw_hdmi_plat_data *drv_data;
556 	struct dw_hdmi_plat_data *plat_data;
557 	struct drm_device *drm = data;
558 	struct drm_encoder *encoder;
559 	struct rockchip_hdmi *hdmi;
560 	int ret, index;
561 
562 	if (!np)
563 		return -ENODEV;
564 
565 	drv_data = of_device_get_match_data(dev);
566 	if (!drv_data)
567 		return -ENODEV;
568 
569 	hdmi = drmm_kzalloc(drm, sizeof(*hdmi), GFP_KERNEL);
570 	if (!hdmi)
571 		return -ENOMEM;
572 
573 	plat_data = drmm_kzalloc(drm, sizeof(*drv_data), GFP_KERNEL);
574 	if (!plat_data)
575 		return -ENOMEM;
576 	memcpy(plat_data, drv_data, sizeof(*drv_data));
577 
578 	hdmi->dev = dev;
579 	hdmi->plat_data = plat_data;
580 	hdmi->chip_data = plat_data->phy_data;
581 	plat_data->phy_data = hdmi;
582 	plat_data->priv_data = hdmi;
583 	encoder = &hdmi->encoder.encoder;
584 
585 	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, np);
586 	rockchip_drm_encoder_set_crtc_endpoint_id(&hdmi->encoder,
587 						  np, 0, 0);
588 
589 	/*
590 	 * If we failed to find the CRTC(s) which this encoder is
591 	 * supposed to be connected to, it's because the CRTC has
592 	 * not been registered yet.  Defer probing, and hope that
593 	 * the required CRTC is added later.
594 	 */
595 	if (encoder->possible_crtcs == 0)
596 		return dev_err_probe(dev, -EPROBE_DEFER,
597 				     "failed to find possible crtcs\n");
598 
599 	hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
600 	if (IS_ERR(hdmi->regmap))
601 		return dev_err_probe(dev, PTR_ERR(hdmi->regmap),
602 				     "failed to get rockchip,grf\n");
603 
604 	hdmi->ref_clk = devm_clk_get_optional_enabled(dev, "ref");
605 	if (!hdmi->ref_clk)
606 		hdmi->ref_clk = devm_clk_get_optional_enabled(dev, "vpll");
607 
608 	if (IS_ERR(hdmi->ref_clk))
609 		return dev_err_probe(dev, PTR_ERR(hdmi->ref_clk),
610 				     "failed to get reference clock\n");
611 
612 	hdmi->grf_clk = devm_clk_get_optional(dev, "grf");
613 	if (IS_ERR(hdmi->grf_clk))
614 		return dev_err_probe(dev, PTR_ERR(hdmi->grf_clk),
615 				     "failed to get grf clock\n");
616 
617 	ret = devm_regulator_get_enable(dev, "avdd-0v9");
618 	if (ret)
619 		return dev_err_probe(dev, ret, "failed to enable avdd-0v9\n");
620 
621 	ret = devm_regulator_get_enable(dev, "avdd-1v8");
622 	if (ret)
623 		return dev_err_probe(dev, ret, "failed to enable avdd-1v8\n");
624 
625 	hdmi->phy = devm_phy_optional_get(dev, "hdmi");
626 	if (IS_ERR(hdmi->phy))
627 		return dev_err_probe(dev, PTR_ERR(hdmi->phy),
628 				     "failed to get phy\n");
629 
630 	index = of_property_match_string(np, "phy-names", "hdmi");
631 	if (index >= 0) {
632 		struct of_phandle_args clkspec;
633 
634 		if (!of_parse_phandle_with_args(np, "phys", "#phy-cells", index,
635 						&clkspec)) {
636 			hdmi->hdmiphy_clk = of_clk_get_from_provider(&clkspec);
637 			of_node_put(clkspec.np);
638 			if (IS_ERR(hdmi->hdmiphy_clk))
639 				hdmi->hdmiphy_clk = NULL;
640 		}
641 	}
642 
643 	if (hdmi->chip_data == &rk3568_chip_data) {
644 		regmap_write(hdmi->regmap, RK3568_GRF_VO_CON1,
645 			     FIELD_PREP_WM16(RK3568_HDMI_SDAIN_MSK, 1) |
646 			     FIELD_PREP_WM16(RK3568_HDMI_SCLIN_MSK, 1));
647 	}
648 
649 	ret = drmm_encoder_init(drm, encoder, NULL, DRM_MODE_ENCODER_TMDS, NULL);
650 	if (ret)
651 		return dev_err_probe(dev, ret, "failed to init encoder\n");
652 
653 	drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
654 
655 	platform_set_drvdata(pdev, hdmi);
656 
657 	hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
658 	if (IS_ERR(hdmi->hdmi))
659 		return dev_err_probe(dev, PTR_ERR(hdmi->hdmi),
660 				     "failed to probe dw-hdmi bridge\n");
661 
662 	hdmi->bridge = of_drm_find_and_get_bridge(np);
663 	if (!hdmi->bridge) {
664 		dw_hdmi_unbind(hdmi->hdmi);
665 		return dev_err_probe(dev, -ENODEV,
666 				     "failed to find dw-hdmi bridge\n");
667 	}
668 
669 	return 0;
670 }
671 
672 static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
673 				    void *data)
674 {
675 	struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
676 
677 	drm_bridge_put(hdmi->bridge);
678 	dw_hdmi_unbind(hdmi->hdmi);
679 }
680 
681 static const struct component_ops dw_hdmi_rockchip_ops = {
682 	.bind	= dw_hdmi_rockchip_bind,
683 	.unbind	= dw_hdmi_rockchip_unbind,
684 };
685 
686 static int dw_hdmi_rockchip_probe(struct platform_device *pdev)
687 {
688 	return component_add(&pdev->dev, &dw_hdmi_rockchip_ops);
689 }
690 
691 static void dw_hdmi_rockchip_remove(struct platform_device *pdev)
692 {
693 	component_del(&pdev->dev, &dw_hdmi_rockchip_ops);
694 }
695 
696 static int __maybe_unused dw_hdmi_rockchip_resume_early(struct device *dev)
697 {
698 	struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
699 
700 	if (hdmi)
701 		dw_hdmi_resume(hdmi->hdmi);
702 
703 	return 0;
704 }
705 
706 static const struct dev_pm_ops dw_hdmi_rockchip_pm = {
707 	SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, dw_hdmi_rockchip_resume_early)
708 };
709 
710 struct platform_driver dw_hdmi_rockchip_pltfm_driver = {
711 	.probe  = dw_hdmi_rockchip_probe,
712 	.remove = dw_hdmi_rockchip_remove,
713 	.driver = {
714 		.name = "dwhdmi-rockchip",
715 		.pm = &dw_hdmi_rockchip_pm,
716 		.of_match_table = dw_hdmi_rockchip_dt_ids,
717 	},
718 };
719