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