xref: /linux/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c (revision 55a42f78ffd386e01a5404419f8c5ded7db70a21)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd.
4  * Copyright (c) 2024 Collabora Ltd.
5  *
6  * Author: Algea Cao <algea.cao@rock-chips.com>
7  * Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
8  */
9 
10 #include <linux/clk.h>
11 #include <linux/gpio/consumer.h>
12 #include <linux/hw_bitfield.h>
13 #include <linux/mfd/syscon.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/phy/phy.h>
17 #include <linux/regmap.h>
18 #include <linux/workqueue.h>
19 
20 #include <drm/bridge/dw_hdmi_qp.h>
21 #include <drm/display/drm_hdmi_helper.h>
22 #include <drm/drm_bridge_connector.h>
23 #include <drm/drm_of.h>
24 #include <drm/drm_probe_helper.h>
25 #include <drm/drm_simple_kms_helper.h>
26 
27 #include "rockchip_drm_drv.h"
28 
29 #define RK3576_IOC_MISC_CON0		0xa400
30 #define RK3576_HDMI_HPD_INT_MSK		BIT(2)
31 #define RK3576_HDMI_HPD_INT_CLR		BIT(1)
32 
33 #define RK3576_IOC_HDMI_HPD_STATUS	0xa440
34 #define RK3576_HDMI_LEVEL_INT		BIT(3)
35 
36 #define RK3576_VO0_GRF_SOC_CON1		0x0004
37 #define RK3576_HDMI_FRL_MOD		BIT(0)
38 #define RK3576_HDMI_HDCP14_MEM_EN	BIT(15)
39 
40 #define RK3576_VO0_GRF_SOC_CON8		0x0020
41 #define RK3576_COLOR_FORMAT_MASK	(0xf << 4)
42 #define RK3576_COLOR_DEPTH_MASK		(0xf << 8)
43 #define RK3576_RGB			(0 << 4)
44 #define RK3576_YUV422			(0x1 << 4)
45 #define RK3576_YUV444			(0x2 << 4)
46 #define RK3576_YUV420			(0x3 << 4)
47 #define RK3576_8BPC			(0x0 << 8)
48 #define RK3576_10BPC			(0x6 << 8)
49 #define RK3576_CECIN_MASK		BIT(3)
50 
51 #define RK3576_VO0_GRF_SOC_CON12	0x0030
52 #define RK3576_GRF_OSDA_DLYN		(0xf << 12)
53 #define RK3576_GRF_OSDA_DIV		(0x7f << 1)
54 #define RK3576_GRF_OSDA_DLY_EN		BIT(0)
55 
56 #define RK3576_VO0_GRF_SOC_CON14	0x0038
57 #define RK3576_I2S_SEL_MASK		BIT(0)
58 #define RK3576_SPDIF_SEL_MASK		BIT(1)
59 #define HDCP0_P1_GPIO_IN		BIT(2)
60 #define RK3576_SCLIN_MASK		BIT(4)
61 #define RK3576_SDAIN_MASK		BIT(5)
62 #define RK3576_HDMI_GRANT_SEL		BIT(6)
63 
64 #define RK3588_GRF_SOC_CON2		0x0308
65 #define RK3588_HDMI0_HPD_INT_MSK	BIT(13)
66 #define RK3588_HDMI0_HPD_INT_CLR	BIT(12)
67 #define RK3588_HDMI1_HPD_INT_MSK	BIT(15)
68 #define RK3588_HDMI1_HPD_INT_CLR	BIT(14)
69 #define RK3588_GRF_SOC_CON7		0x031c
70 #define RK3588_HPD_HDMI0_IO_EN_MASK	BIT(12)
71 #define RK3588_HPD_HDMI1_IO_EN_MASK	BIT(13)
72 #define RK3588_GRF_SOC_STATUS1		0x0384
73 #define RK3588_HDMI0_LEVEL_INT		BIT(16)
74 #define RK3588_HDMI1_LEVEL_INT		BIT(24)
75 #define RK3588_GRF_VO1_CON3		0x000c
76 #define RK3588_GRF_VO1_CON6		0x0018
77 #define RK3588_SCLIN_MASK		BIT(9)
78 #define RK3588_SDAIN_MASK		BIT(10)
79 #define RK3588_MODE_MASK		BIT(11)
80 #define RK3588_I2S_SEL_MASK		BIT(13)
81 #define RK3588_GRF_VO1_CON9		0x0024
82 #define RK3588_HDMI0_GRANT_SEL		BIT(10)
83 #define RK3588_HDMI1_GRANT_SEL		BIT(12)
84 
85 #define HOTPLUG_DEBOUNCE_MS		150
86 #define MAX_HDMI_PORT_NUM		2
87 
88 struct rockchip_hdmi_qp {
89 	struct device *dev;
90 	struct regmap *regmap;
91 	struct regmap *vo_regmap;
92 	struct rockchip_encoder encoder;
93 	struct dw_hdmi_qp *hdmi;
94 	struct phy *phy;
95 	struct gpio_desc *enable_gpio;
96 	struct delayed_work hpd_work;
97 	int port_id;
98 	const struct rockchip_hdmi_qp_ctrl_ops *ctrl_ops;
99 };
100 
101 struct rockchip_hdmi_qp_ctrl_ops {
102 	void (*io_init)(struct rockchip_hdmi_qp *hdmi);
103 	irqreturn_t (*irq_callback)(int irq, void *dev_id);
104 	irqreturn_t (*hardirq_callback)(int irq, void *dev_id);
105 };
106 
107 static struct rockchip_hdmi_qp *to_rockchip_hdmi_qp(struct drm_encoder *encoder)
108 {
109 	struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
110 
111 	return container_of(rkencoder, struct rockchip_hdmi_qp, encoder);
112 }
113 
114 static void dw_hdmi_qp_rockchip_encoder_enable(struct drm_encoder *encoder)
115 {
116 	struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder);
117 	struct drm_crtc *crtc = encoder->crtc;
118 	unsigned long long rate;
119 
120 	/* Unconditionally switch to TMDS as FRL is not yet supported */
121 	gpiod_set_value(hdmi->enable_gpio, 1);
122 
123 	if (crtc && crtc->state) {
124 		rate = drm_hdmi_compute_mode_clock(&crtc->state->adjusted_mode,
125 						   8, HDMI_COLORSPACE_RGB);
126 		/*
127 		 * FIXME: Temporary workaround to pass pixel clock rate
128 		 * to the PHY driver until phy_configure_opts_hdmi
129 		 * becomes available in the PHY API. See also the related
130 		 * comment in rk_hdptx_phy_power_on() from
131 		 * drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
132 		 */
133 		phy_set_bus_width(hdmi->phy, div_u64(rate, 100));
134 	}
135 }
136 
137 static int
138 dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
139 					 struct drm_crtc_state *crtc_state,
140 					 struct drm_connector_state *conn_state)
141 {
142 	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
143 
144 	s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
145 	s->output_type = DRM_MODE_CONNECTOR_HDMIA;
146 
147 	return 0;
148 }
149 
150 static const struct
151 drm_encoder_helper_funcs dw_hdmi_qp_rockchip_encoder_helper_funcs = {
152 	.enable		= dw_hdmi_qp_rockchip_encoder_enable,
153 	.atomic_check	= dw_hdmi_qp_rockchip_encoder_atomic_check,
154 };
155 
156 static int dw_hdmi_qp_rk3588_phy_init(struct dw_hdmi_qp *dw_hdmi, void *data)
157 {
158 	struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
159 
160 	return phy_power_on(hdmi->phy);
161 }
162 
163 static void dw_hdmi_qp_rk3588_phy_disable(struct dw_hdmi_qp *dw_hdmi,
164 					  void *data)
165 {
166 	struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
167 
168 	phy_power_off(hdmi->phy);
169 }
170 
171 static enum drm_connector_status
172 dw_hdmi_qp_rk3588_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
173 {
174 	struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
175 	u32 val;
176 
177 	regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &val);
178 	val &= hdmi->port_id ? RK3588_HDMI1_LEVEL_INT : RK3588_HDMI0_LEVEL_INT;
179 
180 	return val ? connector_status_connected : connector_status_disconnected;
181 }
182 
183 static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
184 {
185 	struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
186 	u32 val;
187 
188 	if (hdmi->port_id)
189 		val = (FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_CLR, 1) |
190 		       FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 0));
191 	else
192 		val = (FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_CLR, 1) |
193 		       FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 0));
194 
195 	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
196 }
197 
198 static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = {
199 	.init		= dw_hdmi_qp_rk3588_phy_init,
200 	.disable	= dw_hdmi_qp_rk3588_phy_disable,
201 	.read_hpd	= dw_hdmi_qp_rk3588_read_hpd,
202 	.setup_hpd	= dw_hdmi_qp_rk3588_setup_hpd,
203 };
204 
205 static enum drm_connector_status
206 dw_hdmi_qp_rk3576_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
207 {
208 	struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
209 	u32 val;
210 
211 	regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &val);
212 
213 	return val & RK3576_HDMI_LEVEL_INT ?
214 		connector_status_connected : connector_status_disconnected;
215 }
216 
217 static void dw_hdmi_qp_rk3576_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
218 {
219 	struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
220 	u32 val;
221 
222 	val = (FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1) |
223 	       FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0));
224 
225 	regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
226 	regmap_write(hdmi->regmap, 0xa404, 0xffff0102);
227 }
228 
229 static const struct dw_hdmi_qp_phy_ops rk3576_hdmi_phy_ops = {
230 	.init		= dw_hdmi_qp_rk3588_phy_init,
231 	.disable	= dw_hdmi_qp_rk3588_phy_disable,
232 	.read_hpd	= dw_hdmi_qp_rk3576_read_hpd,
233 	.setup_hpd	= dw_hdmi_qp_rk3576_setup_hpd,
234 };
235 
236 static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
237 {
238 	struct rockchip_hdmi_qp *hdmi = container_of(work,
239 						     struct rockchip_hdmi_qp,
240 						     hpd_work.work);
241 	struct drm_device *drm = hdmi->encoder.encoder.dev;
242 	bool changed;
243 
244 	if (drm) {
245 		changed = drm_helper_hpd_irq_event(drm);
246 		if (changed)
247 			dev_dbg(hdmi->dev, "connector status changed\n");
248 	}
249 }
250 
251 static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
252 {
253 	struct rockchip_hdmi_qp *hdmi = dev_id;
254 	u32 intr_stat, val;
255 
256 	regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat);
257 	if (intr_stat) {
258 		val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
259 
260 		regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
261 		return IRQ_WAKE_THREAD;
262 	}
263 
264 	return IRQ_NONE;
265 }
266 
267 static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id)
268 {
269 	struct rockchip_hdmi_qp *hdmi = dev_id;
270 	u32 intr_stat, val;
271 
272 	regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat);
273 
274 	if (!intr_stat)
275 		return IRQ_NONE;
276 
277 	val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1);
278 	regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
279 	mod_delayed_work(system_wq, &hdmi->hpd_work,
280 			 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
281 
282 	val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0);
283 	regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
284 
285 	return IRQ_HANDLED;
286 }
287 
288 static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
289 {
290 	struct rockchip_hdmi_qp *hdmi = dev_id;
291 	u32 intr_stat, val;
292 
293 	regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
294 
295 	if (intr_stat) {
296 		if (hdmi->port_id)
297 			val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
298 		else
299 			val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
300 		regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
301 		return IRQ_WAKE_THREAD;
302 	}
303 
304 	return IRQ_NONE;
305 }
306 
307 static irqreturn_t dw_hdmi_qp_rk3588_irq(int irq, void *dev_id)
308 {
309 	struct rockchip_hdmi_qp *hdmi = dev_id;
310 	u32 intr_stat, val;
311 
312 	regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
313 	if (!intr_stat)
314 		return IRQ_NONE;
315 
316 	if (hdmi->port_id)
317 		val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_CLR, 1);
318 	else
319 		val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_CLR, 1);
320 	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
321 
322 	mod_delayed_work(system_wq, &hdmi->hpd_work,
323 			 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
324 
325 	if (hdmi->port_id)
326 		val |= FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 0);
327 	else
328 		val |= FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 0);
329 	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
330 
331 	return IRQ_HANDLED;
332 }
333 
334 static void dw_hdmi_qp_rk3576_io_init(struct rockchip_hdmi_qp *hdmi)
335 {
336 	u32 val;
337 
338 	val = FIELD_PREP_WM16(RK3576_SCLIN_MASK, 1) |
339 	      FIELD_PREP_WM16(RK3576_SDAIN_MASK, 1) |
340 	      FIELD_PREP_WM16(RK3576_HDMI_GRANT_SEL, 1) |
341 	      FIELD_PREP_WM16(RK3576_I2S_SEL_MASK, 1);
342 
343 	regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON14, val);
344 
345 	val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0);
346 	regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
347 }
348 
349 static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
350 {
351 	u32 val;
352 
353 	val = FIELD_PREP_WM16(RK3588_SCLIN_MASK, 1) |
354 	      FIELD_PREP_WM16(RK3588_SDAIN_MASK, 1) |
355 	      FIELD_PREP_WM16(RK3588_MODE_MASK, 1) |
356 	      FIELD_PREP_WM16(RK3588_I2S_SEL_MASK, 1);
357 	regmap_write(hdmi->vo_regmap,
358 		     hdmi->port_id ? RK3588_GRF_VO1_CON6 : RK3588_GRF_VO1_CON3,
359 		     val);
360 
361 	val = FIELD_PREP_WM16(RK3588_HPD_HDMI0_IO_EN_MASK, 1) |
362 	      FIELD_PREP_WM16(RK3588_HPD_HDMI1_IO_EN_MASK, 1);
363 	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val);
364 
365 	if (hdmi->port_id)
366 		val = FIELD_PREP_WM16(RK3588_HDMI1_GRANT_SEL, 1);
367 	else
368 		val = FIELD_PREP_WM16(RK3588_HDMI0_GRANT_SEL, 1);
369 	regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val);
370 
371 	if (hdmi->port_id)
372 		val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
373 	else
374 		val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
375 	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
376 }
377 
378 static const struct rockchip_hdmi_qp_ctrl_ops rk3576_hdmi_ctrl_ops = {
379 	.io_init		= dw_hdmi_qp_rk3576_io_init,
380 	.irq_callback	        = dw_hdmi_qp_rk3576_irq,
381 	.hardirq_callback	= dw_hdmi_qp_rk3576_hardirq,
382 };
383 
384 static const struct rockchip_hdmi_qp_ctrl_ops rk3588_hdmi_ctrl_ops = {
385 	.io_init		= dw_hdmi_qp_rk3588_io_init,
386 	.irq_callback	        = dw_hdmi_qp_rk3588_irq,
387 	.hardirq_callback	= dw_hdmi_qp_rk3588_hardirq,
388 };
389 
390 struct rockchip_hdmi_qp_cfg {
391 	unsigned int num_ports;
392 	unsigned int port_ids[MAX_HDMI_PORT_NUM];
393 	const struct rockchip_hdmi_qp_ctrl_ops *ctrl_ops;
394 	const struct dw_hdmi_qp_phy_ops *phy_ops;
395 };
396 
397 static const struct rockchip_hdmi_qp_cfg rk3576_hdmi_cfg = {
398 	.num_ports = 1,
399 	.port_ids = {
400 		0x27da0000,
401 	},
402 	.ctrl_ops = &rk3576_hdmi_ctrl_ops,
403 	.phy_ops = &rk3576_hdmi_phy_ops,
404 };
405 
406 static const struct rockchip_hdmi_qp_cfg rk3588_hdmi_cfg = {
407 	.num_ports = 2,
408 	.port_ids = {
409 		0xfde80000,
410 		0xfdea0000,
411 	},
412 	.ctrl_ops = &rk3588_hdmi_ctrl_ops,
413 	.phy_ops = &rk3588_hdmi_phy_ops,
414 };
415 
416 static const struct of_device_id dw_hdmi_qp_rockchip_dt_ids[] = {
417 	{
418 		.compatible = "rockchip,rk3576-dw-hdmi-qp",
419 		.data = &rk3576_hdmi_cfg
420 	}, {
421 		.compatible = "rockchip,rk3588-dw-hdmi-qp",
422 		.data = &rk3588_hdmi_cfg
423 	},
424 	{},
425 };
426 MODULE_DEVICE_TABLE(of, dw_hdmi_qp_rockchip_dt_ids);
427 
428 static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
429 				    void *data)
430 {
431 	struct platform_device *pdev = to_platform_device(dev);
432 	const struct rockchip_hdmi_qp_cfg *cfg;
433 	struct dw_hdmi_qp_plat_data plat_data;
434 	struct drm_device *drm = data;
435 	struct drm_connector *connector;
436 	struct drm_encoder *encoder;
437 	struct rockchip_hdmi_qp *hdmi;
438 	struct resource *res;
439 	struct clk_bulk_data *clks;
440 	int ret, irq, i;
441 
442 	if (!pdev->dev.of_node)
443 		return -ENODEV;
444 
445 	hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
446 	if (!hdmi)
447 		return -ENOMEM;
448 
449 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
450 	if (!res)
451 		return -ENODEV;
452 
453 	cfg = of_device_get_match_data(dev);
454 	if (!cfg)
455 		return -ENODEV;
456 
457 	if (!cfg->ctrl_ops || !cfg->ctrl_ops->io_init ||
458 	    !cfg->ctrl_ops->irq_callback || !cfg->ctrl_ops->hardirq_callback) {
459 		dev_err(dev, "Missing platform ctrl ops\n");
460 		return -ENODEV;
461 	}
462 
463 	hdmi->ctrl_ops = cfg->ctrl_ops;
464 	hdmi->dev = &pdev->dev;
465 	hdmi->port_id = -ENODEV;
466 
467 	/* Identify port ID by matching base IO address */
468 	for (i = 0; i < cfg->num_ports; i++) {
469 		if (res->start == cfg->port_ids[i]) {
470 			hdmi->port_id = i;
471 			break;
472 		}
473 	}
474 	if (hdmi->port_id < 0) {
475 		dev_err(hdmi->dev, "Failed to match HDMI port ID\n");
476 		return hdmi->port_id;
477 	}
478 
479 	plat_data.phy_ops = cfg->phy_ops;
480 	plat_data.phy_data = hdmi;
481 
482 	encoder = &hdmi->encoder.encoder;
483 	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
484 
485 	rockchip_drm_encoder_set_crtc_endpoint_id(&hdmi->encoder,
486 						  dev->of_node, 0, 0);
487 	/*
488 	 * If we failed to find the CRTC(s) which this encoder is
489 	 * supposed to be connected to, it's because the CRTC has
490 	 * not been registered yet.  Defer probing, and hope that
491 	 * the required CRTC is added later.
492 	 */
493 	if (encoder->possible_crtcs == 0)
494 		return -EPROBE_DEFER;
495 
496 	hdmi->regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
497 						       "rockchip,grf");
498 	if (IS_ERR(hdmi->regmap)) {
499 		dev_err(hdmi->dev, "Unable to get rockchip,grf\n");
500 		return PTR_ERR(hdmi->regmap);
501 	}
502 
503 	hdmi->vo_regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
504 							  "rockchip,vo-grf");
505 	if (IS_ERR(hdmi->vo_regmap)) {
506 		dev_err(hdmi->dev, "Unable to get rockchip,vo-grf\n");
507 		return PTR_ERR(hdmi->vo_regmap);
508 	}
509 
510 	ret = devm_clk_bulk_get_all_enabled(hdmi->dev, &clks);
511 	if (ret < 0) {
512 		dev_err(hdmi->dev, "Failed to get clocks: %d\n", ret);
513 		return ret;
514 	}
515 
516 	hdmi->enable_gpio = devm_gpiod_get_optional(hdmi->dev, "enable",
517 						    GPIOD_OUT_HIGH);
518 	if (IS_ERR(hdmi->enable_gpio)) {
519 		ret = PTR_ERR(hdmi->enable_gpio);
520 		dev_err(hdmi->dev, "Failed to request enable GPIO: %d\n", ret);
521 		return ret;
522 	}
523 
524 	hdmi->phy = devm_of_phy_get_by_index(dev, dev->of_node, 0);
525 	if (IS_ERR(hdmi->phy)) {
526 		ret = PTR_ERR(hdmi->phy);
527 		if (ret != -EPROBE_DEFER)
528 			dev_err(hdmi->dev, "failed to get phy: %d\n", ret);
529 		return ret;
530 	}
531 
532 	cfg->ctrl_ops->io_init(hdmi);
533 
534 	INIT_DELAYED_WORK(&hdmi->hpd_work, dw_hdmi_qp_rk3588_hpd_work);
535 
536 	plat_data.main_irq = platform_get_irq_byname(pdev, "main");
537 	if (plat_data.main_irq < 0)
538 		return plat_data.main_irq;
539 
540 	irq = platform_get_irq_byname(pdev, "hpd");
541 	if (irq < 0)
542 		return irq;
543 
544 	ret = devm_request_threaded_irq(hdmi->dev, irq,
545 					cfg->ctrl_ops->hardirq_callback,
546 					cfg->ctrl_ops->irq_callback,
547 					IRQF_SHARED, "dw-hdmi-qp-hpd",
548 					hdmi);
549 	if (ret)
550 		return ret;
551 
552 	drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs);
553 	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
554 
555 	platform_set_drvdata(pdev, hdmi);
556 
557 	hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data);
558 	if (IS_ERR(hdmi->hdmi)) {
559 		ret = PTR_ERR(hdmi->hdmi);
560 		drm_encoder_cleanup(encoder);
561 		return ret;
562 	}
563 
564 	connector = drm_bridge_connector_init(drm, encoder);
565 	if (IS_ERR(connector)) {
566 		ret = PTR_ERR(connector);
567 		dev_err(hdmi->dev, "failed to init bridge connector: %d\n", ret);
568 		return ret;
569 	}
570 
571 	return drm_connector_attach_encoder(connector, encoder);
572 }
573 
574 static void dw_hdmi_qp_rockchip_unbind(struct device *dev,
575 				       struct device *master,
576 				       void *data)
577 {
578 	struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
579 
580 	cancel_delayed_work_sync(&hdmi->hpd_work);
581 
582 	drm_encoder_cleanup(&hdmi->encoder.encoder);
583 }
584 
585 static const struct component_ops dw_hdmi_qp_rockchip_ops = {
586 	.bind	= dw_hdmi_qp_rockchip_bind,
587 	.unbind	= dw_hdmi_qp_rockchip_unbind,
588 };
589 
590 static int dw_hdmi_qp_rockchip_probe(struct platform_device *pdev)
591 {
592 	return component_add(&pdev->dev, &dw_hdmi_qp_rockchip_ops);
593 }
594 
595 static void dw_hdmi_qp_rockchip_remove(struct platform_device *pdev)
596 {
597 	component_del(&pdev->dev, &dw_hdmi_qp_rockchip_ops);
598 }
599 
600 static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev)
601 {
602 	struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
603 
604 	hdmi->ctrl_ops->io_init(hdmi);
605 
606 	dw_hdmi_qp_resume(dev, hdmi->hdmi);
607 
608 	if (hdmi->encoder.encoder.dev)
609 		drm_helper_hpd_irq_event(hdmi->encoder.encoder.dev);
610 
611 	return 0;
612 }
613 
614 static const struct dev_pm_ops dw_hdmi_qp_rockchip_pm = {
615 	SET_SYSTEM_SLEEP_PM_OPS(NULL, dw_hdmi_qp_rockchip_resume)
616 };
617 
618 struct platform_driver dw_hdmi_qp_rockchip_pltfm_driver = {
619 	.probe = dw_hdmi_qp_rockchip_probe,
620 	.remove = dw_hdmi_qp_rockchip_remove,
621 	.driver = {
622 		.name = "dwhdmiqp-rockchip",
623 		.pm = &dw_hdmi_qp_rockchip_pm,
624 		.of_match_table = dw_hdmi_qp_rockchip_dt_ids,
625 	},
626 };
627