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