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