File Index
Files and directories
Sign in
FILE

dw_hdmi-rockchip.c

File preview with syntax highlighting.

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